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/package.h
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#ifdef PACKAGE_NAME
|
|
2
|
+
#undef PACKAGE_NAME
|
|
3
|
+
#endif
|
|
4
|
+
|
|
5
|
+
#ifdef PACKAGE_TARNAME
|
|
6
|
+
#undef PACKAGE_TARNAME
|
|
7
|
+
#endif
|
|
8
|
+
|
|
9
|
+
#ifdef PACKAGE_VERSION
|
|
10
|
+
#undef PACKAGE_VERSION
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
#ifdef PACKAGE_STRING
|
|
14
|
+
#undef PACKAGE_STRING
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
#ifdef PACKAGE_BUGREPORT
|
|
18
|
+
#undef PACKAGE_BUGREPORT
|
|
19
|
+
#endif
|
|
20
|
+
|
data/src/plpl.c
ADDED
|
@@ -0,0 +1,1708 @@
|
|
|
1
|
+
#include "plruby.h"
|
|
2
|
+
|
|
3
|
+
static VALUE pl_ePLruby, pl_mPLtemp;
|
|
4
|
+
static VALUE pl_mPL, pl_cPLPlan, pl_eCatch;
|
|
5
|
+
|
|
6
|
+
static ID id_thr;
|
|
7
|
+
|
|
8
|
+
static VALUE pl_SPI_exec _((int, VALUE *, VALUE));
|
|
9
|
+
|
|
10
|
+
#ifndef HAVE_RB_HASH_DELETE
|
|
11
|
+
static ID id_delete;
|
|
12
|
+
|
|
13
|
+
#define rb_hash_delete(a, b) rb_funcall((a), id_delete, 1, (b))
|
|
14
|
+
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
static char *names =
|
|
18
|
+
"SELECT a.attname FROM pg_class c, pg_attribute a, pg_namespace n"
|
|
19
|
+
" WHERE c.relname = '%s' AND a.attnum > 0 AND NOT a.attisdropped AND a.attrelid = c.oid"
|
|
20
|
+
" AND c.relnamespace = n.oid AND n.nspname = '%s'"
|
|
21
|
+
" ORDER BY a.attnum";
|
|
22
|
+
|
|
23
|
+
static VALUE
|
|
24
|
+
pl_column_name(VALUE obj, VALUE table)
|
|
25
|
+
{
|
|
26
|
+
VALUE *query, res;
|
|
27
|
+
char *tmp;
|
|
28
|
+
char *nsp, *tbl, *c;
|
|
29
|
+
|
|
30
|
+
if (TYPE(table) != T_STRING || !RSTRING_PTR(table)) {
|
|
31
|
+
rb_raise(pl_ePLruby, "expected a String");
|
|
32
|
+
}
|
|
33
|
+
tmp = ALLOCA_N(char, strlen(names) + RSTRING_LEN(table) + 1);
|
|
34
|
+
nsp = ALLOCA_N(char, RSTRING_LEN(table) + 1);
|
|
35
|
+
tbl = ALLOCA_N(char, RSTRING_LEN(table) + 1);
|
|
36
|
+
strcpy(nsp, RSTRING_PTR(table));
|
|
37
|
+
if ((c = strchr(nsp, '.')) != NULL) {
|
|
38
|
+
*c = 0;
|
|
39
|
+
strcpy(tbl, c + 1);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
strcpy(tbl, nsp);
|
|
43
|
+
strcpy(nsp, "public");
|
|
44
|
+
}
|
|
45
|
+
sprintf(tmp, names, tbl, nsp);
|
|
46
|
+
query = ALLOCA_N(VALUE, 3);
|
|
47
|
+
MEMZERO(query, VALUE, 3);
|
|
48
|
+
query[0] = rb_str_new2(tmp);
|
|
49
|
+
query[1] = Qnil;
|
|
50
|
+
query[2] = rb_str_new2("value");
|
|
51
|
+
res = pl_SPI_exec(3, query, pl_mPL);
|
|
52
|
+
rb_funcall2(res, rb_intern("flatten!"), 0, 0);
|
|
53
|
+
return res;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static char *types =
|
|
57
|
+
"SELECT t.typname FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n"
|
|
58
|
+
" WHERE c.relname = '%s' and a.attnum > 0 AND NOT a.attisdropped"
|
|
59
|
+
" AND a.attrelid = c.oid and a.atttypid = t.oid"
|
|
60
|
+
" AND c.relnamespace = n.oid AND n.nspname = '%s'"
|
|
61
|
+
" ORDER BY a.attnum";
|
|
62
|
+
|
|
63
|
+
static VALUE
|
|
64
|
+
pl_column_type(VALUE obj, VALUE table)
|
|
65
|
+
{
|
|
66
|
+
VALUE *query, res;
|
|
67
|
+
char *tmp;
|
|
68
|
+
char *nsp, *tbl, *c;
|
|
69
|
+
|
|
70
|
+
if (TYPE(table) != T_STRING || !RSTRING_PTR(table)) {
|
|
71
|
+
rb_raise(pl_ePLruby, "expected a String");
|
|
72
|
+
}
|
|
73
|
+
tmp = ALLOCA_N(char, strlen(types) + RSTRING_LEN(table) + 1);
|
|
74
|
+
nsp = ALLOCA_N(char, RSTRING_LEN(table) + 1);
|
|
75
|
+
tbl = ALLOCA_N(char, RSTRING_LEN(table) + 1);
|
|
76
|
+
strcpy(nsp, RSTRING_PTR(table));
|
|
77
|
+
if ((c = strchr(nsp, '.')) != NULL) {
|
|
78
|
+
*c = 0;
|
|
79
|
+
strcpy(tbl, c + 1);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
strcpy(tbl, nsp);
|
|
83
|
+
strcpy(nsp, "public");
|
|
84
|
+
}
|
|
85
|
+
sprintf(tmp, types, tbl, nsp);
|
|
86
|
+
query = ALLOCA_N(VALUE, 3);
|
|
87
|
+
MEMZERO(query, VALUE, 3);
|
|
88
|
+
query[0] = rb_str_new2(tmp);
|
|
89
|
+
query[1] = Qnil;
|
|
90
|
+
query[2] = rb_str_new2("value");
|
|
91
|
+
res = pl_SPI_exec(3, query, pl_mPL);
|
|
92
|
+
rb_funcall2(res, rb_intern("flatten!"), 0, 0);
|
|
93
|
+
return res;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
struct pl_tuple {
|
|
97
|
+
MemoryContext cxt;
|
|
98
|
+
AttInMetadata *att;
|
|
99
|
+
pl_proc_desc *pro;
|
|
100
|
+
TupleDesc dsc;
|
|
101
|
+
Tuplestorestate *out;
|
|
102
|
+
PG_FUNCTION_ARGS;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
#if PG_PL_VERSION >= 75
|
|
106
|
+
#define SortMem work_mem
|
|
107
|
+
#endif
|
|
108
|
+
|
|
109
|
+
extern int SortMem;
|
|
110
|
+
|
|
111
|
+
static void pl_thr_mark(struct pl_tuple *tpl) {}
|
|
112
|
+
|
|
113
|
+
#define GetTuple(tmp_, tpl_) do { \
|
|
114
|
+
if (TYPE(tmp_) != T_DATA || \
|
|
115
|
+
RDATA(tmp_)->dmark != (RUBY_DATA_FUNC)pl_thr_mark) { \
|
|
116
|
+
rb_raise(pl_ePLruby, "invalid thread local variable"); \
|
|
117
|
+
} \
|
|
118
|
+
Data_Get_Struct(tmp_, struct pl_tuple, tpl_); \
|
|
119
|
+
} while(0)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
static VALUE
|
|
123
|
+
pl_query_name(VALUE obj)
|
|
124
|
+
{
|
|
125
|
+
VALUE res, tmp;
|
|
126
|
+
struct pl_tuple *tpl;
|
|
127
|
+
char * attname;
|
|
128
|
+
int i;
|
|
129
|
+
|
|
130
|
+
tmp = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
131
|
+
if (NIL_P(tmp)) {
|
|
132
|
+
return Qnil;
|
|
133
|
+
}
|
|
134
|
+
GetTuple(tmp, tpl);
|
|
135
|
+
if (!tpl->dsc) {
|
|
136
|
+
return Qnil;
|
|
137
|
+
}
|
|
138
|
+
res = rb_ary_new2(tpl->dsc->natts);
|
|
139
|
+
for (i = 0; i < tpl->dsc->natts; i++) {
|
|
140
|
+
if (tpl->dsc->attrs[i]->attisdropped) {
|
|
141
|
+
attname = "";
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
attname = NameStr(tpl->dsc->attrs[i]->attname);
|
|
145
|
+
}
|
|
146
|
+
rb_ary_push(res, rb_tainted_str_new2(attname));
|
|
147
|
+
}
|
|
148
|
+
return res;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static VALUE
|
|
152
|
+
pl_query_type(VALUE obj)
|
|
153
|
+
{
|
|
154
|
+
struct pl_tuple *tpl;
|
|
155
|
+
VALUE res, tmp;
|
|
156
|
+
char * attname;
|
|
157
|
+
HeapTuple typeTup;
|
|
158
|
+
Form_pg_type fpgt;
|
|
159
|
+
int i;
|
|
160
|
+
|
|
161
|
+
tmp = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
162
|
+
if (NIL_P(tmp)) {
|
|
163
|
+
return Qnil;
|
|
164
|
+
}
|
|
165
|
+
GetTuple(tmp, tpl);
|
|
166
|
+
if (!tpl->dsc) {
|
|
167
|
+
PLRUBY_BEGIN(1);
|
|
168
|
+
typeTup = SearchSysCache(TYPEOID, OidGD(tpl->pro->result_oid),0,0,0);
|
|
169
|
+
PLRUBY_END;
|
|
170
|
+
if (!HeapTupleIsValid(typeTup)) {
|
|
171
|
+
rb_raise(pl_ePLruby, "Cache lookup for result type %ld failed",
|
|
172
|
+
tpl->pro->result_oid);
|
|
173
|
+
}
|
|
174
|
+
fpgt = (Form_pg_type) GETSTRUCT(typeTup);
|
|
175
|
+
res = rb_tainted_str_new2(NameStr(fpgt->typname));
|
|
176
|
+
ReleaseSysCache(typeTup);
|
|
177
|
+
return res;
|
|
178
|
+
}
|
|
179
|
+
res = rb_ary_new2(tpl->dsc->natts);
|
|
180
|
+
for (i = 0; i < tpl->dsc->natts; i++) {
|
|
181
|
+
if (tpl->dsc->attrs[i]->attisdropped)
|
|
182
|
+
continue;
|
|
183
|
+
PLRUBY_BEGIN(1);
|
|
184
|
+
attname = NameStr(tpl->dsc->attrs[i]->attname);
|
|
185
|
+
typeTup = SearchSysCache(TYPEOID, OidGD(tpl->dsc->attrs[i]->atttypid),
|
|
186
|
+
0, 0, 0);
|
|
187
|
+
PLRUBY_END;
|
|
188
|
+
if (!HeapTupleIsValid(typeTup)) {
|
|
189
|
+
rb_raise(pl_ePLruby, "Cache lookup for attribute '%s' type %ld failed",
|
|
190
|
+
attname, OidGD(tpl->dsc->attrs[i]->atttypid));
|
|
191
|
+
}
|
|
192
|
+
fpgt = (Form_pg_type) GETSTRUCT(typeTup);
|
|
193
|
+
rb_ary_push(res, rb_tainted_str_new2(NameStr(fpgt->typname)));
|
|
194
|
+
ReleaseSysCache(typeTup);
|
|
195
|
+
}
|
|
196
|
+
return res;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static VALUE
|
|
200
|
+
pl_query_description(VALUE obj)
|
|
201
|
+
{
|
|
202
|
+
VALUE name, types, res;
|
|
203
|
+
VALUE tt_virg, tt_blc;
|
|
204
|
+
int i;
|
|
205
|
+
|
|
206
|
+
tt_virg = rb_str_new2(", ");
|
|
207
|
+
tt_blc = rb_str_new2(" ");
|
|
208
|
+
name = pl_query_name(obj);
|
|
209
|
+
if (NIL_P(name)) {
|
|
210
|
+
return Qnil;
|
|
211
|
+
}
|
|
212
|
+
types = pl_query_type(obj);
|
|
213
|
+
if (TYPE(name) != T_ARRAY || TYPE(types) != T_ARRAY ||
|
|
214
|
+
RARRAY_LEN(name) != RARRAY_LEN(types)) {
|
|
215
|
+
rb_raise(pl_ePLruby, "unknown error");
|
|
216
|
+
}
|
|
217
|
+
res = rb_tainted_str_new2("");
|
|
218
|
+
for (i = 0; i < RARRAY_LEN(name); ++i) {
|
|
219
|
+
rb_str_concat(res, RARRAY_PTR(name)[i]);
|
|
220
|
+
rb_str_concat(res, tt_blc);
|
|
221
|
+
rb_str_concat(res, RARRAY_PTR(types)[i]);
|
|
222
|
+
if (i != (RARRAY_LEN(name) - 1)) {
|
|
223
|
+
rb_str_concat(res, tt_virg);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return res;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
static VALUE
|
|
230
|
+
pl_query_lgth(VALUE obj)
|
|
231
|
+
{
|
|
232
|
+
VALUE tmp;
|
|
233
|
+
struct pl_tuple *tpl;
|
|
234
|
+
|
|
235
|
+
tmp = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
236
|
+
if (NIL_P(tmp)) {
|
|
237
|
+
return Qnil;
|
|
238
|
+
}
|
|
239
|
+
GetTuple(tmp, tpl);
|
|
240
|
+
if (!tpl->dsc) {
|
|
241
|
+
return Qnil;
|
|
242
|
+
}
|
|
243
|
+
return INT2NUM(tpl->dsc->natts);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static VALUE
|
|
247
|
+
pl_args_type(VALUE obj)
|
|
248
|
+
{
|
|
249
|
+
struct pl_tuple *tpl;
|
|
250
|
+
VALUE res, tmp;
|
|
251
|
+
HeapTuple typeTup;
|
|
252
|
+
Form_pg_type fpgt;
|
|
253
|
+
int i;
|
|
254
|
+
|
|
255
|
+
tmp = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
256
|
+
if (NIL_P(tmp)) {
|
|
257
|
+
return Qnil;
|
|
258
|
+
}
|
|
259
|
+
GetTuple(tmp, tpl);
|
|
260
|
+
res = rb_ary_new2(tpl->pro->nargs);
|
|
261
|
+
for (i = 0; i < tpl->pro->nargs; i++) {
|
|
262
|
+
PLRUBY_BEGIN(1);
|
|
263
|
+
typeTup = SearchSysCache(TYPEOID, OidGD(tpl->pro->arg_type[i]),0,0,0);
|
|
264
|
+
PLRUBY_END;
|
|
265
|
+
if (!HeapTupleIsValid(typeTup)) {
|
|
266
|
+
rb_raise(pl_ePLruby, "Cache lookup for type %ld failed",
|
|
267
|
+
OidGD(tpl->pro->arg_type[i]));
|
|
268
|
+
}
|
|
269
|
+
fpgt = (Form_pg_type) GETSTRUCT(typeTup);
|
|
270
|
+
rb_ary_push(res, rb_tainted_str_new2(NameStr(fpgt->typname)));
|
|
271
|
+
ReleaseSysCache(typeTup);
|
|
272
|
+
}
|
|
273
|
+
return res;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
static VALUE PLcontext;
|
|
277
|
+
|
|
278
|
+
struct PL_node
|
|
279
|
+
{
|
|
280
|
+
NodeTag type;
|
|
281
|
+
VALUE value;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
static VALUE
|
|
285
|
+
pl_context_get(VALUE obj)
|
|
286
|
+
{
|
|
287
|
+
struct pl_tuple *tpl;
|
|
288
|
+
VALUE tmp;
|
|
289
|
+
|
|
290
|
+
tmp = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
291
|
+
if (NIL_P(tmp)) {
|
|
292
|
+
return Qnil;
|
|
293
|
+
}
|
|
294
|
+
GetTuple(tmp, tpl);
|
|
295
|
+
if (!tpl->fcinfo || !tpl->fcinfo->context ||
|
|
296
|
+
!IsA(tpl->fcinfo->context, Invalid)) {
|
|
297
|
+
return Qnil;
|
|
298
|
+
}
|
|
299
|
+
return ((struct PL_node *)tpl->fcinfo->context)->value;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
static VALUE
|
|
303
|
+
pl_context_set(VALUE obj, VALUE a)
|
|
304
|
+
{
|
|
305
|
+
struct pl_tuple *tpl;
|
|
306
|
+
VALUE tmp;
|
|
307
|
+
|
|
308
|
+
tmp = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
309
|
+
GetTuple(tmp, tpl);
|
|
310
|
+
if (tpl->fcinfo && tpl->fcinfo->context) {
|
|
311
|
+
if (!IsA(tpl->fcinfo->context, Invalid)) {
|
|
312
|
+
rb_raise(pl_ePLruby, "trying to change a valid context");
|
|
313
|
+
}
|
|
314
|
+
rb_hash_delete(PLcontext, ((struct PL_node *)tpl->fcinfo->context)->value);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
if (!tpl->fcinfo) {
|
|
318
|
+
rb_raise(pl_ePLruby, "no function info");
|
|
319
|
+
}
|
|
320
|
+
tpl->fcinfo->context = newNode(sizeof(struct PL_node), T_Invalid);
|
|
321
|
+
}
|
|
322
|
+
((struct PL_node *)tpl->fcinfo->context)->value = a;
|
|
323
|
+
rb_hash_aset(PLcontext, a, Qnil);
|
|
324
|
+
return a;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
static void
|
|
328
|
+
pl_context_remove()
|
|
329
|
+
{
|
|
330
|
+
struct pl_tuple *tpl;
|
|
331
|
+
VALUE tmp;
|
|
332
|
+
|
|
333
|
+
tmp = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
334
|
+
GetTuple(tmp, tpl);
|
|
335
|
+
if (tpl->fcinfo && tpl->fcinfo->context) {
|
|
336
|
+
rb_hash_delete(PLcontext, ((struct PL_node *)tpl->fcinfo->context)->value);
|
|
337
|
+
pfree(tpl->fcinfo->context);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
static VALUE
|
|
342
|
+
pl_tuple_s_new(PG_FUNCTION_ARGS, pl_proc_desc *prodesc)
|
|
343
|
+
{
|
|
344
|
+
VALUE res;
|
|
345
|
+
ReturnSetInfo *rsi;
|
|
346
|
+
struct pl_tuple *tpl;
|
|
347
|
+
|
|
348
|
+
if (!fcinfo || !fcinfo->resultinfo) {
|
|
349
|
+
rb_raise(pl_ePLruby, "no description given");
|
|
350
|
+
}
|
|
351
|
+
rsi = (ReturnSetInfo *)fcinfo->resultinfo;
|
|
352
|
+
if ((rsi->allowedModes & SFRM_Materialize) == 0 || !rsi->expectedDesc) {
|
|
353
|
+
rb_raise(pl_ePLruby, "context don't accept set");
|
|
354
|
+
}
|
|
355
|
+
res = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
356
|
+
if (NIL_P(res)) {
|
|
357
|
+
res = Data_Make_Struct(rb_cData, struct pl_tuple, pl_thr_mark, free, tpl);
|
|
358
|
+
}
|
|
359
|
+
GetTuple(res, tpl);
|
|
360
|
+
tpl->cxt = rsi->econtext->ecxt_per_query_memory;
|
|
361
|
+
tpl->dsc = rsi->expectedDesc;
|
|
362
|
+
tpl->att = TupleDescGetAttInMetadata(tpl->dsc);
|
|
363
|
+
tpl->pro = prodesc;
|
|
364
|
+
rb_thread_local_aset(rb_thread_current(), id_thr, res);
|
|
365
|
+
return res;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
#ifdef PLRUBY_ENABLE_CONVERSION
|
|
369
|
+
|
|
370
|
+
static ID id_from_datum;
|
|
371
|
+
static ID id_to_datum;
|
|
372
|
+
|
|
373
|
+
struct datum_value {
|
|
374
|
+
Datum d;
|
|
375
|
+
Oid typoid;
|
|
376
|
+
int typlen;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
static void pl_conv_mark() {}
|
|
380
|
+
|
|
381
|
+
Oid plruby_datum_oid(VALUE obj, int *typlen)
|
|
382
|
+
{
|
|
383
|
+
struct datum_value *dv;
|
|
384
|
+
|
|
385
|
+
if (TYPE(obj) != T_DATA ||
|
|
386
|
+
RDATA(obj)->dmark != (RUBY_DATA_FUNC)pl_conv_mark) {
|
|
387
|
+
rb_raise(pl_ePLruby, "invalid Datum value");
|
|
388
|
+
}
|
|
389
|
+
Data_Get_Struct(obj, struct datum_value, dv);
|
|
390
|
+
if (typlen) *typlen = dv->typlen;
|
|
391
|
+
return dv->typoid;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
VALUE plruby_datum_set(VALUE obj, Datum d)
|
|
395
|
+
{
|
|
396
|
+
struct datum_value *dv;
|
|
397
|
+
|
|
398
|
+
if (TYPE(obj) != T_DATA ||
|
|
399
|
+
RDATA(obj)->dmark != (RUBY_DATA_FUNC)pl_conv_mark) {
|
|
400
|
+
rb_raise(pl_ePLruby, "invalid Datum value");
|
|
401
|
+
}
|
|
402
|
+
Data_Get_Struct(obj, struct datum_value, dv);
|
|
403
|
+
dv->d = d;
|
|
404
|
+
return obj;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
Datum plruby_datum_get(VALUE obj, Oid *typoid)
|
|
408
|
+
{
|
|
409
|
+
struct datum_value *dv;
|
|
410
|
+
|
|
411
|
+
if (TYPE(obj) != T_DATA ||
|
|
412
|
+
RDATA(obj)->dmark != (RUBY_DATA_FUNC)pl_conv_mark) {
|
|
413
|
+
rb_raise(pl_ePLruby, "invalid Datum value");
|
|
414
|
+
}
|
|
415
|
+
Data_Get_Struct(obj, struct datum_value, dv);
|
|
416
|
+
if (typoid) *typoid = dv->typoid;
|
|
417
|
+
return dv->d;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
#endif
|
|
421
|
+
|
|
422
|
+
Datum
|
|
423
|
+
plruby_to_datum(VALUE obj, FmgrInfo *finfo, Oid typoid,
|
|
424
|
+
Oid typelem, int typlen)
|
|
425
|
+
{
|
|
426
|
+
Datum d;
|
|
427
|
+
VALUE tmp;
|
|
428
|
+
|
|
429
|
+
tmp = rb_attr_get(obj, rb_intern("plruby_tuple"));
|
|
430
|
+
if (TYPE(tmp) == T_DATA) {
|
|
431
|
+
return (Datum)DATA_PTR(tmp);
|
|
432
|
+
}
|
|
433
|
+
if (typoid == BOOLOID) {
|
|
434
|
+
return BoolGD(RTEST(obj));
|
|
435
|
+
}
|
|
436
|
+
#ifdef PLRUBY_ENABLE_CONVERSION
|
|
437
|
+
if (rb_respond_to(obj, id_to_datum)) {
|
|
438
|
+
struct datum_value *dv;
|
|
439
|
+
VALUE res;
|
|
440
|
+
|
|
441
|
+
res = Data_Make_Struct(rb_cData, struct datum_value, pl_conv_mark, free, dv);
|
|
442
|
+
dv->typoid = typoid;
|
|
443
|
+
dv->typlen = typlen;
|
|
444
|
+
res = rb_funcall(obj, id_to_datum, 1, res);
|
|
445
|
+
if (TYPE(res) == T_DATA &&
|
|
446
|
+
RDATA(res)->dmark == (RUBY_DATA_FUNC)pl_conv_mark) {
|
|
447
|
+
Data_Get_Struct(res, struct datum_value, dv);
|
|
448
|
+
if (dv->typoid == typoid && dv->typlen == typlen && dv->d) {
|
|
449
|
+
return dv->d;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
#endif
|
|
454
|
+
obj = plruby_to_s(obj);
|
|
455
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
456
|
+
d = FunctionCall3(finfo, PointerGD(RSTRING_PTR(obj)),
|
|
457
|
+
OidGD(typelem), IntGD(typlen));
|
|
458
|
+
PLRUBY_END_PROTECT;
|
|
459
|
+
return d;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
Datum
|
|
463
|
+
plruby_return_array(VALUE ary, pl_proc_desc *p)
|
|
464
|
+
{
|
|
465
|
+
VALUE tmp;
|
|
466
|
+
int i, total, ndim, *dim, *lbs;
|
|
467
|
+
Datum *values;
|
|
468
|
+
ArrayType *array;
|
|
469
|
+
|
|
470
|
+
tmp = rb_Array(ary);
|
|
471
|
+
total = 1;
|
|
472
|
+
dim = ALLOCA_N(int, MAXDIM);
|
|
473
|
+
MEMZERO(dim, int, MAXDIM);
|
|
474
|
+
lbs = ALLOCA_N(int, MAXDIM);
|
|
475
|
+
MEMZERO(lbs, int, MAXDIM);
|
|
476
|
+
i = 0;
|
|
477
|
+
while (TYPE(tmp) == T_ARRAY) {
|
|
478
|
+
lbs[i] = 1;
|
|
479
|
+
dim[i++] = RARRAY_LEN(tmp);
|
|
480
|
+
if (i == MAXDIM) {
|
|
481
|
+
rb_raise(pl_ePLruby, "too many dimensions -- max %d", MAXDIM);
|
|
482
|
+
}
|
|
483
|
+
if (RARRAY_LEN(tmp)) {
|
|
484
|
+
total *= RARRAY_LEN(tmp);
|
|
485
|
+
}
|
|
486
|
+
tmp = RARRAY_PTR(tmp)[0];
|
|
487
|
+
}
|
|
488
|
+
ndim = i;
|
|
489
|
+
#if PG_PL_VERSION < 74
|
|
490
|
+
if (ndim != 1) {
|
|
491
|
+
rb_raise(rb_eNotImpError, "multi-dimensional array only for >= 7.4");
|
|
492
|
+
}
|
|
493
|
+
#endif
|
|
494
|
+
ary = rb_funcall2(ary, rb_intern("flatten"), 0, 0);
|
|
495
|
+
if (RARRAY_LEN(ary) != total) {
|
|
496
|
+
#ifdef WARNING
|
|
497
|
+
elog(WARNING, "not a regular array");
|
|
498
|
+
#else
|
|
499
|
+
elog(NOTICE, "not a regular array");
|
|
500
|
+
#endif
|
|
501
|
+
}
|
|
502
|
+
values = (Datum *)palloc(RARRAY_LEN(ary) * sizeof(Datum));
|
|
503
|
+
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
504
|
+
values[i] = plruby_to_datum(RARRAY_PTR(ary)[i],
|
|
505
|
+
&p->result_func,
|
|
506
|
+
p->result_oid, p->result_elem,
|
|
507
|
+
-1);
|
|
508
|
+
}
|
|
509
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
510
|
+
#if PG_PL_VERSION >= 74
|
|
511
|
+
#if PG_PL_VERSION >= 82
|
|
512
|
+
array = construct_md_array(values, NULL, ndim, dim, lbs,
|
|
513
|
+
p->result_elem, p->result_len,
|
|
514
|
+
p->result_val, p->result_align);
|
|
515
|
+
#else
|
|
516
|
+
array = construct_md_array(values, ndim, dim, lbs,
|
|
517
|
+
p->result_elem, p->result_len,
|
|
518
|
+
p->result_val, p->result_align);
|
|
519
|
+
#endif
|
|
520
|
+
#else
|
|
521
|
+
array = construct_array(values, dim[0], p->result_elem, p->result_len,
|
|
522
|
+
p->result_val, p->result_align);
|
|
523
|
+
#endif
|
|
524
|
+
PLRUBY_END_PROTECT;
|
|
525
|
+
return PointerGD(array);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
static Datum
|
|
529
|
+
return_base_type(VALUE c, pl_proc_desc *prodesc)
|
|
530
|
+
{
|
|
531
|
+
Datum retval;
|
|
532
|
+
|
|
533
|
+
if (prodesc->result_is_array) {
|
|
534
|
+
retval = plruby_return_array(c, prodesc);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
retval = plruby_to_datum(c, &prodesc->result_func,
|
|
538
|
+
prodesc->result_oid,
|
|
539
|
+
prodesc->result_elem,
|
|
540
|
+
-1);
|
|
541
|
+
}
|
|
542
|
+
return retval;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
struct each_st {
|
|
546
|
+
VALUE res;
|
|
547
|
+
TupleDesc tup;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
static HeapTuple
|
|
551
|
+
pl_tuple_heap(VALUE c, VALUE tuple)
|
|
552
|
+
{
|
|
553
|
+
HeapTuple retval;
|
|
554
|
+
struct pl_tuple *tpl;
|
|
555
|
+
TupleDesc tupdesc = 0;
|
|
556
|
+
Datum *dvalues;
|
|
557
|
+
Oid typid;
|
|
558
|
+
char *nulls;
|
|
559
|
+
int i;
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
GetTuple(tuple, tpl);
|
|
563
|
+
if (tpl->att) {
|
|
564
|
+
tupdesc = tpl->att->tupdesc;
|
|
565
|
+
}
|
|
566
|
+
if (!tupdesc) {
|
|
567
|
+
rb_raise(pl_ePLruby, "Invalid descriptor");
|
|
568
|
+
}
|
|
569
|
+
if (TYPE(c) != T_ARRAY) {
|
|
570
|
+
if (NIL_P(c) || (TYPE(c) == T_STRING && !RSTRING_LEN(c))) {
|
|
571
|
+
c = rb_ary_new2(1);
|
|
572
|
+
rb_ary_push(c, rb_str_new2(""));
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
c = rb_Array(c);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
if (TYPE(c) != T_ARRAY || !RARRAY_PTR(c)) {
|
|
579
|
+
rb_raise(pl_ePLruby, "expected an Array");
|
|
580
|
+
}
|
|
581
|
+
if (tupdesc->natts != RARRAY_LEN(c)) {
|
|
582
|
+
rb_raise(pl_ePLruby, "Invalid number of rows (%d expected %d)",
|
|
583
|
+
RARRAY_LEN(c), tupdesc->natts);
|
|
584
|
+
}
|
|
585
|
+
dvalues = ALLOCA_N(Datum, RARRAY_LEN(c));
|
|
586
|
+
MEMZERO(dvalues, Datum, RARRAY_LEN(c));
|
|
587
|
+
nulls = ALLOCA_N(char, RARRAY_LEN(c));
|
|
588
|
+
MEMZERO(nulls, char, RARRAY_LEN(c));
|
|
589
|
+
for (i = 0; i < RARRAY_LEN(c); i++) {
|
|
590
|
+
if (NIL_P(RARRAY_PTR(c)[i]) ||
|
|
591
|
+
tupdesc->attrs[i]->attisdropped) {
|
|
592
|
+
dvalues[i] = (Datum)0;
|
|
593
|
+
nulls[i] = 'n';
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
nulls[i] = ' ';
|
|
597
|
+
typid = tupdesc->attrs[i]->atttypid;
|
|
598
|
+
if (tupdesc->attrs[i]->attndims != 0 ||
|
|
599
|
+
tpl->att->attinfuncs[i].fn_addr == (PGFunction)array_in) {
|
|
600
|
+
pl_proc_desc prodesc;
|
|
601
|
+
FmgrInfo func;
|
|
602
|
+
HeapTuple hp;
|
|
603
|
+
Form_pg_type fpg;
|
|
604
|
+
|
|
605
|
+
MEMZERO(&prodesc, pl_proc_desc, 1);
|
|
606
|
+
PLRUBY_BEGIN(1);
|
|
607
|
+
hp = SearchSysCache(TYPEOID, OidGD(typid), 0, 0, 0);
|
|
608
|
+
if (!HeapTupleIsValid(hp)) {
|
|
609
|
+
rb_raise(pl_ePLruby, "cache lookup failed for type %u",
|
|
610
|
+
typid);
|
|
611
|
+
}
|
|
612
|
+
fpg = (Form_pg_type) GETSTRUCT(hp);
|
|
613
|
+
#if PG_PL_VERSION >= 75
|
|
614
|
+
typid = getTypeIOParam(hp);
|
|
615
|
+
#else
|
|
616
|
+
typid = fpg->typelem;
|
|
617
|
+
#endif
|
|
618
|
+
ReleaseSysCache(hp);
|
|
619
|
+
hp = SearchSysCache(TYPEOID, OidGD(typid), 0, 0, 0);
|
|
620
|
+
PLRUBY_END;
|
|
621
|
+
if (!HeapTupleIsValid(hp)) {
|
|
622
|
+
rb_raise(pl_ePLruby, "cache lookup failed for type %u",
|
|
623
|
+
typid);
|
|
624
|
+
}
|
|
625
|
+
fpg = (Form_pg_type) GETSTRUCT(hp);
|
|
626
|
+
fmgr_info(fpg->typinput, &func);
|
|
627
|
+
prodesc.result_func = func;
|
|
628
|
+
prodesc.result_oid = typid;
|
|
629
|
+
prodesc.result_elem = typid;
|
|
630
|
+
prodesc.result_val = fpg->typbyval;
|
|
631
|
+
prodesc.result_len = fpg->typlen;
|
|
632
|
+
prodesc.result_align = fpg->typalign;
|
|
633
|
+
ReleaseSysCache(hp);
|
|
634
|
+
dvalues[i] = plruby_return_array(RARRAY_PTR(c)[i], &prodesc);
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
#if PG_PL_VERSION >= 75
|
|
638
|
+
dvalues[i] = plruby_to_datum(RARRAY_PTR(c)[i],
|
|
639
|
+
&tpl->att->attinfuncs[i],
|
|
640
|
+
typid,
|
|
641
|
+
tpl->att->attioparams[i],
|
|
642
|
+
tpl->att->atttypmods[i]);
|
|
643
|
+
#else
|
|
644
|
+
dvalues[i] = plruby_to_datum(RARRAY_PTR(c)[i],
|
|
645
|
+
&tpl->att->attinfuncs[i],
|
|
646
|
+
typid,
|
|
647
|
+
tpl->att->attelems[i],
|
|
648
|
+
tpl->att->atttypmods[i]);
|
|
649
|
+
#endif
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
654
|
+
retval = heap_formtuple(tupdesc, dvalues, nulls);
|
|
655
|
+
PLRUBY_END_PROTECT;
|
|
656
|
+
return retval;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
static VALUE
|
|
660
|
+
pl_tuple_put(VALUE c, VALUE tuple)
|
|
661
|
+
{
|
|
662
|
+
HeapTuple retval;
|
|
663
|
+
MemoryContext oldcxt;
|
|
664
|
+
struct pl_tuple *tpl;
|
|
665
|
+
|
|
666
|
+
GetTuple(tuple, tpl);
|
|
667
|
+
retval = pl_tuple_heap(c, tuple);
|
|
668
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
669
|
+
oldcxt = MemoryContextSwitchTo(tpl->cxt);
|
|
670
|
+
if (!tpl->out) {
|
|
671
|
+
#if PG_PL_VERSION >= 74
|
|
672
|
+
tpl->out = tuplestore_begin_heap(true, false, SortMem);
|
|
673
|
+
#else
|
|
674
|
+
tpl->out = tuplestore_begin_heap(true, SortMem);
|
|
675
|
+
#endif
|
|
676
|
+
}
|
|
677
|
+
tuplestore_puttuple(tpl->out, retval);
|
|
678
|
+
MemoryContextSwitchTo(oldcxt);
|
|
679
|
+
PLRUBY_END_PROTECT;
|
|
680
|
+
return Qnil;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
static VALUE
|
|
684
|
+
pl_ary_collect(VALUE c, VALUE ary)
|
|
685
|
+
{
|
|
686
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
687
|
+
rb_ary_push(ary,c);
|
|
688
|
+
PLRUBY_END_PROTECT;
|
|
689
|
+
return Qnil;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
static Datum
|
|
693
|
+
pl_tuple_datum(VALUE c, VALUE tuple)
|
|
694
|
+
{
|
|
695
|
+
Datum retval;
|
|
696
|
+
HeapTuple tmp;
|
|
697
|
+
struct pl_tuple *tpl;
|
|
698
|
+
|
|
699
|
+
GetTuple(tuple, tpl);
|
|
700
|
+
tmp = pl_tuple_heap(c, tuple);
|
|
701
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
702
|
+
retval = TupleGD(TupleDescGetSlot(tpl->att->tupdesc), tmp);
|
|
703
|
+
PLRUBY_END_PROTECT;
|
|
704
|
+
return retval;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
struct pl_arg {
|
|
708
|
+
ID id;
|
|
709
|
+
int named;
|
|
710
|
+
VALUE ary;
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
static void
|
|
714
|
+
pl_arg_mark(struct pl_arg *args)
|
|
715
|
+
{
|
|
716
|
+
rb_gc_mark(args->ary);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
static VALUE
|
|
720
|
+
pl_func(VALUE arg)
|
|
721
|
+
{
|
|
722
|
+
#if HAVE_RB_BLOCK_CALL
|
|
723
|
+
return Qtrue;
|
|
724
|
+
#else
|
|
725
|
+
struct pl_arg *args;
|
|
726
|
+
|
|
727
|
+
Data_Get_Struct(arg, struct pl_arg, args);
|
|
728
|
+
if (args->named) {
|
|
729
|
+
return rb_funcall2(pl_mPLtemp, args->id, RARRAY_LEN(args->ary),
|
|
730
|
+
RARRAY_PTR(args->ary));
|
|
731
|
+
}
|
|
732
|
+
return rb_funcall(pl_mPLtemp, args->id, 1, args->ary);
|
|
733
|
+
#endif
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
static VALUE
|
|
737
|
+
pl_string(VALUE arg)
|
|
738
|
+
{
|
|
739
|
+
struct pl_arg *args;
|
|
740
|
+
VALUE tmp[2], plan;
|
|
741
|
+
|
|
742
|
+
Data_Get_Struct(arg, struct pl_arg, args);
|
|
743
|
+
tmp[0] = args->ary;
|
|
744
|
+
tmp[1] = rb_hash_new();
|
|
745
|
+
rb_hash_aset(tmp[1], rb_str_new2("block"), INT2NUM(50));
|
|
746
|
+
rb_hash_aset(tmp[1], rb_str_new2("output"), rb_str_new2("value"));
|
|
747
|
+
plan = plruby_s_new(2, tmp, pl_cPLPlan);
|
|
748
|
+
#if HAVE_RB_BLOCK_CALL
|
|
749
|
+
return plan;
|
|
750
|
+
#else
|
|
751
|
+
rb_funcall2(plan, rb_intern("each"), 0, 0);
|
|
752
|
+
return Qnil;
|
|
753
|
+
#endif
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
static VALUE
|
|
757
|
+
pl_warn(argc, argv, obj)
|
|
758
|
+
int argc;
|
|
759
|
+
VALUE *argv;
|
|
760
|
+
VALUE obj;
|
|
761
|
+
{
|
|
762
|
+
int level, indice;
|
|
763
|
+
VALUE res;
|
|
764
|
+
|
|
765
|
+
level = NOTICE;
|
|
766
|
+
indice = 0;
|
|
767
|
+
switch (argc) {
|
|
768
|
+
case 2:
|
|
769
|
+
indice = 1;
|
|
770
|
+
switch (level = NUM2INT(argv[0])) {
|
|
771
|
+
#ifdef DEBUG
|
|
772
|
+
case DEBUG:
|
|
773
|
+
#endif
|
|
774
|
+
#ifdef DEBUG1
|
|
775
|
+
case DEBUG1:
|
|
776
|
+
#endif
|
|
777
|
+
#ifdef DEBUG2
|
|
778
|
+
case DEBUG2:
|
|
779
|
+
#endif
|
|
780
|
+
#ifdef DEBUG3
|
|
781
|
+
case DEBUG3:
|
|
782
|
+
#endif
|
|
783
|
+
#ifdef DEBUG4
|
|
784
|
+
case DEBUG4:
|
|
785
|
+
#endif
|
|
786
|
+
#ifdef DEBUG5
|
|
787
|
+
case DEBUG5:
|
|
788
|
+
#endif
|
|
789
|
+
#ifdef NOTICE
|
|
790
|
+
case NOTICE:
|
|
791
|
+
#endif
|
|
792
|
+
#ifdef LOG
|
|
793
|
+
#if !defined(DEBUG) || LOG != DEBUG
|
|
794
|
+
case LOG:
|
|
795
|
+
#endif
|
|
796
|
+
#endif
|
|
797
|
+
#ifdef NOIND
|
|
798
|
+
case NOIND:
|
|
799
|
+
#endif
|
|
800
|
+
#ifdef WARNING
|
|
801
|
+
case WARNING:
|
|
802
|
+
#endif
|
|
803
|
+
#ifdef WARN
|
|
804
|
+
case WARN:
|
|
805
|
+
#endif
|
|
806
|
+
#ifdef ERROR
|
|
807
|
+
case ERROR:
|
|
808
|
+
#endif
|
|
809
|
+
#ifdef FATAL
|
|
810
|
+
case FATAL:
|
|
811
|
+
#endif
|
|
812
|
+
break;
|
|
813
|
+
default:
|
|
814
|
+
rb_raise(pl_ePLruby, "invalid level %d", level);
|
|
815
|
+
}
|
|
816
|
+
case 1:
|
|
817
|
+
res = argv[indice];
|
|
818
|
+
if (NIL_P(res)) {
|
|
819
|
+
return Qnil;
|
|
820
|
+
}
|
|
821
|
+
res = plruby_to_s(res);
|
|
822
|
+
break;
|
|
823
|
+
default:
|
|
824
|
+
rb_raise(pl_ePLruby, "invalid syntax");
|
|
825
|
+
}
|
|
826
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
827
|
+
elog(level, "%s", RSTRING_PTR(res));
|
|
828
|
+
PLRUBY_END_PROTECT;
|
|
829
|
+
return Qnil;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
static VALUE
|
|
833
|
+
pl_quote(obj, mes)
|
|
834
|
+
VALUE obj, mes;
|
|
835
|
+
{
|
|
836
|
+
char *tmp, *cp1, *cp2;
|
|
837
|
+
|
|
838
|
+
if (TYPE(mes) != T_STRING || !RSTRING_PTR(mes)) {
|
|
839
|
+
rb_raise(pl_ePLruby, "quote: string expected");
|
|
840
|
+
}
|
|
841
|
+
tmp = ALLOCA_N(char, RSTRING_LEN(mes) * 2 + 1);
|
|
842
|
+
cp1 = RSTRING_PTR(mes);
|
|
843
|
+
cp2 = tmp;
|
|
844
|
+
while (*cp1) {
|
|
845
|
+
if (*cp1 == '\'')
|
|
846
|
+
*cp2++ = '\'';
|
|
847
|
+
else {
|
|
848
|
+
if (*cp1 == '\\')
|
|
849
|
+
*cp2++ = '\\';
|
|
850
|
+
}
|
|
851
|
+
*cp2++ = *cp1++;
|
|
852
|
+
}
|
|
853
|
+
*cp2 = '\0';
|
|
854
|
+
return rb_tainted_str_new2(tmp);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
void
|
|
858
|
+
plruby_exec_output(VALUE option, int compose, int *result)
|
|
859
|
+
{
|
|
860
|
+
if (TYPE(option) != T_STRING || RSTRING_PTR(option) == 0 || !result) {
|
|
861
|
+
rb_raise(pl_ePLruby, "string expected for optional output");
|
|
862
|
+
}
|
|
863
|
+
if (strcmp(RSTRING_PTR(option), "array") == 0) {
|
|
864
|
+
*result = compose|RET_DESC_ARR;
|
|
865
|
+
}
|
|
866
|
+
else if (strcmp(RSTRING_PTR(option), "hash") == 0) {
|
|
867
|
+
*result = compose|RET_DESC;
|
|
868
|
+
}
|
|
869
|
+
else if (strcmp(RSTRING_PTR(option), "value") == 0) {
|
|
870
|
+
*result = RET_ARRAY;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
static VALUE
|
|
875
|
+
pl_SPI_exec(argc, argv, obj)
|
|
876
|
+
int argc;
|
|
877
|
+
VALUE *argv;
|
|
878
|
+
VALUE obj;
|
|
879
|
+
{
|
|
880
|
+
int spi_rc, count, array;
|
|
881
|
+
int i, comp, ntuples;
|
|
882
|
+
struct portal_options po;
|
|
883
|
+
VALUE a, b, c, result;
|
|
884
|
+
HeapTuple *tuples;
|
|
885
|
+
TupleDesc tupdesc = NULL;
|
|
886
|
+
|
|
887
|
+
count = 0;
|
|
888
|
+
array = comp = RET_HASH;
|
|
889
|
+
if (argc && TYPE(argv[argc - 1]) == T_HASH) {
|
|
890
|
+
MEMZERO(&po, struct portal_options, 1);
|
|
891
|
+
rb_iterate(rb_each, argv[argc - 1], plruby_i_each, (VALUE)&po);
|
|
892
|
+
comp = po.output;
|
|
893
|
+
count = po.count;
|
|
894
|
+
argc--;
|
|
895
|
+
}
|
|
896
|
+
switch (rb_scan_args(argc, argv, "12", &a, &b, &c)) {
|
|
897
|
+
case 3:
|
|
898
|
+
plruby_exec_output(c, RET_HASH, &comp);
|
|
899
|
+
/* ... */
|
|
900
|
+
case 2:
|
|
901
|
+
if (!NIL_P(b)) {
|
|
902
|
+
count = NUM2INT(b);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
if (TYPE(a) != T_STRING) {
|
|
906
|
+
rb_raise(pl_ePLruby, "exec: first argument must be a string");
|
|
907
|
+
}
|
|
908
|
+
array = comp;
|
|
909
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
910
|
+
spi_rc = SPI_exec(RSTRING_PTR(a), count);
|
|
911
|
+
PLRUBY_END_PROTECT;
|
|
912
|
+
|
|
913
|
+
switch (spi_rc) {
|
|
914
|
+
case SPI_OK_UTILITY:
|
|
915
|
+
if (SPI_tuptable == NULL) {
|
|
916
|
+
SPI_freetuptable(SPI_tuptable);
|
|
917
|
+
return Qtrue;
|
|
918
|
+
}
|
|
919
|
+
break;
|
|
920
|
+
case SPI_OK_SELINTO:
|
|
921
|
+
case SPI_OK_INSERT:
|
|
922
|
+
case SPI_OK_DELETE:
|
|
923
|
+
case SPI_OK_UPDATE:
|
|
924
|
+
SPI_freetuptable(SPI_tuptable);
|
|
925
|
+
return INT2NUM(SPI_processed);
|
|
926
|
+
case SPI_OK_SELECT:
|
|
927
|
+
#ifdef SPI_OK_INSERT_RETURNING
|
|
928
|
+
case SPI_OK_INSERT_RETURNING:
|
|
929
|
+
case SPI_OK_DELETE_RETURNING:
|
|
930
|
+
case SPI_OK_UPDATE_RETURNING:
|
|
931
|
+
#endif
|
|
932
|
+
break;
|
|
933
|
+
case SPI_ERROR_ARGUMENT:
|
|
934
|
+
rb_raise(pl_ePLruby, "SPI_exec() failed - SPI_ERROR_ARGUMENT");
|
|
935
|
+
case SPI_ERROR_UNCONNECTED:
|
|
936
|
+
rb_raise(pl_ePLruby, "SPI_exec() failed - SPI_ERROR_UNCONNECTED");
|
|
937
|
+
case SPI_ERROR_COPY:
|
|
938
|
+
rb_raise(pl_ePLruby, "SPI_exec() failed - SPI_ERROR_COPY");
|
|
939
|
+
case SPI_ERROR_CURSOR:
|
|
940
|
+
rb_raise(pl_ePLruby, "SPI_exec() failed - SPI_ERROR_CURSOR");
|
|
941
|
+
case SPI_ERROR_TRANSACTION:
|
|
942
|
+
rb_raise(pl_ePLruby, "SPI_exec() failed - SPI_ERROR_TRANSACTION");
|
|
943
|
+
case SPI_ERROR_OPUNKNOWN:
|
|
944
|
+
rb_raise(pl_ePLruby, "SPI_exec() failed - SPI_ERROR_OPUNKNOWN");
|
|
945
|
+
default:
|
|
946
|
+
rb_raise(pl_ePLruby, "SPI_exec() failed - unknown RC %d", spi_rc);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
ntuples = SPI_processed;
|
|
950
|
+
if (ntuples <= 0) {
|
|
951
|
+
SPI_freetuptable(SPI_tuptable);
|
|
952
|
+
if (rb_block_given_p() || count == 1)
|
|
953
|
+
return Qfalse;
|
|
954
|
+
else
|
|
955
|
+
return rb_ary_new2(0);
|
|
956
|
+
}
|
|
957
|
+
tuples = SPI_tuptable->vals;
|
|
958
|
+
tupdesc = SPI_tuptable->tupdesc;
|
|
959
|
+
if (rb_block_given_p()) {
|
|
960
|
+
if (count == 1) {
|
|
961
|
+
if (!(array & RET_DESC)) {
|
|
962
|
+
array |= RET_BASIC;
|
|
963
|
+
}
|
|
964
|
+
plruby_build_tuple(tuples[0], tupdesc, array);
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
for (i = 0; i < ntuples; i++) {
|
|
968
|
+
rb_yield(plruby_build_tuple(tuples[i], tupdesc, array));
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
result = Qtrue;
|
|
972
|
+
}
|
|
973
|
+
else {
|
|
974
|
+
if (count == 1) {
|
|
975
|
+
result = plruby_build_tuple(tuples[0], tupdesc, array);
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
result = rb_ary_new2(ntuples);
|
|
979
|
+
for (i = 0; i < ntuples; i++) {
|
|
980
|
+
rb_ary_push(result, plruby_build_tuple(tuples[i], tupdesc, array));
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
SPI_freetuptable(SPI_tuptable);
|
|
985
|
+
return result;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
static VALUE
|
|
989
|
+
pl_convert_arg(Datum value, Oid typoid, FmgrInfo *finfo, Oid typelem,
|
|
990
|
+
int attlen)
|
|
991
|
+
{
|
|
992
|
+
VALUE result;
|
|
993
|
+
char *outstr;
|
|
994
|
+
|
|
995
|
+
if (typoid == BOOLOID) {
|
|
996
|
+
return DatumGetBool(value)?Qtrue:Qfalse;
|
|
997
|
+
}
|
|
998
|
+
#ifdef PLRUBY_ENABLE_CONVERSION
|
|
999
|
+
{
|
|
1000
|
+
VALUE vid, klass;
|
|
1001
|
+
|
|
1002
|
+
vid = INT2NUM(typoid);
|
|
1003
|
+
klass = rb_hash_aref(plruby_classes, vid);
|
|
1004
|
+
if (NIL_P(klass)) {
|
|
1005
|
+
klass = rb_hash_aref(plruby_conversions, vid);
|
|
1006
|
+
if (NIL_P(klass)) {
|
|
1007
|
+
st_insert(RHASH_TBL(plruby_classes), vid, Qfalse);
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
klass = rb_const_get(rb_cObject, NUM2INT(klass));
|
|
1011
|
+
st_insert(RHASH_TBL(plruby_classes), vid, klass);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (RTEST(klass)) {
|
|
1015
|
+
struct datum_value *dv;
|
|
1016
|
+
VALUE res;
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
res = Data_Make_Struct(rb_cData, struct datum_value,
|
|
1020
|
+
pl_conv_mark, free, dv);
|
|
1021
|
+
dv->d = value;
|
|
1022
|
+
dv->typoid = typoid;
|
|
1023
|
+
dv->typlen = attlen;
|
|
1024
|
+
res = rb_funcall(klass, id_from_datum, 1, res);
|
|
1025
|
+
return res;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
#endif
|
|
1029
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
1030
|
+
outstr = DatumGetCString(FunctionCall3(finfo, value, OidGD(typelem),
|
|
1031
|
+
IntGD(attlen)));
|
|
1032
|
+
result = rb_tainted_str_new2(outstr);
|
|
1033
|
+
pfree(outstr);
|
|
1034
|
+
PLRUBY_END_PROTECT;
|
|
1035
|
+
return result;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
static VALUE
|
|
1039
|
+
create_array(index, ndim, dim, p, prodesc, curr, typoid)
|
|
1040
|
+
int index, ndim, *dim, curr;
|
|
1041
|
+
Oid typoid;
|
|
1042
|
+
char **p;
|
|
1043
|
+
pl_proc_desc *prodesc;
|
|
1044
|
+
{
|
|
1045
|
+
VALUE res, tmp;
|
|
1046
|
+
Datum itemvalue;
|
|
1047
|
+
int i;
|
|
1048
|
+
|
|
1049
|
+
res = rb_ary_new2(dim[index]);
|
|
1050
|
+
for (i = 0; i < dim[index]; ++i) {
|
|
1051
|
+
if (index == ndim - 1) {
|
|
1052
|
+
itemvalue = fetch_att(*p, prodesc->arg_val[curr],
|
|
1053
|
+
prodesc->arg_len[curr]);
|
|
1054
|
+
tmp = pl_convert_arg(itemvalue, typoid,
|
|
1055
|
+
&prodesc->arg_func[curr], (Datum)0, -1);
|
|
1056
|
+
#ifdef att_addlength_pointer
|
|
1057
|
+
*p = att_addlength_pointer(*p, prodesc->arg_len[curr], PointerGD(*p));
|
|
1058
|
+
*p = (char *) att_align_nominal(*p, prodesc->arg_align[curr]);
|
|
1059
|
+
#else
|
|
1060
|
+
*p = att_addlength(*p, prodesc->arg_len[curr], PointerGD(*p));
|
|
1061
|
+
*p = (char *) att_align(*p, prodesc->arg_align[curr]);
|
|
1062
|
+
#endif
|
|
1063
|
+
rb_ary_push(res, tmp);
|
|
1064
|
+
}
|
|
1065
|
+
else {
|
|
1066
|
+
for (i = 0; i < dim[index]; ++i) {
|
|
1067
|
+
rb_ary_push(res, create_array(index + 1, ndim, dim, p,
|
|
1068
|
+
prodesc, curr, typoid));
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
return res;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
VALUE
|
|
1076
|
+
plruby_build_tuple(HeapTuple tuple, TupleDesc tupdesc, int type_ret)
|
|
1077
|
+
{
|
|
1078
|
+
int i;
|
|
1079
|
+
VALUE output, res = Qnil;
|
|
1080
|
+
Datum attr;
|
|
1081
|
+
bool isnull;
|
|
1082
|
+
char *attname;
|
|
1083
|
+
HeapTuple typeTup;
|
|
1084
|
+
Oid typoutput;
|
|
1085
|
+
Oid typelem;
|
|
1086
|
+
Form_pg_type fpgt;
|
|
1087
|
+
|
|
1088
|
+
output = Qnil;
|
|
1089
|
+
if (type_ret & RET_ARRAY) {
|
|
1090
|
+
output = rb_ary_new();
|
|
1091
|
+
}
|
|
1092
|
+
else if (type_ret & RET_HASH) {
|
|
1093
|
+
output = rb_hash_new();
|
|
1094
|
+
}
|
|
1095
|
+
if (!tuple) {
|
|
1096
|
+
return output;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
for (i = 0; i < tupdesc->natts; i++) {
|
|
1100
|
+
if (tupdesc->attrs[i]->attisdropped)
|
|
1101
|
+
continue;
|
|
1102
|
+
PLRUBY_BEGIN(1);
|
|
1103
|
+
attname = NameStr(tupdesc->attrs[i]->attname);
|
|
1104
|
+
attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);
|
|
1105
|
+
typeTup = SearchSysCache(TYPEOID, OidGD(tupdesc->attrs[i]->atttypid),
|
|
1106
|
+
0, 0, 0);
|
|
1107
|
+
PLRUBY_END;
|
|
1108
|
+
|
|
1109
|
+
if (!HeapTupleIsValid(typeTup)) {
|
|
1110
|
+
rb_raise(pl_ePLruby, "Cache lookup for attribute '%s' type %ld failed",
|
|
1111
|
+
attname, OidGD(tupdesc->attrs[i]->atttypid));
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
fpgt = (Form_pg_type) GETSTRUCT(typeTup);
|
|
1115
|
+
typoutput = (Oid) (fpgt->typoutput);
|
|
1116
|
+
#if PG_PL_VERSION >= 75
|
|
1117
|
+
typelem = getTypeIOParam(typeTup);
|
|
1118
|
+
#else
|
|
1119
|
+
typelem = (Oid) (fpgt->typelem);
|
|
1120
|
+
#endif
|
|
1121
|
+
if (type_ret & RET_DESC) {
|
|
1122
|
+
Oid typeid;
|
|
1123
|
+
char *typname;
|
|
1124
|
+
int alen;
|
|
1125
|
+
|
|
1126
|
+
typname = NameStr(fpgt->typname);
|
|
1127
|
+
alen = tupdesc->attrs[i]->attlen;
|
|
1128
|
+
typeid = tupdesc->attrs[i]->atttypid;
|
|
1129
|
+
if (strcmp(typname, "text") == 0) {
|
|
1130
|
+
alen = -1;
|
|
1131
|
+
}
|
|
1132
|
+
else if (strcmp(typname, "bpchar") == 0 ||
|
|
1133
|
+
strcmp(typname, "varchar") == 0) {
|
|
1134
|
+
if (tupdesc->attrs[i]->atttypmod == -1) {
|
|
1135
|
+
alen = 0;
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
alen = tupdesc->attrs[i]->atttypmod - 4;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
if ((type_ret & RET_DESC_ARR) == RET_DESC_ARR) {
|
|
1142
|
+
res = rb_ary_new();
|
|
1143
|
+
rb_ary_push(res, rb_tainted_str_new2(attname));
|
|
1144
|
+
rb_ary_push(res, Qnil);
|
|
1145
|
+
rb_ary_push(res, rb_tainted_str_new2(typname));
|
|
1146
|
+
rb_ary_push(res, INT2FIX(alen));
|
|
1147
|
+
rb_ary_push(res, INT2FIX(typeid));
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
res = rb_hash_new();
|
|
1151
|
+
rb_hash_aset(res, rb_tainted_str_new2("name"), rb_tainted_str_new2(attname));
|
|
1152
|
+
rb_hash_aset(res, rb_tainted_str_new2("type"), rb_tainted_str_new2(typname));
|
|
1153
|
+
rb_hash_aset(res, rb_tainted_str_new2("typeid"), INT2FIX(typeid));
|
|
1154
|
+
rb_hash_aset(res, rb_tainted_str_new2("len"), INT2FIX(alen));
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
ReleaseSysCache(typeTup);
|
|
1158
|
+
if (!isnull && OidIsValid(typoutput)) {
|
|
1159
|
+
VALUE s;
|
|
1160
|
+
|
|
1161
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
1162
|
+
if (NameStr(fpgt->typname)[0] == '_') {
|
|
1163
|
+
ArrayType *array;
|
|
1164
|
+
int ndim, *dim;
|
|
1165
|
+
|
|
1166
|
+
array = (ArrayType *)attr;
|
|
1167
|
+
ndim = ARR_NDIM(array);
|
|
1168
|
+
dim = ARR_DIMS(array);
|
|
1169
|
+
if (ArrayGetNItems(ndim, dim) == 0) {
|
|
1170
|
+
s = rb_ary_new2(0);
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
pl_proc_desc prodesc;
|
|
1174
|
+
HeapTuple typeTuple;
|
|
1175
|
+
Form_pg_type typeStruct;
|
|
1176
|
+
Oid elemtyp;
|
|
1177
|
+
char *p = ARR_DATA_PTR(array);
|
|
1178
|
+
|
|
1179
|
+
typeTuple =
|
|
1180
|
+
SearchSysCache(TYPEOID, OidGD(typelem), 0, 0, 0);
|
|
1181
|
+
if (!HeapTupleIsValid(typeTuple)) {
|
|
1182
|
+
elog(ERROR, "cache lookup failed for type %u",
|
|
1183
|
+
typelem);
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
|
|
1187
|
+
|
|
1188
|
+
fmgr_info(typeStruct->typoutput, &(prodesc.arg_func[0]));
|
|
1189
|
+
prodesc.arg_val[0] = typeStruct->typbyval;
|
|
1190
|
+
prodesc.arg_len[0] = typeStruct->typlen;
|
|
1191
|
+
prodesc.arg_align[0] = typeStruct->typalign;
|
|
1192
|
+
elemtyp = ARR_ELEMTYPE(array);
|
|
1193
|
+
ReleaseSysCache(typeTuple);
|
|
1194
|
+
s = create_array(0, ndim, dim, &p, &prodesc, 0, elemtyp);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
else {
|
|
1198
|
+
FmgrInfo finfo;
|
|
1199
|
+
|
|
1200
|
+
fmgr_info(typoutput, &finfo);
|
|
1201
|
+
|
|
1202
|
+
s = pl_convert_arg(attr, tupdesc->attrs[i]->atttypid,
|
|
1203
|
+
&finfo, typelem,tupdesc->attrs[i]->attlen);
|
|
1204
|
+
}
|
|
1205
|
+
PLRUBY_END_PROTECT;
|
|
1206
|
+
|
|
1207
|
+
if (type_ret & RET_DESC) {
|
|
1208
|
+
if (TYPE(res) == T_ARRAY) {
|
|
1209
|
+
RARRAY_PTR(res)[1] = s;
|
|
1210
|
+
}
|
|
1211
|
+
else {
|
|
1212
|
+
rb_hash_aset(res, rb_tainted_str_new2("value"), s);
|
|
1213
|
+
}
|
|
1214
|
+
if (TYPE(output) == T_ARRAY) {
|
|
1215
|
+
rb_ary_push(output, res);
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
rb_yield(res);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
if (type_ret & RET_BASIC) {
|
|
1223
|
+
rb_yield(rb_assoc_new(rb_tainted_str_new2(attname), s));
|
|
1224
|
+
}
|
|
1225
|
+
else {
|
|
1226
|
+
switch (TYPE(output)) {
|
|
1227
|
+
case T_HASH:
|
|
1228
|
+
rb_hash_aset(output, rb_tainted_str_new2(attname), s);
|
|
1229
|
+
break;
|
|
1230
|
+
case T_ARRAY:
|
|
1231
|
+
rb_ary_push(output, s);
|
|
1232
|
+
break;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
else {
|
|
1238
|
+
if (isnull) {
|
|
1239
|
+
if (type_ret & RET_DESC) {
|
|
1240
|
+
if (TYPE(res) == T_HASH) {
|
|
1241
|
+
rb_hash_aset(res, rb_tainted_str_new2("value"), Qnil);
|
|
1242
|
+
}
|
|
1243
|
+
if (TYPE(output) == T_ARRAY) {
|
|
1244
|
+
rb_ary_push(output, res);
|
|
1245
|
+
}
|
|
1246
|
+
else {
|
|
1247
|
+
rb_yield(res);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
else {
|
|
1251
|
+
if (type_ret & RET_BASIC) {
|
|
1252
|
+
rb_yield(rb_assoc_new(rb_tainted_str_new2(attname), Qnil));
|
|
1253
|
+
}
|
|
1254
|
+
else {
|
|
1255
|
+
switch (TYPE(output)) {
|
|
1256
|
+
case T_HASH:
|
|
1257
|
+
rb_hash_aset(output, rb_tainted_str_new2(attname), Qnil);
|
|
1258
|
+
break;
|
|
1259
|
+
case T_ARRAY:
|
|
1260
|
+
rb_ary_push(output, Qnil);
|
|
1261
|
+
break;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
return output;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
VALUE
|
|
1272
|
+
plruby_create_args(struct pl_thread_st *plth, pl_proc_desc *prodesc)
|
|
1273
|
+
{
|
|
1274
|
+
VALUE ary;
|
|
1275
|
+
int i;
|
|
1276
|
+
PG_FUNCTION_ARGS;
|
|
1277
|
+
|
|
1278
|
+
fcinfo = plth->fcinfo;
|
|
1279
|
+
{
|
|
1280
|
+
VALUE res;
|
|
1281
|
+
struct pl_tuple *tpl;
|
|
1282
|
+
|
|
1283
|
+
res = rb_thread_local_aref(rb_thread_current(), id_thr);
|
|
1284
|
+
if (NIL_P(res)) {
|
|
1285
|
+
res = Data_Make_Struct(rb_cData, struct pl_tuple, pl_thr_mark, free, tpl);
|
|
1286
|
+
}
|
|
1287
|
+
GetTuple(res, tpl);
|
|
1288
|
+
tpl->fcinfo = fcinfo;
|
|
1289
|
+
tpl->pro = prodesc;
|
|
1290
|
+
rb_thread_local_aset(rb_thread_current(), id_thr, res);
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
ary = rb_ary_new2(prodesc->nargs);
|
|
1294
|
+
for (i = 0; i < prodesc->nargs; i++) {
|
|
1295
|
+
if (fcinfo->argnull[i]) {
|
|
1296
|
+
rb_ary_push(ary, Qnil);
|
|
1297
|
+
}
|
|
1298
|
+
else if (prodesc->arg_is_rel[i]) {
|
|
1299
|
+
VALUE tmp;
|
|
1300
|
+
|
|
1301
|
+
#if PG_PL_VERSION >= 75
|
|
1302
|
+
HeapTupleHeader td;
|
|
1303
|
+
Oid tupType;
|
|
1304
|
+
int32 tupTypmod;
|
|
1305
|
+
TupleDesc tupdesc;
|
|
1306
|
+
HeapTupleData tmptup;
|
|
1307
|
+
|
|
1308
|
+
td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
|
|
1309
|
+
tupType = HeapTupleHeaderGetTypeId(td);
|
|
1310
|
+
tupTypmod = HeapTupleHeaderGetTypMod(td);
|
|
1311
|
+
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
|
|
1312
|
+
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
|
|
1313
|
+
tmptup.t_data = td;
|
|
1314
|
+
tmp = plruby_build_tuple(&tmptup, tupdesc, RET_HASH);
|
|
1315
|
+
#else
|
|
1316
|
+
TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];
|
|
1317
|
+
tmp = plruby_build_tuple(slot->val, slot->ttc_tupleDescriptor, RET_HASH);
|
|
1318
|
+
#endif
|
|
1319
|
+
rb_iv_set(tmp, "plruby_tuple",
|
|
1320
|
+
Data_Wrap_Struct(rb_cData, 0, 0, (void *)fcinfo->arg[i]));
|
|
1321
|
+
rb_ary_push(ary, tmp);
|
|
1322
|
+
}
|
|
1323
|
+
else if (prodesc->arg_is_array[i]) {
|
|
1324
|
+
ArrayType *array;
|
|
1325
|
+
int ndim, *dim;
|
|
1326
|
+
char *p;
|
|
1327
|
+
|
|
1328
|
+
array = (ArrayType *)fcinfo->arg[i];
|
|
1329
|
+
ndim = ARR_NDIM(array);
|
|
1330
|
+
dim = ARR_DIMS(array);
|
|
1331
|
+
if (ArrayGetNItems(ndim, dim) == 0) {
|
|
1332
|
+
rb_ary_push(ary, rb_ary_new2(0));
|
|
1333
|
+
}
|
|
1334
|
+
else {
|
|
1335
|
+
Oid elemtyp;
|
|
1336
|
+
elemtyp = ARR_ELEMTYPE(array);
|
|
1337
|
+
p = ARR_DATA_PTR(array);
|
|
1338
|
+
rb_ary_push(ary, create_array(0, ndim, dim, &p, prodesc, i,
|
|
1339
|
+
elemtyp));
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
else {
|
|
1343
|
+
VALUE res;
|
|
1344
|
+
|
|
1345
|
+
res = pl_convert_arg(fcinfo->arg[i],
|
|
1346
|
+
prodesc->arg_type[i],
|
|
1347
|
+
&prodesc->arg_func[i],
|
|
1348
|
+
prodesc->arg_elem[i],
|
|
1349
|
+
prodesc->arg_len[i]);
|
|
1350
|
+
rb_ary_push(ary, res);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return ary;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
Datum
|
|
1357
|
+
plruby_return_value(struct pl_thread_st *plth, pl_proc_desc *prodesc,
|
|
1358
|
+
VALUE value_proname, VALUE ary)
|
|
1359
|
+
{
|
|
1360
|
+
VALUE c;
|
|
1361
|
+
int expr_multiple;
|
|
1362
|
+
PG_FUNCTION_ARGS;
|
|
1363
|
+
|
|
1364
|
+
fcinfo = plth->fcinfo;
|
|
1365
|
+
expr_multiple = 0;
|
|
1366
|
+
if (prodesc->result_type && prodesc->result_type != 'x' &&
|
|
1367
|
+
prodesc->result_type != 'y') {
|
|
1368
|
+
ReturnSetInfo *rsi;
|
|
1369
|
+
|
|
1370
|
+
if (!fcinfo || !fcinfo->resultinfo) {
|
|
1371
|
+
rb_raise(pl_ePLruby, "no description given");
|
|
1372
|
+
}
|
|
1373
|
+
rsi = (ReturnSetInfo *)fcinfo->resultinfo;
|
|
1374
|
+
if (prodesc->result_is_setof && !rsi->expectedDesc) {
|
|
1375
|
+
VALUE res, retary, arg;
|
|
1376
|
+
struct pl_arg *args;
|
|
1377
|
+
TupleDesc tupdesc;
|
|
1378
|
+
FuncCallContext *funcctx;
|
|
1379
|
+
Datum result;
|
|
1380
|
+
|
|
1381
|
+
arg = Data_Make_Struct(rb_cObject, struct pl_arg, pl_arg_mark, free, args);
|
|
1382
|
+
args->id = rb_intern(RSTRING_PTR(value_proname));
|
|
1383
|
+
args->ary = ary;
|
|
1384
|
+
#if PG_PL_VERSION >= 75
|
|
1385
|
+
args->named = prodesc->named_args;
|
|
1386
|
+
#endif
|
|
1387
|
+
|
|
1388
|
+
if (SRF_IS_FIRSTCALL())
|
|
1389
|
+
{
|
|
1390
|
+
MemoryContext oldcontext;
|
|
1391
|
+
|
|
1392
|
+
funcctx = SRF_FIRSTCALL_INIT();
|
|
1393
|
+
|
|
1394
|
+
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
|
1395
|
+
|
|
1396
|
+
/* Build a tuple descriptor for our result type */
|
|
1397
|
+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
1398
|
+
ereport(ERROR,
|
|
1399
|
+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
1400
|
+
errmsg("function returning record called in context "
|
|
1401
|
+
"that cannot accept type record")));
|
|
1402
|
+
/*
|
|
1403
|
+
* generate attribute metadata needed later to produce tuples from raw
|
|
1404
|
+
* C strings
|
|
1405
|
+
*/
|
|
1406
|
+
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
|
1407
|
+
|
|
1408
|
+
MemoryContextSwitchTo(oldcontext);
|
|
1409
|
+
|
|
1410
|
+
retary = rb_ary_new();
|
|
1411
|
+
#if HAVE_RB_BLOCK_CALL
|
|
1412
|
+
if (args->named) {
|
|
1413
|
+
res = rb_block_call(pl_mPLtemp, args->id,
|
|
1414
|
+
RARRAY_LEN(args->ary),
|
|
1415
|
+
RARRAY_PTR(args->ary),
|
|
1416
|
+
pl_ary_collect, retary);
|
|
1417
|
+
}
|
|
1418
|
+
else {
|
|
1419
|
+
res = rb_block_call(pl_mPLtemp, args->id,
|
|
1420
|
+
1, &args->ary,
|
|
1421
|
+
pl_ary_collect, retary);
|
|
1422
|
+
}
|
|
1423
|
+
#else
|
|
1424
|
+
res = rb_iterate(pl_func, arg, pl_ary_collect, retary);
|
|
1425
|
+
#endif
|
|
1426
|
+
elog(NOTICE, "returned array len is: %ld", RARRAY_LEN(retary) );
|
|
1427
|
+
|
|
1428
|
+
funcctx->max_calls = RARRAY_LEN(retary) ;
|
|
1429
|
+
funcctx->user_fctx = (void *)retary;
|
|
1430
|
+
|
|
1431
|
+
}
|
|
1432
|
+
funcctx = SRF_PERCALL_SETUP();
|
|
1433
|
+
|
|
1434
|
+
retary = (VALUE)funcctx->user_fctx;
|
|
1435
|
+
|
|
1436
|
+
if (funcctx->call_cntr < funcctx->max_calls) /* do when there is more left to send */
|
|
1437
|
+
{
|
|
1438
|
+
char ** values;
|
|
1439
|
+
HeapTuple tuple;
|
|
1440
|
+
size_t idx;
|
|
1441
|
+
VALUE resary;
|
|
1442
|
+
|
|
1443
|
+
resary = RARRAY_PTR(retary)[funcctx->call_cntr];
|
|
1444
|
+
values = (char **)palloc(RARRAY_LEN(resary) * sizeof(char *));
|
|
1445
|
+
|
|
1446
|
+
for ( idx = 0; idx < RARRAY_LEN(resary); idx++ )
|
|
1447
|
+
{
|
|
1448
|
+
VALUE str = rb_ary_entry( resary, idx );
|
|
1449
|
+
if (TYPE(str) != T_STRING) {
|
|
1450
|
+
str = rb_obj_as_string(str);
|
|
1451
|
+
}
|
|
1452
|
+
values[idx] = pstrdup( StringValueCStr( str ) );
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/* build a tuple */
|
|
1456
|
+
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
|
|
1457
|
+
|
|
1458
|
+
/* make the tuple into a datum */
|
|
1459
|
+
result = HeapTupleGetDatum(tuple);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
1463
|
+
{
|
|
1464
|
+
MemoryContext oldcxt;
|
|
1465
|
+
int rc;
|
|
1466
|
+
|
|
1467
|
+
oldcxt = MemoryContextSwitchTo(plruby_spi_context);
|
|
1468
|
+
if ((rc = SPI_finish()) != SPI_OK_FINISH) {
|
|
1469
|
+
elog(ERROR, "SPI_finish() failed : %d", rc);
|
|
1470
|
+
}
|
|
1471
|
+
MemoryContextSwitchTo(oldcxt);
|
|
1472
|
+
}
|
|
1473
|
+
PLRUBY_END_PROTECT;
|
|
1474
|
+
|
|
1475
|
+
if ( funcctx->call_cntr < funcctx->max_calls )
|
|
1476
|
+
{
|
|
1477
|
+
SRF_RETURN_NEXT(funcctx, result);
|
|
1478
|
+
}
|
|
1479
|
+
else
|
|
1480
|
+
{
|
|
1481
|
+
SRF_RETURN_DONE(funcctx);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
} else if ((rsi->allowedModes & SFRM_Materialize) && rsi->expectedDesc) {
|
|
1485
|
+
VALUE tuple, res, arg;
|
|
1486
|
+
struct pl_arg *args;
|
|
1487
|
+
struct pl_tuple *tpl;
|
|
1488
|
+
VALUE (*pl_call)(VALUE);
|
|
1489
|
+
|
|
1490
|
+
tuple = pl_tuple_s_new(fcinfo, prodesc);
|
|
1491
|
+
arg = Data_Make_Struct(rb_cObject, struct pl_arg, pl_arg_mark, free, args);
|
|
1492
|
+
args->id = rb_intern(RSTRING_PTR(value_proname));
|
|
1493
|
+
args->ary = ary;
|
|
1494
|
+
#if PG_PL_VERSION >= 75
|
|
1495
|
+
args->named = prodesc->named_args;
|
|
1496
|
+
#endif
|
|
1497
|
+
pl_call = pl_func;
|
|
1498
|
+
while (1) {
|
|
1499
|
+
#if HAVE_RB_BLOCK_CALL
|
|
1500
|
+
if (pl_call == pl_func) {
|
|
1501
|
+
if (args->named) {
|
|
1502
|
+
res = rb_block_call(pl_mPLtemp, args->id,
|
|
1503
|
+
RARRAY_LEN(args->ary),
|
|
1504
|
+
RARRAY_PTR(args->ary),
|
|
1505
|
+
pl_tuple_put, tuple);
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
res = rb_block_call(pl_mPLtemp, args->id,
|
|
1509
|
+
1, &args->ary,
|
|
1510
|
+
pl_tuple_put, tuple);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
else {
|
|
1514
|
+
res = rb_block_call(pl_string(arg), rb_intern("each"),
|
|
1515
|
+
0, 0, pl_tuple_put, tuple);
|
|
1516
|
+
}
|
|
1517
|
+
#else
|
|
1518
|
+
res = rb_iterate(pl_call, arg, pl_tuple_put, tuple);
|
|
1519
|
+
#endif
|
|
1520
|
+
Data_Get_Struct(tuple, struct pl_tuple, tpl);
|
|
1521
|
+
if (NIL_P(res) && !tpl->out) {
|
|
1522
|
+
MemoryContext oldcxt;
|
|
1523
|
+
|
|
1524
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
1525
|
+
oldcxt = MemoryContextSwitchTo(tpl->cxt);
|
|
1526
|
+
#if PG_PL_VERSION >= 74
|
|
1527
|
+
tpl->out = tuplestore_begin_heap(true, false, SortMem);
|
|
1528
|
+
#else
|
|
1529
|
+
tpl->out = tuplestore_begin_heap(true, SortMem);
|
|
1530
|
+
#endif
|
|
1531
|
+
MemoryContextSwitchTo(oldcxt);
|
|
1532
|
+
PLRUBY_END_PROTECT;
|
|
1533
|
+
}
|
|
1534
|
+
if (tpl->out) {
|
|
1535
|
+
MemoryContext oldcxt;
|
|
1536
|
+
|
|
1537
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
1538
|
+
oldcxt = MemoryContextSwitchTo(tpl->cxt);
|
|
1539
|
+
tuplestore_donestoring(tpl->out);
|
|
1540
|
+
MemoryContextSwitchTo(oldcxt);
|
|
1541
|
+
PLRUBY_END_PROTECT;
|
|
1542
|
+
((ReturnSetInfo *)fcinfo->resultinfo)->setResult = tpl->out;
|
|
1543
|
+
((ReturnSetInfo *)fcinfo->resultinfo)->returnMode = SFRM_Materialize;
|
|
1544
|
+
break;
|
|
1545
|
+
}
|
|
1546
|
+
if (NIL_P(res)) {
|
|
1547
|
+
break;
|
|
1548
|
+
}
|
|
1549
|
+
if (TYPE(res) != T_STRING || RSTRING_PTR(res) == 0) {
|
|
1550
|
+
rb_raise(pl_ePLruby, "invalid return type for a SET");
|
|
1551
|
+
}
|
|
1552
|
+
args->ary = res;
|
|
1553
|
+
pl_call = pl_string;
|
|
1554
|
+
}
|
|
1555
|
+
c = Qnil;
|
|
1556
|
+
}
|
|
1557
|
+
else if (IsA(rsi, ReturnSetInfo)) {
|
|
1558
|
+
expr_multiple = 1;
|
|
1559
|
+
#if PG_PL_VERSION >= 75
|
|
1560
|
+
if (prodesc->named_args) {
|
|
1561
|
+
c = rb_funcall2(pl_mPLtemp, rb_intern(RSTRING_PTR(value_proname)),
|
|
1562
|
+
RARRAY_LEN(ary), RARRAY_PTR(ary));
|
|
1563
|
+
}
|
|
1564
|
+
else {
|
|
1565
|
+
c = rb_funcall(pl_mPLtemp, rb_intern(RSTRING_PTR(value_proname)),
|
|
1566
|
+
1, ary);
|
|
1567
|
+
}
|
|
1568
|
+
#else
|
|
1569
|
+
c = rb_funcall(pl_mPLtemp, rb_intern(RSTRING_PTR(value_proname)),
|
|
1570
|
+
1, ary);
|
|
1571
|
+
#endif
|
|
1572
|
+
}
|
|
1573
|
+
else {
|
|
1574
|
+
rb_raise(pl_ePLruby, "context don't accept set");
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
else {
|
|
1578
|
+
#if PG_PL_VERSION >= 75
|
|
1579
|
+
if (prodesc->named_args) {
|
|
1580
|
+
c = rb_funcall2(pl_mPLtemp, rb_intern(RSTRING_PTR(value_proname)),
|
|
1581
|
+
RARRAY_LEN(ary), RARRAY_PTR(ary));
|
|
1582
|
+
}
|
|
1583
|
+
else {
|
|
1584
|
+
c = rb_funcall(pl_mPLtemp, rb_intern(RSTRING_PTR(value_proname)),
|
|
1585
|
+
1, ary);
|
|
1586
|
+
}
|
|
1587
|
+
#else
|
|
1588
|
+
c = rb_funcall(pl_mPLtemp, rb_intern(RSTRING_PTR(value_proname)),
|
|
1589
|
+
1, ary);
|
|
1590
|
+
#endif
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
1594
|
+
{
|
|
1595
|
+
MemoryContext oldcxt;
|
|
1596
|
+
int rc;
|
|
1597
|
+
|
|
1598
|
+
oldcxt = MemoryContextSwitchTo(plruby_spi_context);
|
|
1599
|
+
if ((rc = SPI_finish()) != SPI_OK_FINISH) {
|
|
1600
|
+
elog(ERROR, "SPI_finish() failed : %d", rc);
|
|
1601
|
+
}
|
|
1602
|
+
MemoryContextSwitchTo(oldcxt);
|
|
1603
|
+
}
|
|
1604
|
+
PLRUBY_END_PROTECT;
|
|
1605
|
+
|
|
1606
|
+
if (c == Qnil) {
|
|
1607
|
+
if (expr_multiple) {
|
|
1608
|
+
pl_context_remove();
|
|
1609
|
+
fcinfo->context = NULL;
|
|
1610
|
+
((ReturnSetInfo *)fcinfo->resultinfo)->isDone = ExprEndResult;
|
|
1611
|
+
}
|
|
1612
|
+
PG_RETURN_NULL();
|
|
1613
|
+
}
|
|
1614
|
+
if (fcinfo->resultinfo) {
|
|
1615
|
+
if (fcinfo->flinfo->fn_retset) {
|
|
1616
|
+
((ReturnSetInfo *)fcinfo->resultinfo)->isDone = ExprMultipleResult;
|
|
1617
|
+
return return_base_type(c, prodesc);
|
|
1618
|
+
}
|
|
1619
|
+
if (!prodesc->result_type) {
|
|
1620
|
+
return return_base_type(c, prodesc);
|
|
1621
|
+
}
|
|
1622
|
+
return pl_tuple_datum(c, pl_tuple_s_new(fcinfo, prodesc));
|
|
1623
|
+
}
|
|
1624
|
+
if (prodesc->result_type == 'x') {
|
|
1625
|
+
VALUE res;
|
|
1626
|
+
Datum retval;
|
|
1627
|
+
|
|
1628
|
+
res = rb_funcall2(c, rb_intern("portal_name"), 0, 0);
|
|
1629
|
+
res = plruby_to_s(res);
|
|
1630
|
+
PLRUBY_BEGIN_PROTECT(1);
|
|
1631
|
+
retval = DFC1(textin, CStringGD(RSTRING_PTR(res)));
|
|
1632
|
+
PLRUBY_END_PROTECT;
|
|
1633
|
+
return retval;
|
|
1634
|
+
}
|
|
1635
|
+
#if PG_PL_VERSION >= 81
|
|
1636
|
+
if (prodesc->result_type == 'y') {
|
|
1637
|
+
TupleDesc tupdesc;
|
|
1638
|
+
|
|
1639
|
+
if (get_call_result_type(fcinfo, NULL, &tupdesc) == TYPEFUNC_COMPOSITE) {
|
|
1640
|
+
VALUE tmp;
|
|
1641
|
+
struct pl_tuple *tpl;
|
|
1642
|
+
|
|
1643
|
+
tmp = Data_Make_Struct(rb_cData, struct pl_tuple, pl_thr_mark,
|
|
1644
|
+
free, tpl);
|
|
1645
|
+
GetTuple(tmp, tpl);
|
|
1646
|
+
tpl->pro = prodesc;
|
|
1647
|
+
tpl->dsc = tupdesc;
|
|
1648
|
+
tpl->att = TupleDescGetAttInMetadata(tupdesc);
|
|
1649
|
+
return pl_tuple_datum(c, tmp);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
#endif
|
|
1653
|
+
return return_base_type(c, prodesc);
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
extern void Init_plruby_plan();
|
|
1657
|
+
|
|
1658
|
+
void Init_plruby_pl()
|
|
1659
|
+
{
|
|
1660
|
+
VALUE pl_sPLtemp;
|
|
1661
|
+
|
|
1662
|
+
pl_mPL = rb_define_module("PL");
|
|
1663
|
+
rb_const_set(rb_cObject, rb_intern("PLruby"), pl_mPL);
|
|
1664
|
+
rb_define_const(pl_mPL, "OK", INT2FIX(TG_OK));
|
|
1665
|
+
rb_define_const(pl_mPL, "SKIP", INT2FIX(TG_SKIP));
|
|
1666
|
+
rb_define_const(pl_mPL, "BEFORE", INT2FIX(TG_BEFORE));
|
|
1667
|
+
rb_define_const(pl_mPL, "AFTER", INT2FIX(TG_AFTER));
|
|
1668
|
+
rb_define_const(pl_mPL, "ROW", INT2FIX(TG_ROW));
|
|
1669
|
+
rb_define_const(pl_mPL, "STATEMENT", INT2FIX(TG_STATEMENT));
|
|
1670
|
+
rb_define_const(pl_mPL, "INSERT", INT2FIX(TG_INSERT));
|
|
1671
|
+
rb_define_const(pl_mPL, "DELETE", INT2FIX(TG_DELETE));
|
|
1672
|
+
rb_define_const(pl_mPL, "UPDATE", INT2FIX(TG_UPDATE));
|
|
1673
|
+
rb_define_const(pl_mPL, "UNKNOWN", INT2FIX(TG_UNKNOWN));
|
|
1674
|
+
rb_define_global_function("warn", pl_warn, -1);
|
|
1675
|
+
rb_define_module_function(pl_mPL, "quote", pl_quote, 1);
|
|
1676
|
+
rb_define_module_function(pl_mPL, "spi_exec", pl_SPI_exec, -1);
|
|
1677
|
+
rb_define_module_function(pl_mPL, "exec", pl_SPI_exec, -1);
|
|
1678
|
+
rb_define_module_function(pl_mPL, "column_name", pl_column_name, 1);
|
|
1679
|
+
rb_define_module_function(pl_mPL, "column_type", pl_column_type, 1);
|
|
1680
|
+
rb_define_module_function(pl_mPL, "result_name", pl_query_name, 0);
|
|
1681
|
+
rb_define_module_function(pl_mPL, "result_type", pl_query_type, 0);
|
|
1682
|
+
rb_define_module_function(pl_mPL, "result_size", pl_query_lgth, 0);
|
|
1683
|
+
rb_define_module_function(pl_mPL, "result_description", pl_query_description, 0);
|
|
1684
|
+
rb_define_module_function(pl_mPL, "args_type", pl_args_type, 0);
|
|
1685
|
+
rb_define_module_function(pl_mPL, "context", pl_context_get, 0);
|
|
1686
|
+
rb_define_module_function(pl_mPL, "context=", pl_context_set, 1);
|
|
1687
|
+
pl_ePLruby = rb_define_class_under(pl_mPL, "Error", rb_eStandardError);
|
|
1688
|
+
pl_eCatch = rb_define_class_under(pl_mPL, "Catch", rb_eStandardError);
|
|
1689
|
+
pl_mPLtemp = rb_define_module("PLtemp");
|
|
1690
|
+
pl_sPLtemp = rb_singleton_class(pl_mPLtemp);
|
|
1691
|
+
PLcontext = rb_hash_new();
|
|
1692
|
+
rb_global_variable(&PLcontext);
|
|
1693
|
+
if (MAIN_SAFE_LEVEL >= 3) {
|
|
1694
|
+
rb_obj_taint(pl_mPLtemp);
|
|
1695
|
+
rb_obj_taint(pl_sPLtemp);
|
|
1696
|
+
rb_obj_taint(PLcontext);
|
|
1697
|
+
}
|
|
1698
|
+
id_thr = rb_intern("__functype__");
|
|
1699
|
+
#ifndef HAVE_RB_HASH_DELETE
|
|
1700
|
+
id_delete = rb_intern("delete");
|
|
1701
|
+
#endif
|
|
1702
|
+
#ifdef PLRUBY_ENABLE_CONVERSION
|
|
1703
|
+
id_from_datum = rb_intern("from_datum");
|
|
1704
|
+
id_to_datum = rb_intern("to_datum");
|
|
1705
|
+
#endif
|
|
1706
|
+
Init_plruby_plan();
|
|
1707
|
+
pl_cPLPlan = rb_const_get(pl_mPL, rb_intern("Plan"));
|
|
1708
|
+
}
|