globegit-postgresql-plruby 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. data/Changes +121 -0
  2. data/README.markdown +155 -0
  3. data/Rakefile +48 -0
  4. data/docs/plruby.rb +1931 -0
  5. data/ex_trans.sql +33 -0
  6. data/extconf.rb +267 -0
  7. data/plruby.html +1454 -0
  8. data/plruby.rd +1571 -0
  9. data/postgresql-plruby.gemspec +56 -0
  10. data/src/conversions.h +5 -0
  11. data/src/conversions/basic/conversions.h +25 -0
  12. data/src/conversions/basic/extconf.rb +8 -0
  13. data/src/conversions/basic/plruby_basic.c +357 -0
  14. data/src/conversions/bitstring/bitstring.sql +75 -0
  15. data/src/conversions/bitstring/conversions.h +15 -0
  16. data/src/conversions/bitstring/extconf.rb +8 -0
  17. data/src/conversions/bitstring/plruby_bitstring.c +579 -0
  18. data/src/conversions/convcommon.h +129 -0
  19. data/src/conversions/datetime/conversions.h +13 -0
  20. data/src/conversions/datetime/extconf.rb +8 -0
  21. data/src/conversions/datetime/plruby_datetime.c +269 -0
  22. data/src/conversions/geometry/conversions.h +37 -0
  23. data/src/conversions/geometry/extconf.rb +8 -0
  24. data/src/conversions/geometry/geometry.sql +196 -0
  25. data/src/conversions/geometry/plruby_geometry.c +2494 -0
  26. data/src/conversions/network/conversions.h +21 -0
  27. data/src/conversions/network/extconf.rb +8 -0
  28. data/src/conversions/network/network.sql +63 -0
  29. data/src/conversions/network/plruby_network.c +537 -0
  30. data/src/package.h +20 -0
  31. data/src/plpl.c +1708 -0
  32. data/src/plplan.c +893 -0
  33. data/src/plruby.c +1676 -0
  34. data/src/plruby.h +324 -0
  35. data/src/pltrans.c +388 -0
  36. data/test/conv_bitstring/b.rb +45 -0
  37. data/test/conv_bitstring/runtest +26 -0
  38. data/test/conv_bitstring/test.expected.73 +148 -0
  39. data/test/conv_bitstring/test.expected.74 +148 -0
  40. data/test/conv_bitstring/test.expected.80 +148 -0
  41. data/test/conv_bitstring/test.expected.81 +148 -0
  42. data/test/conv_bitstring/test.expected.82 +148 -0
  43. data/test/conv_bitstring/test.expected.83 +148 -0
  44. data/test/conv_bitstring/test.expected.84 +148 -0
  45. data/test/conv_bitstring/test.out +148 -0
  46. data/test/conv_bitstring/test_mklang.sql +8 -0
  47. data/test/conv_bitstring/test_queries.sql +63 -0
  48. data/test/conv_bitstring/test_queries.sql.in +63 -0
  49. data/test/conv_geometry/b.rb +45 -0
  50. data/test/conv_geometry/runtest +26 -0
  51. data/test/conv_geometry/test.expected.73 +265 -0
  52. data/test/conv_geometry/test.expected.74 +265 -0
  53. data/test/conv_geometry/test.expected.80 +265 -0
  54. data/test/conv_geometry/test.expected.81 +265 -0
  55. data/test/conv_geometry/test.expected.82 +265 -0
  56. data/test/conv_geometry/test.expected.83 +265 -0
  57. data/test/conv_geometry/test.expected.84 +265 -0
  58. data/test/conv_geometry/test.out +265 -0
  59. data/test/conv_geometry/test_mklang.sql +8 -0
  60. data/test/conv_geometry/test_queries.sql +194 -0
  61. data/test/conv_geometry/test_queries.sql.in +194 -0
  62. data/test/conv_network/b.rb +45 -0
  63. data/test/conv_network/runtest +26 -0
  64. data/test/conv_network/test.expected.73 +213 -0
  65. data/test/conv_network/test.expected.74 +237 -0
  66. data/test/conv_network/test.expected.80 +237 -0
  67. data/test/conv_network/test.expected.81 +237 -0
  68. data/test/conv_network/test.expected.82 +237 -0
  69. data/test/conv_network/test.expected.83 +237 -0
  70. data/test/conv_network/test.expected.84 +237 -0
  71. data/test/conv_network/test.out +237 -0
  72. data/test/conv_network/test_mklang.sql +8 -0
  73. data/test/conv_network/test_queries.sql +60 -0
  74. data/test/conv_network/test_queries.sql.in +60 -0
  75. data/test/plp/b.rb +34 -0
  76. data/test/plp/runtest +29 -0
  77. data/test/plp/test.expected.73 +472 -0
  78. data/test/plp/test.expected.74 +472 -0
  79. data/test/plp/test.expected.75 +472 -0
  80. data/test/plp/test.expected.80 +472 -0
  81. data/test/plp/test.expected.81 +472 -0
  82. data/test/plp/test.expected.82 +472 -0
  83. data/test/plp/test.expected.83 +472 -0
  84. data/test/plp/test.expected.84 +472 -0
  85. data/test/plp/test.out +472 -0
  86. data/test/plp/test_mklang.sql +8 -0
  87. data/test/plp/test_queries.sql +273 -0
  88. data/test/plp/test_setup.sql +931 -0
  89. data/test/plp/test_setup.sql.in +931 -0
  90. data/test/plt/b.rb +34 -0
  91. data/test/plt/runtest +29 -0
  92. data/test/plt/test.expected.73 +178 -0
  93. data/test/plt/test.expected.74 +178 -0
  94. data/test/plt/test.expected.75 +178 -0
  95. data/test/plt/test.expected.80 +178 -0
  96. data/test/plt/test.expected.81 +178 -0
  97. data/test/plt/test.expected.82 +178 -0
  98. data/test/plt/test.expected.83 +164 -0
  99. data/test/plt/test.expected.84 +168 -0
  100. data/test/plt/test.out +168 -0
  101. data/test/plt/test_mklang.sql +8 -0
  102. data/test/plt/test_queries.sql +72 -0
  103. data/test/plt/test_setup.sql +252 -0
  104. data/test/plt/test_setup.sql.in +252 -0
  105. data/test/range/b.rb +45 -0
  106. data/test/range/runtest +26 -0
  107. data/test/range/test.expected.73 +396 -0
  108. data/test/range/test.expected.73.in +396 -0
  109. data/test/range/test.expected.74 +396 -0
  110. data/test/range/test.expected.74.in +396 -0
  111. data/test/range/test.expected.75 +396 -0
  112. data/test/range/test.expected.75.in +396 -0
  113. data/test/range/test.expected.80 +396 -0
  114. data/test/range/test.expected.81 +397 -0
  115. data/test/range/test.expected.82 +397 -0
  116. data/test/range/test.expected.83 +397 -0
  117. data/test/range/test.expected.84 +399 -0
  118. data/test/range/test.out +399 -0
  119. data/test/range/test_mklang.sql +8 -0
  120. data/test/range/test_queries.sql +249 -0
  121. data/test/range/test_queries.sql.in +249 -0
  122. metadata +207 -0
