ruby-staci 2.2.9

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +14 -0
  3. data/COPYING +30 -0
  4. data/COPYING_old +64 -0
  5. data/ChangeLog +3826 -0
  6. data/Makefile +92 -0
  7. data/NEWS +1194 -0
  8. data/README.md +66 -0
  9. data/dist-files +113 -0
  10. data/docs/bind-array-to-in_cond.md +38 -0
  11. data/docs/conflicts-local-connections-and-processes.md +98 -0
  12. data/docs/hanging-after-inactivity.md +63 -0
  13. data/docs/install-binary-package.md +44 -0
  14. data/docs/install-full-client.md +111 -0
  15. data/docs/install-instant-client.md +194 -0
  16. data/docs/install-on-osx.md +133 -0
  17. data/docs/ldap-auth-and-function-interposition.md +123 -0
  18. data/docs/number-type-mapping.md +79 -0
  19. data/docs/osx-install-dev-tools.png +0 -0
  20. data/docs/platform-specific-issues.md +164 -0
  21. data/docs/report-installation-issue.md +50 -0
  22. data/docs/timeout-parameters.md +94 -0
  23. data/ext/oci8/.document +18 -0
  24. data/ext/oci8/MANIFEST +18 -0
  25. data/ext/oci8/apiwrap.c.tmpl +178 -0
  26. data/ext/oci8/apiwrap.h.tmpl +61 -0
  27. data/ext/oci8/apiwrap.rb +96 -0
  28. data/ext/oci8/apiwrap.yml +1322 -0
  29. data/ext/oci8/attr.c +57 -0
  30. data/ext/oci8/bind.c +838 -0
  31. data/ext/oci8/connection_pool.c +216 -0
  32. data/ext/oci8/encoding.c +196 -0
  33. data/ext/oci8/env.c +139 -0
  34. data/ext/oci8/error.c +385 -0
  35. data/ext/oci8/extconf.rb +219 -0
  36. data/ext/oci8/hook_funcs.c +407 -0
  37. data/ext/oci8/lob.c +1278 -0
  38. data/ext/oci8/metadata.c +279 -0
  39. data/ext/oci8/object.c +919 -0
  40. data/ext/oci8/oci8.c +1058 -0
  41. data/ext/oci8/oci8.h +556 -0
  42. data/ext/oci8/oci8lib.c +704 -0
  43. data/ext/oci8/ocidatetime.c +506 -0
  44. data/ext/oci8/ocihandle.c +852 -0
  45. data/ext/oci8/ocinumber.c +1922 -0
  46. data/ext/oci8/oraconf.rb +1145 -0
  47. data/ext/oci8/oradate.c +670 -0
  48. data/ext/oci8/oranumber_util.c +352 -0
  49. data/ext/oci8/oranumber_util.h +24 -0
  50. data/ext/oci8/plthook.h +66 -0
  51. data/ext/oci8/plthook_elf.c +702 -0
  52. data/ext/oci8/plthook_osx.c +505 -0
  53. data/ext/oci8/plthook_win32.c +391 -0
  54. data/ext/oci8/post-config.rb +5 -0
  55. data/ext/oci8/stmt.c +448 -0
  56. data/ext/oci8/thread_util.c +81 -0
  57. data/ext/oci8/thread_util.h +18 -0
  58. data/ext/oci8/util.c +71 -0
  59. data/ext/oci8/win32.c +117 -0
  60. data/lib/.document +1 -0
  61. data/lib/dbd/STACI.rb +591 -0
  62. data/lib/oci8/.document +8 -0
  63. data/lib/oci8/bindtype.rb +333 -0
  64. data/lib/oci8/check_load_error.rb +146 -0
  65. data/lib/oci8/compat.rb +117 -0
  66. data/lib/oci8/connection_pool.rb +179 -0
  67. data/lib/oci8/cursor.rb +605 -0
  68. data/lib/oci8/datetime.rb +605 -0
  69. data/lib/oci8/encoding-init.rb +45 -0
  70. data/lib/oci8/encoding.yml +537 -0
  71. data/lib/oci8/metadata.rb +2148 -0
  72. data/lib/oci8/object.rb +641 -0
  73. data/lib/oci8/oci8.rb +756 -0
  74. data/lib/oci8/ocihandle.rb +591 -0
  75. data/lib/oci8/oracle_version.rb +153 -0
  76. data/lib/oci8/properties.rb +196 -0
  77. data/lib/oci8/version.rb +3 -0
  78. data/lib/ruby-staci.rb +1 -0
  79. data/lib/staci.rb +190 -0
  80. data/metaconfig +142 -0
  81. data/pre-distclean.rb +7 -0
  82. data/ruby-aci.gemspec +83 -0
  83. data/setup.rb +1342 -0
  84. data/test/README.md +37 -0
  85. data/test/config.rb +201 -0
  86. data/test/setup_test_object.sql +199 -0
  87. data/test/setup_test_package.sql +59 -0
  88. data/test/test_all.rb +56 -0
  89. data/test/test_appinfo.rb +62 -0
  90. data/test/test_array_dml.rb +333 -0
  91. data/test/test_bind_array.rb +70 -0
  92. data/test/test_bind_boolean.rb +99 -0
  93. data/test/test_bind_integer.rb +47 -0
  94. data/test/test_bind_raw.rb +45 -0
  95. data/test/test_bind_string.rb +105 -0
  96. data/test/test_bind_time.rb +177 -0
  97. data/test/test_break.rb +124 -0
  98. data/test/test_clob.rb +86 -0
  99. data/test/test_connection_pool.rb +124 -0
  100. data/test/test_connstr.rb +220 -0
  101. data/test/test_datetime.rb +585 -0
  102. data/test/test_dbi.rb +365 -0
  103. data/test/test_dbi_clob.rb +53 -0
  104. data/test/test_encoding.rb +103 -0
  105. data/test/test_error.rb +87 -0
  106. data/test/test_metadata.rb +2674 -0
  107. data/test/test_object.rb +546 -0
  108. data/test/test_oci8.rb +624 -0
  109. data/test/test_oracle_version.rb +68 -0
  110. data/test/test_oradate.rb +255 -0
  111. data/test/test_oranumber.rb +786 -0
  112. data/test/test_package_type.rb +981 -0
  113. data/test/test_properties.rb +17 -0
  114. data/test/test_rowid.rb +32 -0
  115. metadata +158 -0