@@ -0,0 +1,324 @@
1
+ #include <unistd.h>
2
+ #include <fcntl.h>
3
+ #include <setjmp.h>
4
+
5
+ #include "postgres.h"
6
+ #include "executor/spi.h"
7
+ #include "executor/executor.h"
8
+ #include "commands/trigger.h"
9
+ #include "utils/elog.h"
10
+ #include "utils/builtins.h"
11
+ #include "fmgr.h"
12
+ #include "access/heapam.h"
13
+
14
+ #include "tcop/tcopprot.h"
15
+ #include "utils/syscache.h"
16
+ #include "catalog/pg_proc.h"
17
+ #include "catalog/pg_language.h"
18
+ #include "catalog/pg_type.h"
19
+
20
+ #include "nodes/makefuncs.h"
21
+ #include "nodes/nodes.h"
22
+ #include "parser/parse_type.h"
23
+ #include "utils/lsyscache.h"
24
+ #include "funcapi.h"
25
+
26
+ #include "utils/array.h"
27
+
28
+ #if PG_PL_VERSION >= 75
29
+ #include "nodes/pg_list.h"
30
+ #include "utils/typcache.h"
31
+ #include "access/xact.h"
32
+ #endif
33
+
34
+ #if PG_PL_VERSION >= 81
35
+ #include "utils/memutils.h"
36
+ #endif
37
+
38
+ #include "package.h"
39
+
40
+ #include <ruby.h>
41
+ #if HAVE_RUBY_ST_H
42
+ #include <ruby/st.h>
43
+ #elif HAVE_ST_H
44
+ #include <st.h>
45
+ #endif
46
+
47
+ #ifndef StringValuePtr
48
+ #define StringValuePtr(x) STR2CSTR(x)
49
+ #endif
50
+
51
+ #ifndef RSTRING_PTR
52
+ # define RSTRING_PTR(x_) RSTRING(x_)->ptr
53
+ # define RSTRING_LEN(x_) RSTRING(x_)->len
54
+ #endif
55
+
56
+ #ifndef RARRAY_PTR
57
+ # define RARRAY_PTR(x_) RARRAY(x_)->ptr
58
+ # define RARRAY_LEN(x_) RARRAY(x_)->len
59
+ #endif
60
+
61
+ #ifndef RHASH_TBL
62
+ #define RHASH_TBL(x_) (RHASH(x_)->tbl)
63
+ #endif
64
+
65
+ #ifndef RFLOAT_VALUE
66
+ #define RFLOAT_VALUE(x_) (RFLOAT(x_)->value)
67
+ #endif
68
+
69
+ extern VALUE rb_thread_list();
70
+
71
+ #ifndef SAFE_LEVEL
72
+ #define SAFE_LEVEL 12
73
+ #endif
74
+
75
+ #ifndef MAIN_SAFE_LEVEL
76
+ #ifdef PLRUBY_TIMEOUT
77
+ #define MAIN_SAFE_LEVEL 3
78
+ #else
79
+ #define MAIN_SAFE_LEVEL SAFE_LEVEL
80
+ #endif
81
+ #endif
82
+
83
+ #if SAFE_LEVEL <= MAIN_SAFE_LEVEL
84
+ #define MAIN_SAFE_LEVEL SAFE_LEVEL
85
+ #endif
86
+
87
+ #ifdef PLRUBY_TIMEOUT
88
+
89
+ extern int plruby_in_progress;
90
+ extern int plruby_interrupted;
91
+
92
+ #define PLRUBY_BEGIN(lvl_) do { \
93
+ int in_progress = plruby_in_progress; \
94
+ if (plruby_interrupted) { \
95
+ rb_raise(pl_ePLruby, "timeout"); \
96
+ } \
97
+ plruby_in_progress = lvl_;
98
+
99
+ #define PLRUBY_END \
100
+ plruby_in_progress = in_progress; \
101
+ if (plruby_interrupted) { \
102
+ rb_raise(pl_ePLruby, "timeout"); \
103
+ } \
104
+ } while (0)
105
+
106
+ #ifdef PG_PL_TRYCATCH
107
+
108
+ #define PLRUBY_BEGIN_PROTECT(lvl_) do { \
109
+ int in_progress = plruby_in_progress; \
110
+ if (plruby_interrupted) { \
111
+ rb_raise(pl_ePLruby, "timeout"); \
112
+ } \
113
+ plruby_in_progress = lvl_; \
114
+ PG_TRY(); \
115
+ {
116
+
117
+ extern int errorcode;
118
+
119
+ #define PLRUBY_END_PROTECT \
120
+ } \
121
+ PG_CATCH(); \
122
+ { \
123
+ plruby_in_progress = in_progress; \
124
+ rb_raise(pl_eCatch, "propagate"); \
125
+ } \
126
+ PG_END_TRY(); \
127
+ plruby_in_progress = in_progress; \
128
+ if (plruby_interrupted) { \
129
+ rb_raise(pl_ePLruby, "timeout"); \
130
+ } \
131
+ } while (0)
132
+
133
+ #else
134
+
135
+ #define PLRUBY_BEGIN_PROTECT(lvl_) do { \
136
+ sigjmp_buf save_restart; \
137
+ int in_progress = plruby_in_progress; \
138
+ if (plruby_interrupted) { \
139
+ rb_raise(pl_ePLruby, "timeout"); \
140
+ } \
141
+ memcpy(&save_restart, &Warn_restart, sizeof(save_restart)); \
142
+ if (sigsetjmp(Warn_restart, 1) != 0) { \
143
+ plruby_in_progress = in_progress; \
144
+ memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); \
145
+ rb_raise(pl_eCatch, "propagate"); \
146
+ } \
147
+ plruby_in_progress = lvl_;
148
+
149
+ #define PLRUBY_END_PROTECT \
150
+ plruby_in_progress = in_progress; \
151
+ memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); \
152
+ if (plruby_interrupted) { \
153
+ rb_raise(pl_ePLruby, "timeout"); \
154
+ } \
155
+ } while (0)
156
+
157
+ #endif
158
+
159
+ #else
160
+
161
+ #define PLRUBY_BEGIN(lvl_)
162
+ #define PLRUBY_END
163
+
164
+ #ifdef PG_PL_TRYCATCH
165
+
166
+ #define PLRUBY_BEGIN_PROTECT(lvl_) do { \
167
+ PG_TRY(); \
168
+ {
169
+
170
+ #define PLRUBY_END_PROTECT \
171
+ } \
172
+ PG_CATCH(); \
173
+ { \
174
+ rb_raise(pl_eCatch, "propagate"); \
175
+ } \
176
+ PG_END_TRY(); \
177
+ } while (0)
178
+
179
+ #else
180
+
181
+ #define PLRUBY_BEGIN_PROTECT(lvl_) do { \
182
+ sigjmp_buf save_restart; \
183
+ memcpy(&save_restart, &Warn_restart, sizeof(save_restart)); \
184
+ if (sigsetjmp(Warn_restart, 1) != 0) { \
185
+ memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); \
186
+ rb_raise(pl_eCatch, "propagate"); \
187
+ }
188
+
189
+ #define PLRUBY_END_PROTECT \
190
+ memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); \
191
+ } while (0)
192
+
193
+ #endif
194
+
195
+ #endif
196
+
197
+
198
+
199
+ enum { TG_OK, TG_SKIP };
200
+ enum { TG_BEFORE, TG_AFTER, TG_ROW, TG_STATEMENT, TG_INSERT,
201
+ TG_DELETE, TG_UPDATE, TG_UNKNOWN };
202
+
203
+ struct pl_thread_st {
204
+ PG_FUNCTION_ARGS;
205
+ int timeout;
206
+ Oid validator;
207
+ };
208
+
209
+ typedef struct pl_proc_desc
210
+ {
211
+ char *proname;
212
+ TransactionId fn_xmin;
213
+ CommandId fn_cmin;
214
+ FmgrInfo result_func;
215
+ Oid result_elem;
216
+ Oid result_oid;
217
+ int result_len;
218
+ bool result_is_array;
219
+ bool result_val;
220
+ bool result_is_setof;
221
+ char result_align;
222
+ int nargs;
223
+ #if PG_PL_VERSION >= 75
224
+ int named_args;
225
+ #endif
226
+ FmgrInfo arg_func[FUNC_MAX_ARGS];
227
+ Oid arg_elem[FUNC_MAX_ARGS];
228
+ Oid arg_type[FUNC_MAX_ARGS];
229
+ int arg_len[FUNC_MAX_ARGS];
230
+ bool arg_is_array[FUNC_MAX_ARGS];
231
+ bool arg_val[FUNC_MAX_ARGS];
232
+ char arg_align[FUNC_MAX_ARGS];
233
+ int arg_is_rel[FUNC_MAX_ARGS];
234
+ char result_type;
235
+ } pl_proc_desc;
236
+
237
+ struct portal_options {
238
+ VALUE argsv;
239
+ int count, output;
240
+ int block, save;
241
+ };
242
+
243
+ typedef struct pl_query_desc
244
+ {
245
+ char qname[20];
246
+ void *plan;
247
+ int nargs;
248
+ Oid *argtypes;
249
+ FmgrInfo *arginfuncs;
250
+ Oid *argtypelems;
251
+ int *arglen;
252
+ bool *arg_is_array;
253
+ bool *arg_val;
254
+ char *arg_align;
255
+ int cursor;
256
+ struct portal_options po;
257
+ } pl_query_desc;
258
+
259
+ struct PLportal {
260
+ Portal portal;
261
+ char *nulls;
262
+ Datum *argvalues;
263
+ int *arglen;
264
+ int nargs;
265
+ struct portal_options po;
266
+ };
267
+
268
+ #define GetPortal(obj, portal) do { \
269
+ Data_Get_Struct(obj, struct PLportal, portal); \
270
+ if (!portal->portal) { \
271
+ rb_raise(pl_ePLruby, "cursor closed"); \
272
+ } \
273
+ } while (0)
274
+
275
+ #define GetPlan(obj, qdesc) do { \
276
+ Data_Get_Struct(obj, pl_query_desc, qdesc); \
277
+ if (!qdesc->plan) { \
278
+ rb_raise(pl_ePLruby, "plan was dropped during the session"); \
279
+ } \
280
+ } while (0)
281
+
282
+ #define RET_HASH 1
283
+ #define RET_ARRAY 2
284
+ #define RET_DESC 4
285
+ #define RET_DESC_ARR 12
286
+ #define RET_BASIC 16
287
+
288
+ extern VALUE plruby_s_new _((int, VALUE *, VALUE));
289
+ extern VALUE plruby_build_tuple _((HeapTuple, TupleDesc, int));
290
+ extern Datum plruby_to_datum _((VALUE, FmgrInfo *, Oid, Oid, int));
291
+ extern Datum plruby_return_value _((struct pl_thread_st *, pl_proc_desc *,
292
+ VALUE, VALUE));
293
+ extern VALUE plruby_create_args _((struct pl_thread_st *, pl_proc_desc *));
294
+ extern VALUE plruby_i_each _((VALUE, struct portal_options *));
295
+ extern void plruby_exec_output _((VALUE, int, int *));
296
+ extern VALUE plruby_to_s _((VALUE));
297
+
298
+ extern Datum plruby_return_array _((VALUE, pl_proc_desc *));
299
+ extern MemoryContext plruby_spi_context;
300
+
301
+ extern Datum plruby_dfc0 _((PGFunction));
302
+ extern Datum plruby_dfc1 _((PGFunction, Datum));
303
+ extern Datum plruby_dfc2 _((PGFunction, Datum, Datum));
304
+ extern Datum plruby_dfc3 _((PGFunction, Datum, Datum, Datum));
305
+
306
+ #ifdef PLRUBY_ENABLE_CONVERSION
307
+ extern VALUE plruby_classes, plruby_conversions;
308
+ extern Oid plruby_datum_oid _((VALUE, int *));
309
+ extern VALUE plruby_datum_set _((VALUE, Datum));
310
+ extern Datum plruby_datum_get _((VALUE, Oid *));
311
+ extern VALUE plruby_define_void_class _((char *, char *));
312
+ #endif
313
+
314
+ #define DFC1(a_, b_) DirectFunctionCall1((a_), (b_))
315
+
316
+ #define OidGD(a_) ObjectIdGetDatum(a_)
317
+ #define PointerGD(a_) PointerGetDatum(a_)
318
+ #define NameGD(a_) NameGetDatum(a_)
319
+ #define BoolGD(a_) BoolGetDatum(a_)
320
+ #define IntGD(a_) Int32GetDatum(a_)
321
+ #define CStringGD(a_) CStringGetDatum(a_)
322
+ #define TupleGD(a_,b_) TupleGetDatum((a_),(b_))
323
+
324
+
@@ -0,0 +1,388 @@
1
+ #include "plruby.h"
2
+
3
+ #if PG_PL_VERSION >= 75
4
+
5
+ #define PG_PL_READ_UNCOMMITTED 0
6
+ #define PG_PL_READ_COMMITTED 1
7
+ #define PG_PL_REPETABLE_READ 2
8
+ #define PG_PL_SERIALIZABLE 3
9
+
10
+ #define PL_ELOG_DEBUG 0
11
+
12
+ #if PL_ELOG_DEBUG
13
+ #define pl_elog(a,b) elog(a,b)
14
+ #else
15
+ #define pl_elog(a,b)
16
+ #endif
17
+
18
+ static int pl_in_transaction = 0;
19
+ static VALUE pl_eCatch, pl_ePLruby, pl_cTrans;
20
+
21
+ struct pl_trans {
22
+ VALUE name;
23
+ int commit;
24
+ };
25
+
26
+ static void
27
+ pl_trans_mark(void *trans)
28
+ {
29
+ }
30
+
31
+ #define GetTrans(obj_, trans_) do { \
32
+ if (TYPE(obj_) != T_DATA || \
33
+ RDATA(obj_)->dmark != (RUBY_DATA_FUNC)pl_trans_mark) { \
34
+ rb_raise(rb_eArgError, \
35
+ "transaction method called with a wrong object"); \
36
+ } \
37
+ Data_Get_Struct(obj_, struct pl_trans, trans_); \
38
+ } while (0)
39
+
40
+ static char *savename = "savepoint_name";
41
+
42
+ static DefElem *
43
+ make_defelem(char *name, VALUE arg)
44
+ {
45
+ DefElem *f = makeNode(DefElem);
46
+ f->defname = name;
47
+ f->arg = (Node *)makeString(RSTRING_PTR(arg));
48
+ return f;
49
+ }
50
+
51
+
52
+ static VALUE
53
+ pl_intern_commit(VALUE obj)
54
+ {
55
+ struct pl_trans *trans;
56
+ int rc;
57
+
58
+ pl_elog(NOTICE, "==> pl_intern_commit");
59
+ GetTrans(obj, trans);
60
+ PLRUBY_BEGIN_PROTECT(1);
61
+ if (NIL_P(trans->name)) {
62
+ if (!trans->commit) {
63
+ pl_elog(NOTICE, "ReleaseCurrentSubTransaction");
64
+ trans->commit = Qtrue;
65
+ if ((rc = SPI_finish()) != SPI_OK_FINISH) {
66
+ elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
67
+ }
68
+ ReleaseCurrentSubTransaction();
69
+ }
70
+ }
71
+ else {
72
+ List *list;
73
+
74
+ pl_elog(NOTICE, "ReleaseSavepoint");
75
+ list = list_make1(make_defelem(savename, trans->name));
76
+ trans->name = Qnil;
77
+ trans->commit = Qtrue;
78
+ ReleaseSavepoint(list);
79
+ CommitTransactionCommand();
80
+ StartTransactionCommand();
81
+ }
82
+ PLRUBY_END_PROTECT;
83
+ pl_elog(NOTICE, "<== pl_intern_commit");
84
+ return Qnil;
85
+ }
86
+
87
+ struct pl_throw {
88
+ VALUE txn;
89
+ int commit;
90
+ };
91
+
92
+ static void
93
+ pl_throw_mark(struct pl_throw *plt)
94
+ {
95
+ rb_gc_mark(plt->txn);
96
+ }
97
+
98
+ static VALUE
99
+ pl_commit(VALUE obj)
100
+ {
101
+ VALUE res;
102
+ struct pl_throw *plt;
103
+
104
+ pl_elog(NOTICE, "pl_commit");
105
+ if (!IsSubTransaction()) {
106
+ rb_raise(pl_ePLruby, "outside a transaction");
107
+ }
108
+ res = Data_Make_Struct(pl_cTrans, struct pl_throw, pl_throw_mark, free, plt);
109
+ plt->commit = Qtrue;
110
+ plt->txn = obj;
111
+ rb_throw("__plruby__transaction__", res);
112
+ return Qnil;
113
+ }
114
+
115
+ static VALUE
116
+ pl_intern_abort(VALUE obj)
117
+ {
118
+ struct pl_trans *trans;
119
+ int rc;
120
+
121
+ pl_elog(NOTICE, "==> pl_intern_abort");
122
+ if (!IsSubTransaction()) {
123
+ rb_raise(pl_ePLruby, "outside a transaction");
124
+ }
125
+ GetTrans(obj, trans);
126
+ PLRUBY_BEGIN_PROTECT(1);
127
+ if (NIL_P(trans->name)) {
128
+ if (!trans->commit) {
129
+ pl_elog(NOTICE, "RollbackAndReleaseCurrentSubTransaction");
130
+ trans->commit = Qtrue;
131
+ if ((rc = SPI_finish()) != SPI_OK_FINISH) {
132
+ elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
133
+ }
134
+ RollbackAndReleaseCurrentSubTransaction();
135
+ }
136
+ }
137
+ else {
138
+ List *list;
139
+
140
+ pl_elog(NOTICE, "RollbackToSavepoint");
141
+ list = list_make1(make_defelem(savename, trans->name));
142
+ trans->name = Qnil;
143
+ trans->commit = Qtrue;
144
+ RollbackToSavepoint(list);
145
+ CommitTransactionCommand();
146
+ RollbackAndReleaseCurrentSubTransaction();
147
+ }
148
+ PLRUBY_END_PROTECT;
149
+ pl_elog(NOTICE, "<== pl_intern_abort");
150
+ return Qnil;
151
+ }
152
+
153
+ static VALUE
154
+ pl_intern_error(VALUE obj)
155
+ {
156
+ struct pl_trans *trans;
157
+
158
+ pl_elog(NOTICE, "==> pl_intern_error");
159
+ if (!IsSubTransaction()) {
160
+ rb_raise(pl_ePLruby, "outside a transaction");
161
+ }
162
+ GetTrans(obj, trans);
163
+ PLRUBY_BEGIN_PROTECT(1);
164
+ pl_elog(NOTICE, "RollbackAndReleaseCurrentSubTransaction");
165
+ trans->commit = Qtrue;
166
+ RollbackAndReleaseCurrentSubTransaction();
167
+ PLRUBY_END_PROTECT;
168
+ pl_elog(NOTICE, "<== pl_intern_error");
169
+ return Qnil;
170
+ }
171
+
172
+ static VALUE
173
+ pl_abort(VALUE obj)
174
+ {
175
+ VALUE res;
176
+ struct pl_throw *plt;
177
+
178
+ pl_elog(NOTICE, "pl_abort");
179
+ if (!IsSubTransaction()) {
180
+ rb_raise(pl_ePLruby, "outside a transaction");
181
+ }
182
+ res = Data_Make_Struct(pl_cTrans, struct pl_throw, pl_throw_mark, free, plt);
183
+ plt->commit = Qfalse;
184
+ plt->txn = obj;
185
+ rb_throw("__plruby__transaction__", res);
186
+ return Qnil;
187
+ }
188
+
189
+ static VALUE
190
+ pl_exec(VALUE val, VALUE args, VALUE self)
191
+ {
192
+ rb_yield(args);
193
+ return Qnil;
194
+ }
195
+
196
+ static VALUE
197
+ pl_catch(VALUE obj)
198
+ {
199
+ VALUE res;
200
+ struct pl_throw *plt;
201
+
202
+ pl_elog(NOTICE, "pl_catch");
203
+ res = rb_catch("__plruby__transaction__", pl_exec, obj);
204
+ if (TYPE(res) == T_DATA &&
205
+ RDATA(res)->dmark == (RUBY_DATA_FUNC)pl_throw_mark) {
206
+ Data_Get_Struct(res, struct pl_throw, plt);
207
+ if (plt->commit) {
208
+ pl_intern_commit(obj);
209
+ }
210
+ else {
211
+ pl_intern_abort(obj);
212
+ }
213
+ if (obj != plt->txn) {
214
+ rb_throw("__plruby__transaction__", res);
215
+ }
216
+ }
217
+ else {
218
+ pl_intern_commit(obj);
219
+ }
220
+ return Qnil;
221
+ }
222
+
223
+
224
+ static VALUE
225
+ pl_transaction(VALUE obj)
226
+ {
227
+ struct pl_trans *trans;
228
+ VALUE res;
229
+ int state, rc, begin_sub;
230
+ MemoryContext orig_context = 0;
231
+
232
+
233
+ pl_elog(NOTICE, "==> pl_transaction");
234
+ if (!rb_block_given_p()) {
235
+ rb_raise(rb_eArgError, "no block given");
236
+ }
237
+ res = Data_Make_Struct(pl_cTrans, struct pl_trans, pl_trans_mark, 0, trans);
238
+ trans->name = Qnil;
239
+ PLRUBY_BEGIN_PROTECT(1);
240
+ if (IsSubTransaction()) {
241
+ char name[1024];
242
+
243
+ pl_elog(NOTICE, "DefineSavepoint");
244
+ sprintf(name, "__plruby__%d__", pl_in_transaction);
245
+ DefineSavepoint(name);
246
+ CommitTransactionCommand();
247
+ StartTransactionCommand();
248
+ pl_in_transaction++;
249
+ begin_sub = Qfalse;
250
+ trans->name = rb_str_new2(name);
251
+ }
252
+ else {
253
+ pl_in_transaction = 0;
254
+ pl_elog(NOTICE, "BeginTransactionBlock");
255
+ orig_context = CurrentMemoryContext;
256
+ SPI_push();
257
+ BeginInternalSubTransaction(NULL);
258
+ MemoryContextSwitchTo(orig_context);
259
+ if ((rc = SPI_connect()) != SPI_OK_CONNECT) {
260
+ elog(ERROR, "SPI_connect in transaction failed : %s",
261
+ SPI_result_code_string(rc));
262
+ }
263
+ begin_sub = Qtrue;
264
+ }
265
+ PLRUBY_END_PROTECT;
266
+ pl_elog(NOTICE, "==> rb_protect");
267
+ rb_protect(pl_catch, res, &state);
268
+ pl_elog(NOTICE, "<== rb_protect");
269
+ if (state) {
270
+ VALUE error = rb_gv_get("$!");
271
+ if (begin_sub && CLASS_OF(error) == pl_eCatch) {
272
+ if (!trans->commit) {
273
+ rb_protect(pl_intern_error, res, 0);
274
+ }
275
+ }
276
+ else {
277
+ if (!trans->commit) {
278
+ rb_protect(pl_intern_abort, res, 0);
279
+ }
280
+ if (begin_sub) {
281
+ MemoryContextSwitchTo(orig_context);
282
+ SPI_pop();
283
+ }
284
+ }
285
+ rb_jump_tag(state);
286
+ }
287
+ Data_Get_Struct(res, struct pl_trans, trans);
288
+ if (begin_sub) {
289
+ pl_elog(NOTICE, "commit");
290
+ if (!trans->commit) {
291
+ rb_protect(pl_intern_commit, res, 0);
292
+ }
293
+ MemoryContextSwitchTo(orig_context);
294
+ SPI_pop();
295
+ }
296
+ pl_elog(NOTICE, "<== pl_transaction");
297
+ return Qnil;
298
+ }
299
+
300
+ #endif
301
+
302
+ #if PG_PL_VERSION >= 81
303
+
304
+ static VALUE
305
+ pl_savepoint(VALUE obj, VALUE a)
306
+ {
307
+ if (!IsTransactionBlock() || !IsSubTransaction()) {
308
+ rb_raise(pl_ePLruby, "savepoint called outside a transaction");
309
+ }
310
+ a = plruby_to_s(a);
311
+ pl_elog(NOTICE, "====> definesavepoint");
312
+ PLRUBY_BEGIN_PROTECT(1);
313
+ DefineSavepoint(RSTRING_PTR(a));
314
+ CommitTransactionCommand();
315
+ StartTransactionCommand();
316
+ PLRUBY_END_PROTECT;
317
+ pl_elog(NOTICE, "<==== definesavepoint");
318
+ return Qnil;
319
+ }
320
+
321
+ static VALUE
322
+ pl_release(VALUE obj, VALUE a)
323
+ {
324
+ if (!IsTransactionBlock() || !IsSubTransaction()) {
325
+ rb_raise(pl_ePLruby, "release called outside a transaction");
326
+ }
327
+ a = plruby_to_s(a);
328
+ pl_elog(NOTICE, "====> releasesavepoint");
329
+ PLRUBY_BEGIN_PROTECT(1);
330
+ ReleaseSavepoint(list_make1(make_defelem("savepoint_name", a)));
331
+ CommitTransactionCommand();
332
+ StartTransactionCommand();
333
+ PLRUBY_END_PROTECT;
334
+ pl_elog(NOTICE, "<==== releasesavepoint");
335
+ return Qnil;
336
+ }
337
+
338
+ static VALUE
339
+ pl_rollback(VALUE obj, VALUE a)
340
+ {
341
+ if (!IsTransactionBlock() || !IsSubTransaction()) {
342
+ rb_raise(pl_ePLruby, "rollback called outside a transaction");
343
+ }
344
+ a = plruby_to_s(a);
345
+ pl_elog(NOTICE, "====> rollbacksavepoint");
346
+ PLRUBY_BEGIN_PROTECT(1);
347
+ RollbackToSavepoint(list_make1(make_defelem("savepoint_name", a)));
348
+ CommitTransactionCommand();
349
+ RollbackAndReleaseCurrentSubTransaction();
350
+ PLRUBY_END_PROTECT;
351
+ pl_elog(NOTICE, "<==== rollbacksavepoint");
352
+ return Qnil;
353
+ }
354
+
355
+ #endif
356
+
357
+ void
358
+ Init_plruby_trans()
359
+ {
360
+ #if PG_PL_VERSION >= 75
361
+ VALUE pl_mPL;
362
+
363
+ pl_mPL = rb_const_get(rb_cObject, rb_intern("PL"));
364
+ pl_ePLruby = rb_const_get(pl_mPL, rb_intern("Error"));
365
+ pl_eCatch = rb_const_get(pl_mPL, rb_intern("Catch"));
366
+
367
+ rb_define_global_const("READ_UNCOMMITED", INT2FIX(PG_PL_READ_UNCOMMITTED));
368
+ rb_define_global_const("READ_COMMITED", INT2FIX(PG_PL_READ_COMMITTED));
369
+ rb_define_global_const("REPETABLE_READ", INT2FIX(PG_PL_REPETABLE_READ));
370
+ rb_define_global_const("SERIALIZABLE", INT2FIX(PG_PL_SERIALIZABLE));
371
+ rb_define_global_function("transaction", pl_transaction, 0);
372
+ #if PG_PL_VERSION >= 81
373
+ rb_define_global_function("savepoint", pl_savepoint, 1);
374
+ rb_define_global_function("release_savepoint", pl_release, 1);
375
+ rb_define_global_function("rollback_to_savepoint", pl_rollback, 1);
376
+ #endif
377
+ pl_cTrans = rb_define_class_under(pl_mPL, "Transaction", rb_cObject);
378
+ #if HAVE_RB_DEFINE_ALLOC_FUNC
379
+ rb_undef_alloc_func(pl_cTrans);
380
+ #else
381
+ rb_undef_method(CLASS_OF(pl_cTrans), "allocate");
382
+ #endif
383
+ rb_undef_method(CLASS_OF(pl_cTrans), "new");
384
+ rb_define_method(pl_cTrans, "commit", pl_commit, 0);
385
+ rb_define_method(pl_cTrans, "abort", pl_abort, 0);
386
+ rb_define_method(pl_cTrans, "rollback", pl_abort, 0);
387
+ #endif
388
+ }