data/ext/oci8/stmt.c ADDED
@@ -0,0 +1,448 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * stmt.c - part of ruby-oci8
4
+ * implement the methods of OCIStmt.
5
+ *
6
+ * Copyright (C) 2002-2015 Kubo Takehiro <kubo@jiubao.org>
7
+ *
8
+ */
9
+ #include "oci8.h"
10
+
11
+ static VALUE cOCIStmt;
12
+
13
+ #define TO_STMT(obj) ((oci8_stmt_t *)oci8_check_typeddata((obj), &oci8_stmt_data_type, 1))
14
+
15
+ typedef struct {
16
+ oci8_base_t base;
17
+ VALUE svc;
18
+ char use_stmt_release;
19
+ char end_of_fetch;
20
+ } oci8_stmt_t;
21
+
22
+ static void oci8_stmt_mark(oci8_base_t *base)
23
+ {
24
+ oci8_stmt_t *stmt = (oci8_stmt_t *)base;
25
+ rb_gc_mark(stmt->svc);
26
+ }
27
+
28
+ static void oci8_stmt_free(oci8_base_t *base)
29
+ {
30
+ oci8_stmt_t *stmt = (oci8_stmt_t *)base;
31
+ stmt->svc = Qnil;
32
+ if (stmt->use_stmt_release) {
33
+ ACIStmtRelease(base->hp.stmt, oci8_errhp, NULL, 0, ACI_DEFAULT);
34
+ base->type = 0;
35
+ base->closed = 1;
36
+ stmt->use_stmt_release = 0;
37
+ }
38
+ }
39
+
40
+ static const oci8_handle_data_type_t oci8_stmt_data_type = {
41
+ {
42
+ "STACI::Cursor",
43
+ {
44
+ (RUBY_DATA_FUNC)oci8_stmt_mark,
45
+ oci8_handle_cleanup,
46
+ oci8_handle_size,
47
+ },
48
+ &oci8_handle_data_type.rb_data_type, NULL,
49
+ #ifdef RUBY_TYPED_WB_PROTECTED
50
+ RUBY_TYPED_WB_PROTECTED,
51
+ #endif
52
+ },
53
+ oci8_stmt_free,
54
+ sizeof(oci8_stmt_t),
55
+ };
56
+
57
+ static VALUE oci8_stmt_alloc(VALUE klass)
58
+ {
59
+ return oci8_allocate_typeddata(klass, &oci8_stmt_data_type);
60
+ }
61
+
62
+ /*
63
+ * @overload __initialize(connection, sql_statement)
64
+ *
65
+ * @param [OCI8] connection
66
+ * @param [String] sql_statement
67
+ *
68
+ * @private
69
+ */
70
+ static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
71
+ {
72
+ oci8_stmt_t *stmt = TO_STMT(self);
73
+ oci8_svcctx_t *svcctx;
74
+ sword rv;
75
+
76
+ svcctx = oci8_get_svcctx(svc);
77
+ oci8_check_pid_consistency(svcctx);
78
+ if (!NIL_P(sql)) {
79
+ OCI8SafeStringValue(sql);
80
+
81
+ rv = ACIStmtPrepare2(svcctx->base.hp.svc, &stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LEN(sql), NULL, 0, ACI_NTV_SYNTAX, ACI_DEFAULT);
82
+ if (IS_OCI_ERROR(rv)) {
83
+ chker2(rv, &svcctx->base);
84
+ }
85
+ stmt->base.type = ACI_HTYPE_STMT;
86
+ stmt->use_stmt_release = 1;
87
+ } else {
88
+ rv = ACIHandleAlloc(oci8_envhp, &stmt->base.hp.ptr, ACI_HTYPE_STMT, 0, NULL);
89
+ if (rv != ACI_SUCCESS) {
90
+ oci8_env_raise(oci8_envhp, rv);
91
+ }
92
+ stmt->base.type = ACI_HTYPE_STMT;
93
+ }
94
+ RB_OBJ_WRITE(stmt->base.self, &stmt->svc, svc);
95
+
96
+ oci8_link_to_parent(&stmt->base, &svcctx->base);
97
+ return Qnil;
98
+ }
99
+
100
+ /*
101
+ * @overload __define(position, bindobj)
102
+ *
103
+ * @param [Integer] position
104
+ * @param [OCI8::BindType::Base] bindobj
105
+ *
106
+ * @private
107
+ */
108
+ static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
109
+ {
110
+ oci8_stmt_t *stmt = TO_STMT(self);
111
+ ub4 position = NUM2INT(vposition);
112
+ oci8_bind_t *obind = TO_BIND(vbindobj);
113
+ const oci8_bind_data_type_t *data_type;
114
+ sword status;
115
+ void *valuep;
116
+ void *indp;
117
+ ub4 mode;
118
+
119
+ if (obind->base.hp.dfn != NULL) {
120
+ oci8_base_free(&obind->base); /* TODO: OK? */
121
+ }
122
+ data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
123
+ if (obind->value_sz != SB4MAXVAL) {
124
+ valuep = obind->valuep;
125
+ indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
126
+ mode = ACI_DEFAULT;
127
+ } else {
128
+ valuep = NULL;
129
+ indp = NULL;
130
+ mode = ACI_DYNAMIC_FETCH;
131
+ }
132
+ status = ACIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, valuep, obind->value_sz, data_type->dty, indp, NULL, 0, mode);
133
+ if (status != ACI_SUCCESS) {
134
+ chker3(status, &stmt->base, stmt->base.hp.ptr);
135
+ }
136
+ obind->base.type = ACI_HTYPE_DEFINE;
137
+ /* link to the parent as soon as possible to preserve deallocation order. */
138
+ oci8_unlink_from_parent((oci8_base_t*)obind);
139
+ oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
140
+
141
+ if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
142
+ chker2(ACIDefineArrayOfStruct(obind->base.hp.dfn, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0), &stmt->base);
143
+ }
144
+ if (data_type->post_bind_hook != NULL) {
145
+ data_type->post_bind_hook(obind);
146
+ }
147
+ return obind->base.self;
148
+ }
149
+
150
+ /*
151
+ * @overload __bind(placeholder, bindobj)
152
+ *
153
+ * @param [Integer, String or Symbol] placeholder
154
+ * @param [STACI::BindType::Base] bindobj
155
+ *
156
+ * @private
157
+ */
158
+ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
159
+ {
160
+ oci8_stmt_t *stmt = TO_STMT(self);
161
+ char *placeholder_ptr = (char*)-1; /* initialize as an invalid value */
162
+ ub4 placeholder_len = 0;
163
+ ub4 position = 0;
164
+ oci8_bind_t *obind;
165
+ const oci8_bind_data_type_t *data_type;
166
+ sword status;
167
+ void *valuep;
168
+ void *indp;
169
+ ub4 mode;
170
+
171
+ if (NIL_P(vplaceholder)) { /* 1 */
172
+ placeholder_ptr = NULL;
173
+ placeholder_len = 0;
174
+ } else if (SYMBOL_P(vplaceholder)) {
175
+ #ifdef HAVE_RB_SYM2STR
176
+ /* Don't use SYM2ID on ruby 2.2.0 or later.
177
+ * Symbols passed to SYM2ID are not GC'ed.
178
+ */
179
+ VALUE symval = rb_sym2str(vplaceholder);
180
+ const char *symname = RSTRING_PTR(symval);
181
+ size_t len = RSTRING_LEN(symval);
182
+ #else
183
+ const char *symname = rb_id2name(SYM2ID(vplaceholder));
184
+ size_t len = strlen(symname);
185
+ #endif
186
+ placeholder_ptr = ALLOCA_N(char, len + 1);
187
+ placeholder_len = len + 1;
188
+ placeholder_ptr[0] = ':';
189
+ memcpy(placeholder_ptr + 1, symname, len);
190
+ } else if (FIXNUM_P(vplaceholder)) {
191
+ position = NUM2INT(vplaceholder);
192
+ } else {
193
+ OCI8StringValue(vplaceholder);
194
+ placeholder_ptr = RSTRING_PTR(vplaceholder);
195
+ placeholder_len = RSTRING_LEN(vplaceholder);
196
+ }
197
+ obind = TO_BIND(vbindobj); /* 2 */
198
+ if (obind->base.hp.bnd != NULL) {
199
+ oci8_base_free(&obind->base); /* TODO: OK? */
200
+ }
201
+ data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
202
+
203
+ if (obind->value_sz != SB4MAXVAL) {
204
+ valuep = obind->valuep;
205
+ indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
206
+ mode = ACI_DEFAULT;
207
+ } else {
208
+ valuep = NULL;
209
+ indp = NULL;
210
+ mode = ACI_DATA_AT_EXEC;
211
+ }
212
+ if (placeholder_ptr == (char*)-1) {
213
+ status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, mode);
214
+ } else {
215
+ status = ACIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, mode);
216
+ }
217
+ if (status != ACI_SUCCESS) {
218
+ chker3(status, &stmt->base, stmt->base.hp.stmt);
219
+ }
220
+ obind->base.type = ACI_HTYPE_BIND;
221
+ /* link to the parent as soon as possible to preserve deallocation order. */
222
+ oci8_unlink_from_parent((oci8_base_t*)obind);
223
+ oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
224
+
225
+ if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
226
+ chker2(ACIBindArrayOfStruct(obind->base.hp.bnd, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0),
227
+ &stmt->base);
228
+ }
229
+ if (data_type->post_bind_hook != NULL) {
230
+ data_type->post_bind_hook(obind);
231
+ }
232
+ return obind->base.self;
233
+ }
234
+
235
+ static sword oci8_call_stmt_execute(oci8_svcctx_t *svcctx, oci8_stmt_t *stmt, ub4 iters, ub4 mode)
236
+ {
237
+ sword rv;
238
+
239
+ rv = ACIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
240
+ if (rv == ACI_ERROR) {
241
+ if (oci8_get_error_code(oci8_errhp) == 1000) {
242
+ /* run GC to close unreferred cursors
243
+ * when ORA-01000 (maximum open cursors exceeded).
244
+ */
245
+ rb_gc();
246
+ rv = ACIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
247
+ }
248
+ }
249
+ return rv;
250
+ }
251
+
252
+ /*
253
+ * @overload __execute(iteration_count)
254
+ *
255
+ * @param [Integer] iteration_count
256
+ *
257
+ * @private
258
+ */
259
+ static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
260
+ {
261
+ oci8_stmt_t *stmt = TO_STMT(self);
262
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
263
+
264
+ stmt->end_of_fetch = 0;
265
+ chker3(oci8_call_stmt_execute(svcctx, stmt, NUM2UINT(iteration_count),
266
+ svcctx->is_autocommit ? ACI_COMMIT_ON_SUCCESS : ACI_DEFAULT),
267
+ &stmt->base, stmt->base.hp.stmt);
268
+ return self;
269
+ }
270
+
271
+ /*
272
+ * @overload __fetch(connection, max_rows)
273
+ *
274
+ * Fetches one row and set the result to <code>@define_handles</code>.
275
+ * This is called by private methods of STACI::Cursor.
276
+ *
277
+ * @param [STACI] connection
278
+ * @return [true or false] true on success and false when all rows are fetched.
279
+ *
280
+ * @private
281
+ */
282
+ static VALUE oci8_stmt_fetch(VALUE self, VALUE svc, VALUE max_rows)
283
+ {
284
+ oci8_stmt_t *stmt = TO_STMT(self);
285
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
286
+ sword rv;
287
+ oci8_bind_t *obind;
288
+ const oci8_bind_data_type_t *data_type;
289
+ ub4 nrows = NUM2UINT(max_rows);
290
+
291
+ if (stmt->end_of_fetch) {
292
+ return Qnil;
293
+ }
294
+
295
+ if (stmt->base.children != NULL) {
296
+ obind = (oci8_bind_t *)stmt->base.children;
297
+ do {
298
+ if (obind->base.type == ACI_HTYPE_DEFINE) {
299
+ data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
300
+ if (data_type->pre_fetch_hook != NULL) {
301
+ data_type->pre_fetch_hook(obind, stmt->svc);
302
+ }
303
+ if (nrows > 1 && nrows != obind->maxar_sz) {
304
+ rb_raise(rb_eRuntimeError, "fetch size (%u) != define-handle size %u", nrows, obind->maxar_sz);
305
+ }
306
+ }
307
+ obind = (oci8_bind_t *)obind->base.next;
308
+ } while (obind != (oci8_bind_t*)stmt->base.children);
309
+ }
310
+ rv = ACIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp, nrows, ACI_FETCH_NEXT, ACI_DEFAULT);
311
+ if (rv == ACI_NO_DATA) {
312
+ stmt->end_of_fetch = 1;
313
+ } else {
314
+ chker3(rv, &svcctx->base, stmt->base.hp.stmt);
315
+ }
316
+ chker2(ACIAttrGet(stmt->base.hp.stmt, ACI_HTYPE_STMT, &nrows, 0, ACI_ATTR_ROWS_FETCHED, oci8_errhp),
317
+ &svcctx->base);
318
+ return nrows ? UINT2NUM(nrows) : Qnil;
319
+ }
320
+
321
+ /*
322
+ * @overload __paramGet(pos)
323
+ *
324
+ * Returns the definition of column specified by <i>pos</i>
325
+ *
326
+ * @param [Integer] pos Column position which starts from one
327
+ * @return [STACI::Metadata::Base]
328
+ *
329
+ * @private
330
+ */
331
+ static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
332
+ {
333
+ oci8_stmt_t *stmt = TO_STMT(self);
334
+ ACIParam *parmhp = NULL;
335
+ sword rv;
336
+
337
+ Check_Type(pos, T_FIXNUM); /* 1 */
338
+ rv = ACIParamGet(stmt->base.hp.stmt, ACI_HTYPE_STMT, oci8_errhp, (dvoid *)&parmhp, FIX2INT(pos));
339
+ if (rv != ACI_SUCCESS) {
340
+ chker3(rv, &stmt->base, stmt->base.hp.stmt);
341
+ }
342
+ return oci8_metadata_create(parmhp, stmt->svc, self);
343
+ }
344
+
345
+ /*
346
+ * Gets the rowid of the last inserted, updated or deleted row.
347
+ * This cannot be used for select statements.
348
+ *
349
+ * @example
350
+ * cursor = conn.parse('INSERT INTO foo_table values(:1, :2)', 1, 2)
351
+ * cursor.exec
352
+ * cursor.rowid # => "AAAFlLAAEAAAAG9AAA", the inserted row's rowid
353
+ *
354
+ * @return [String]
355
+ */
356
+ static VALUE oci8_stmt_get_rowid(VALUE self)
357
+ {
358
+ oci8_base_t *base = oci8_check_typeddata(self, &oci8_stmt_data_type, 1);
359
+ return oci8_get_rowid_attr(base, ACI_ATTR_ROWID, base->hp.stmt);
360
+ }
361
+
362
+ /*
363
+ * bind_stmt
364
+ */
365
+ VALUE oci8_stmt_get(oci8_bind_t *obind, void *data, void *null_struct)
366
+ {
367
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
368
+ rb_funcall(oho->obj, rb_intern("define_columns"), 0);
369
+ return oho->obj;
370
+ }
371
+
372
+ static void bind_stmt_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
373
+ {
374
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
375
+ oci8_stmt_t *stmt = TO_STMT(val);
376
+ oho->hp = stmt->base.hp.ptr;
377
+ RB_OBJ_WRITE(obind->base.self, &oho->obj, val);
378
+ }
379
+
380
+ static void bind_stmt_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
381
+ {
382
+ obind->value_sz = sizeof(void *);
383
+ obind->alloc_sz = sizeof(oci8_hp_obj_t);
384
+ }
385
+
386
+ static void bind_stmt_init_elem(oci8_bind_t *obind, VALUE svc)
387
+ {
388
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
389
+ oci8_base_t *h;
390
+ ub4 idx = 0;
391
+
392
+ do {
393
+ oho[idx].obj = rb_class_new_instance(1, &svc, cOCIStmt);
394
+ RB_OBJ_WRITTEN(obind->base.self, Qundef, oho[idx].obj);
395
+ h = DATA_PTR(oho[idx].obj);
396
+ oho[idx].hp = h->hp.ptr;
397
+ } while (++idx < obind->maxar_sz);
398
+ }
399
+
400
+ static const oci8_bind_data_type_t bind_stmt_data_type = {
401
+ {
402
+ {
403
+ "STACI::BindType::Cursor",
404
+ {
405
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
406
+ oci8_handle_cleanup,
407
+ oci8_handle_size,
408
+ },
409
+ &oci8_bind_data_type.rb_data_type, NULL,
410
+ #ifdef RUBY_TYPED_WB_PROTECTED
411
+ RUBY_TYPED_WB_PROTECTED,
412
+ #endif
413
+ },
414
+ oci8_bind_free,
415
+ sizeof(oci8_bind_t)
416
+ },
417
+ oci8_stmt_get,
418
+ bind_stmt_set,
419
+ bind_stmt_init,
420
+ bind_stmt_init_elem,
421
+ bind_stmt_init_elem,
422
+ SQLT_RSET
423
+ };
424
+
425
+ static VALUE bind_stmt_alloc(VALUE klass)
426
+ {
427
+ return oci8_allocate_typeddata(klass, &bind_stmt_data_type.base);
428
+ }
429
+
430
+ void Init_oci8_stmt(VALUE cOCI8)
431
+ {
432
+ #if 0
433
+ cOCIHandle = rb_define_class("ACIHandle", rb_cObject);
434
+ cOCI8 = rb_define_class("OCI8", cOCIHandle);
435
+ cOCIStmt = rb_define_class_under(cOCI8, "Cursor", cOCIHandle);
436
+ #endif
437
+ cOCIStmt = oci8_define_class_under(cOCI8, "Cursor", &oci8_stmt_data_type, oci8_stmt_alloc);
438
+
439
+ rb_define_private_method(cOCIStmt, "__initialize", oci8_stmt_initialize, 2);
440
+ rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2);
441
+ rb_define_private_method(cOCIStmt, "__bind", oci8_bind, 2);
442
+ rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 1);
443
+ rb_define_private_method(cOCIStmt, "__fetch", oci8_stmt_fetch, 2);
444
+ rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1);
445
+ rb_define_method(cOCIStmt, "rowid", oci8_stmt_get_rowid, 0);
446
+
447
+ oci8_define_bind_class("Cursor", &bind_stmt_data_type, bind_stmt_alloc);
448
+ }
@@ -0,0 +1,81 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * thread_util.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2011 KUBO Takehiro <kubo@jiubao.org>
6
+ */
7
+ #include "oci8.h"
8
+ #include <errno.h>
9
+
10
+ #ifndef WIN32
11
+ #include <pthread.h>
12
+ static pthread_attr_t detached_thread_attr;
13
+ #endif
14
+
15
+ typedef struct {
16
+ void *(*func)(void *);
17
+ void *arg;
18
+ } adapter_arg_t;
19
+
20
+ void Init_oci8_thread_util(void)
21
+ {
22
+ #ifndef WIN32
23
+ pthread_attr_init(&detached_thread_attr);
24
+ pthread_attr_setdetachstate(&detached_thread_attr, PTHREAD_CREATE_DETACHED);
25
+ #endif
26
+ }
27
+
28
+ #ifdef WIN32
29
+
30
+ static void __cdecl adapter(void *arg)
31
+ {
32
+ adapter_arg_t *aa = (adapter_arg_t *)arg;
33
+ aa->func(aa->arg);
34
+ free(aa);
35
+ }
36
+
37
+ int oci8_run_native_thread(void *(*func)(void*), void *arg)
38
+ {
39
+ adapter_arg_t *aa = malloc(sizeof(adapter_arg_t));
40
+ if (aa == NULL) {
41
+ return ENOMEM;
42
+ }
43
+
44
+ aa->func = func;
45
+ aa->arg = arg;
46
+ if (_beginthread(adapter, 0, aa) == (uintptr_t)-1L) {
47
+ int err = errno;
48
+ free(aa);
49
+ return err;
50
+ }
51
+ return 0;
52
+ }
53
+
54
+ #else /* WIN32 */
55
+
56
+ static void *adapter(void *arg)
57
+ {
58
+ adapter_arg_t *aa = (adapter_arg_t *)arg;
59
+ aa->func(aa->arg);
60
+ free(aa);
61
+ return NULL;
62
+ }
63
+
64
+ int oci8_run_native_thread(void *(*func)(void *), void *arg)
65
+ {
66
+ pthread_t thread;
67
+ adapter_arg_t *aa = malloc(sizeof(adapter_arg_t));
68
+ int rv;
69
+ if (aa == NULL) {
70
+ return ENOMEM;
71
+ }
72
+
73
+ aa->func = func;
74
+ aa->arg = arg;
75
+ rv = pthread_create(&thread, &detached_thread_attr, adapter, aa);
76
+ if (rv != 0) {
77
+ free(aa);
78
+ }
79
+ return rv;
80
+ }
81
+ #endif /* WIN32 */
@@ -0,0 +1,18 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * thread_util.h - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2011 KUBO Takehiro <kubo@jiubao.org>
6
+ */
7
+
8
+ /*
9
+ * Prepare to execute thread-related functions.
10
+ */
11
+ void Init_oci8_thread_util(void);
12
+
13
+ /*
14
+ * Run the func in a new native thread.
15
+ * Don't call any ruby functions in the func.
16
+ * The return value is errno.
17
+ */
18
+ int oci8_run_native_thread(void *(*func)(void *), void *arg);
data/ext/oci8/util.c ADDED
@@ -0,0 +1,71 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ util.c - part of ruby-oci8
4
+
5
+ Copyright (C) 2015 Kubo Takehiro <kubo@jiubao.org>
6
+ */
7
+ #if defined __linux && !defined(_GNU_SOURCE)
8
+ #define _GNU_SOURCE 1
9
+ #endif
10
+ #include "oci8.h"
11
+ #ifdef HAVE_DLADDR
12
+ #include <dlfcn.h>
13
+ #endif
14
+ #ifdef __CYGWIN__
15
+ #undef boolean
16
+ #include <windows.h>
17
+ #endif
18
+
19
+ const char *oci8_dll_path(void)
20
+ {
21
+ #if defined _WIN32 || defined __CYGWIN__
22
+ HMODULE hMod = GetModuleHandleA("ACI.DLL");
23
+ static char buf[MAX_PATH];
24
+ if (hMod != NULL) {
25
+ if (GetModuleFileName(hMod, buf, sizeof(buf))) {
26
+ return buf;
27
+ }
28
+ }
29
+ #elif defined HAVE_DLADDR && defined RTLD_DEFAULT
30
+ void *addr = dlsym(RTLD_DEFAULT, "ACIEnvCreate");
31
+ Dl_info info;
32
+ if (addr != NULL && dladdr(addr, &info)) {
33
+ return info.dli_fname;
34
+ }
35
+ #elif defined HAVE_DLMODINFO && defined HAVE_DLGETNAME && defined RTLD_DEFAULT
36
+ void *addr = dlsym(RTLD_DEFAULT, "ACIEnvCreate");
37
+ if (addr != NULL) {
38
+ struct load_module_desc desc;
39
+ if (dlmodinfo((uint64_t)addr, &desc, sizeof(desc), NULL, 0, 0) != 0) {
40
+ return dlgetname(&desc, sizeof(desc), NULL, 0, 0);
41
+ }
42
+ }
43
+ #endif
44
+ return NULL;
45
+ }
46
+
47
+ /*
48
+ * Returns the full path of Oracle client library used by the current process.
49
+ *
50
+ * @return [String]
51
+ */
52
+ static VALUE dll_path(VALUE module)
53
+ {
54
+ const char *path = oci8_dll_path();
55
+ if (path == NULL) {
56
+ return Qnil;
57
+ }
58
+ return rb_external_str_new_with_enc(path, strlen(path), rb_filesystem_encoding());
59
+ }
60
+
61
+ void Init_oci8_util(VALUE cOCI8)
62
+ {
63
+ #if 0
64
+ /* for yard */
65
+ cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
66
+ cOCI8 = rb_define_class("STACI", cOCIHandle);
67
+ #endif
68
+ VALUE mUtil = rb_define_module_under(cOCI8, "Util");
69
+
70
+ rb_define_module_function(mUtil, "dll_path", dll_path, 0);
71
+ }