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/lob.c ADDED
@@ -0,0 +1,1278 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * lob.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2002-2015 Kubo Takehiro <kubo@jiubao.org>
6
+ */
7
+ #include "oci8.h"
8
+
9
+ static ID id_plus;
10
+ static ID id_dir_alias;
11
+ static ID id_filename;
12
+ static VALUE cOCI8LOB;
13
+ static VALUE cOCI8CLOB;
14
+ static VALUE cOCI8NCLOB;
15
+ static VALUE cOCI8BLOB;
16
+ static VALUE cOCI8BFILE;
17
+ static VALUE seek_set;
18
+ static VALUE seek_cur;
19
+ static VALUE seek_end;
20
+
21
+ #define TO_LOB(obj) ((oci8_lob_t *)oci8_check_typeddata((obj), &oci8_lob_data_type, 1))
22
+
23
+ #ifndef MIN
24
+ #define MIN(a, b) ((a) < (b) ? (a) : (b))
25
+ #endif
26
+
27
+ enum state {
28
+ S_NO_OPEN_CLOSE,
29
+ S_BFILE_CLOSE,
30
+ S_BFILE_OPEN,
31
+ };
32
+ typedef struct {
33
+ oci8_base_t base;
34
+ oci8_svcctx_t *svcctx;
35
+ ub8 pos;
36
+ ub1 csfrm;
37
+ ub1 lobtype;
38
+ enum state state;
39
+ } oci8_lob_t;
40
+
41
+ static oci8_svcctx_t *check_svcctx(oci8_lob_t *lob)
42
+ {
43
+ oci8_svcctx_t *svcctx = lob->svcctx;
44
+ if (svcctx == NULL || svcctx->base.type != ACI_HTYPE_SVCCTX) {
45
+ rb_raise(rb_eRuntimeError, "Invalid Svcctx");
46
+ }
47
+ return svcctx;
48
+ }
49
+
50
+ static VALUE oci8_lob_write(VALUE self, VALUE data);
51
+
52
+ static void oci8_lob_mark(oci8_base_t *base)
53
+ {
54
+ oci8_lob_t *lob = (oci8_lob_t *)base;
55
+ if (lob->svcctx != NULL) {
56
+ rb_gc_mark(lob->svcctx->base.self);
57
+ }
58
+ }
59
+
60
+ static void oci8_lob_free(oci8_base_t *base)
61
+ {
62
+ oci8_lob_t *lob = (oci8_lob_t *)base;
63
+ boolean is_temporary;
64
+ oci8_svcctx_t *svcctx = lob->svcctx;
65
+
66
+ if (svcctx != NULL
67
+ && ACILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == ACI_SUCCESS
68
+ && is_temporary) {
69
+ oci8_temp_lob_t *temp_lob = ALLOC(oci8_temp_lob_t);
70
+
71
+ temp_lob->next = svcctx->temp_lobs;
72
+ temp_lob->lob = lob->base.hp.lob;
73
+ svcctx->temp_lobs = temp_lob;
74
+ lob->base.type = 0;
75
+ lob->base.closed = 1;
76
+ lob->base.hp.ptr = NULL;
77
+ }
78
+ lob->svcctx = NULL;
79
+ }
80
+
81
+ static const oci8_handle_data_type_t oci8_lob_data_type = {
82
+ {
83
+ "STACI::LOB",
84
+ {
85
+ NULL,
86
+ NULL,
87
+ NULL,
88
+ },
89
+ &oci8_handle_data_type.rb_data_type, NULL,
90
+ },
91
+ NULL,
92
+ sizeof(oci8_lob_t),
93
+ };
94
+
95
+ static VALUE oci8_lob_alloc(VALUE klass)
96
+ {
97
+ rb_raise(rb_eNameError, "private method `new' called for %s:Class", rb_class2name(klass));
98
+ }
99
+
100
+ static const oci8_handle_data_type_t oci8_clob_data_type = {
101
+ {
102
+ "STACI::CLOB",
103
+ {
104
+ (RUBY_DATA_FUNC)oci8_lob_mark,
105
+ oci8_handle_cleanup,
106
+ oci8_handle_size,
107
+ },
108
+ &oci8_lob_data_type.rb_data_type, NULL,
109
+ #ifdef RUBY_TYPED_WB_PROTECTED
110
+ RUBY_TYPED_WB_PROTECTED,
111
+ #endif
112
+ },
113
+ oci8_lob_free,
114
+ sizeof(oci8_lob_t),
115
+ };
116
+
117
+ static VALUE oci8_clob_alloc(VALUE klass)
118
+ {
119
+ return oci8_allocate_typeddata(klass, &oci8_clob_data_type);
120
+ }
121
+
122
+ static const oci8_handle_data_type_t oci8_nclob_data_type = {
123
+ {
124
+ "STACI::NCLOB",
125
+ {
126
+ (RUBY_DATA_FUNC)oci8_lob_mark,
127
+ oci8_handle_cleanup,
128
+ oci8_handle_size,
129
+ },
130
+ &oci8_lob_data_type.rb_data_type, NULL,
131
+ #ifdef RUBY_TYPED_WB_PROTECTED
132
+ RUBY_TYPED_WB_PROTECTED,
133
+ #endif
134
+ },
135
+ oci8_lob_free,
136
+ sizeof(oci8_lob_t),
137
+ };
138
+
139
+ static VALUE oci8_nclob_alloc(VALUE klass)
140
+ {
141
+ return oci8_allocate_typeddata(klass, &oci8_nclob_data_type);
142
+ }
143
+
144
+ static const oci8_handle_data_type_t oci8_blob_data_type = {
145
+ {
146
+ "STACI::BLOB",
147
+ {
148
+ (RUBY_DATA_FUNC)oci8_lob_mark,
149
+ oci8_handle_cleanup,
150
+ oci8_handle_size,
151
+ },
152
+ &oci8_lob_data_type.rb_data_type, NULL,
153
+ #ifdef RUBY_TYPED_WB_PROTECTED
154
+ RUBY_TYPED_WB_PROTECTED,
155
+ #endif
156
+ },
157
+ oci8_lob_free,
158
+ sizeof(oci8_lob_t),
159
+ };
160
+
161
+ static VALUE oci8_blob_alloc(VALUE klass)
162
+ {
163
+ return oci8_allocate_typeddata(klass, &oci8_blob_data_type);
164
+ }
165
+
166
+ static const oci8_handle_data_type_t oci8_bfile_data_type = {
167
+ {
168
+ "STACI::BFILE",
169
+ {
170
+ (RUBY_DATA_FUNC)oci8_lob_mark,
171
+ oci8_handle_cleanup,
172
+ oci8_handle_size,
173
+ },
174
+ &oci8_lob_data_type.rb_data_type, NULL,
175
+ #ifdef RUBY_TYPED_WB_PROTECTED
176
+ RUBY_TYPED_WB_PROTECTED,
177
+ #endif
178
+ },
179
+ oci8_lob_free,
180
+ sizeof(oci8_lob_t),
181
+ };
182
+
183
+ static VALUE oci8_bfile_alloc(VALUE klass)
184
+ {
185
+ return oci8_allocate_typeddata(klass, &oci8_bfile_data_type);
186
+ }
187
+
188
+ static VALUE oci8_make_lob(VALUE klass, oci8_svcctx_t *svcctx, ACILobLocator *s)
189
+ {
190
+ oci8_lob_t *lob;
191
+ boolean is_temp;
192
+ VALUE lob_obj;
193
+
194
+ lob_obj = rb_class_new_instance(1, &svcctx->base.self, klass);
195
+ lob = TO_LOB(lob_obj);
196
+ /* If 's' is a temporary lob, use OCILobLocatorAssign instead. */
197
+ chker2(ACILobIsTemporary(oci8_envhp, oci8_errhp, s, &is_temp), &svcctx->base);
198
+ if (is_temp)
199
+ chker2(ACILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, s, &lob->base.hp.lob),
200
+ &svcctx->base);
201
+ else
202
+ chker2(ACILobAssign(oci8_envhp, oci8_errhp, s, &lob->base.hp.lob),
203
+ &svcctx->base);
204
+ return lob_obj;
205
+ }
206
+
207
+ VALUE oci8_make_clob(oci8_svcctx_t *svcctx, ACILobLocator *s)
208
+ {
209
+ return oci8_make_lob(cOCI8CLOB, svcctx, s);
210
+ }
211
+
212
+ VALUE oci8_make_nclob(oci8_svcctx_t *svcctx, ACILobLocator *s)
213
+ {
214
+ return oci8_make_lob(cOCI8NCLOB, svcctx, s);
215
+ }
216
+
217
+ VALUE oci8_make_blob(oci8_svcctx_t *svcctx, ACILobLocator *s)
218
+ {
219
+ return oci8_make_lob(cOCI8BLOB, svcctx, s);
220
+ }
221
+
222
+ VALUE oci8_make_bfile(oci8_svcctx_t *svcctx, ACILobLocator *s)
223
+ {
224
+ return oci8_make_lob(cOCI8BFILE, svcctx, s);
225
+ }
226
+
227
+ static void oci8_assign_lob(VALUE klass, oci8_svcctx_t *svcctx, VALUE lob, ACILobLocator **dest)
228
+ {
229
+ oci8_base_t *base = oci8_check_typeddata(lob, &oci8_lob_data_type, 1);
230
+ if (!rb_obj_is_kind_of(lob, klass)) {
231
+ rb_raise(rb_eTypeError, "wrong argument %s (expect %s)",
232
+ rb_obj_classname(lob), rb_class2name(klass));
233
+ }
234
+ chker2(ACILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, base->hp.lob, dest), base);
235
+ }
236
+
237
+ void oci8_assign_clob(oci8_svcctx_t *svcctx, VALUE lob, ACILobLocator **dest)
238
+ {
239
+ oci8_assign_lob(cOCI8CLOB, svcctx, lob, dest);
240
+ }
241
+
242
+ void oci8_assign_nclob(oci8_svcctx_t *svcctx, VALUE lob, ACILobLocator **dest)
243
+ {
244
+ oci8_assign_lob(cOCI8NCLOB, svcctx, lob, dest);
245
+ }
246
+
247
+ void oci8_assign_blob(oci8_svcctx_t *svcctx, VALUE lob, ACILobLocator **dest)
248
+ {
249
+ oci8_assign_lob(cOCI8BLOB, svcctx, lob, dest);
250
+ }
251
+
252
+ void oci8_assign_bfile(oci8_svcctx_t *svcctx, VALUE lob, ACILobLocator **dest)
253
+ {
254
+ oci8_assign_lob(cOCI8BFILE, svcctx, lob, dest);
255
+ }
256
+
257
+ static ub8 oci8_lob_get_length(oci8_lob_t *lob)
258
+ {
259
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
260
+ ub8 len;
261
+
262
+ chker2(ACILobGetLength2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len),
263
+ &svcctx->base);
264
+ return len;
265
+ }
266
+
267
+ static void bfile_close(oci8_lob_t *lob)
268
+ {
269
+ if (lob->state == S_BFILE_OPEN) {
270
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
271
+
272
+ chker2(ACILobFileClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob),
273
+ &svcctx->base);
274
+ lob->state = S_BFILE_CLOSE;
275
+ }
276
+ }
277
+
278
+ /*
279
+ * Document-class: STACI::LOB
280
+ *
281
+ * STACI::LOB is an I/O object. LOB contents are read from and written
282
+ * to the Oracle server via an associating connection. When a connection
283
+ * is closed, associating LOBs are also closed.
284
+ *
285
+ * This is the abstract base class of large-object data types; {BFILE}, {BLOB}, {CLOB} and {NCLOB}.
286
+ *
287
+ */
288
+
289
+ /*
290
+ * Document-class: STACI::CLOB
291
+ *
292
+ * This class is a ruby-side class of {Oracle NCLOB datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref175].
293
+ */
294
+
295
+ /*
296
+ * Document-class: STACI::NCLOB
297
+ *
298
+ * This class is a ruby-side class of {Oracle CLOB datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref172].
299
+ */
300
+
301
+ /*
302
+ * Document-class: STACI::BLOB
303
+ *
304
+ * This class is a ruby-side class of {Oracle BLOB datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref168].
305
+ *
306
+ */
307
+
308
+ /*
309
+ * Document-class: STACI::BFILE
310
+ *
311
+ * This class is a ruby-side class of {Oracle BFILE datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref164].
312
+ * It is a read-only {LOB}. You cannot change the contents.
313
+ *
314
+ * You can read files on the server-side as follows:
315
+ *
316
+ * 1. Connect to the Oracle server as a user who has CREATE DIRECTORY privilege.
317
+ *
318
+ * # create a directory object on the Oracle server.
319
+ * CREATE DIRECTORY file_storage_dir AS '/opt/file_storage';
320
+ * # grant a privilege to read files on file_storage_dir directory to a user.
321
+ * GRANT READ ON DIRECTORY file_storage_dir TO username;
322
+ *
323
+ * 2. Create a file 'hello_world.txt' in the directory '/opt/file_storage' on the server filesystem.
324
+ *
325
+ * echo 'Hello World!' > /opt/file_storage/hello_world.txt
326
+ *
327
+ * 3. Read the file by ruby-oci8.
328
+ *
329
+ * require 'oci8'
330
+ * # The user must have 'READ ON DIRECTORY file_storage_dir' privilege.
331
+ * conn = STACI.new('username/password')
332
+ *
333
+ * # The second argument is usually an uppercase string unless the directory
334
+ * # object is explicitly created as *double-quoted* lowercase characters.
335
+ * bfile = STACI::BFILE.new(conn, 'FILE_STORAGE_DIR', 'hello_world.txt')
336
+ * bfile.read # => "Hello World!\n"
337
+ */
338
+
339
+ /*
340
+ * Closes the lob.
341
+ *
342
+ * @return [self]
343
+ */
344
+ static VALUE oci8_lob_close(VALUE self)
345
+ {
346
+ oci8_lob_t *lob = TO_LOB(self);
347
+ oci8_base_free(&lob->base);
348
+ return self;
349
+ }
350
+
351
+ static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm, ub1 lobtype)
352
+ {
353
+ oci8_lob_t *lob = TO_LOB(self);
354
+ VALUE svc;
355
+ VALUE val;
356
+ oci8_svcctx_t *svcctx;
357
+ sword rv;
358
+
359
+ rb_scan_args(argc, argv, "11", &svc, &val);
360
+ svcctx = oci8_get_svcctx(svc);
361
+ rv = ACIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, ACI_DTYPE_LOB, 0, NULL);
362
+ if (rv != ACI_SUCCESS)
363
+ oci8_env_raise(oci8_envhp, rv);
364
+ lob->base.type = ACI_DTYPE_LOB;
365
+ lob->pos = 0;
366
+ lob->csfrm = csfrm;
367
+ lob->lobtype = lobtype;
368
+ lob->state = S_NO_OPEN_CLOSE;
369
+ oci8_link_to_parent(&lob->base, &svcctx->base);
370
+ lob->svcctx = svcctx;
371
+ RB_OBJ_WRITTEN(self, Qundef, svc);
372
+ if (!NIL_P(val)) {
373
+ OCI8StringValue(val);
374
+ chker2(ACILobCreateTemporary_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, 0, csfrm, lobtype, TRUE, ACI_DURATION_SESSION),
375
+ &svcctx->base);
376
+ oci8_lob_write(self, val);
377
+ lob->pos = 0; /* reset the position */
378
+ }
379
+ return Qnil;
380
+ }
381
+
382
+ /*
383
+ * call-seq:
384
+ * initialize(conn, contents = nil)
385
+ *
386
+ * Creates a temporary CLOB when <i>contents</i> is not nil.
387
+ * Otherwise, it creates an uninitialized lob, which is used internally
388
+ * to fetch CLOB column data.
389
+ *
390
+ * @example
391
+ * # Inserts a file name and its contents as CLOB.
392
+ * clob = STACI::CLOB.new(conn, File.read(file_name))
393
+ * conn.exec('insert into file_contents values (:1, :2)', file_name, clob)
394
+ *
395
+ * @param [STACI] conn connection
396
+ * @param [String] contents
397
+ * @return [STACI::CLOB]
398
+ */
399
+ static VALUE oci8_clob_initialize(int argc, VALUE *argv, VALUE self)
400
+ {
401
+ oci8_lob_do_initialize(argc, argv, self, SQLCS_IMPLICIT, ACI_TEMP_CLOB);
402
+ return Qnil;
403
+ }
404
+
405
+ /*
406
+ * call-seq:
407
+ * initialize(conn, contents = nil)
408
+ *
409
+ * Creates a temporary NCLOB when <i>contents</i> is not nil.
410
+ * Otherwise, it creates an uninitialized lob, which is used internally
411
+ * to fetch NCLOB column data.
412
+ *
413
+ * @example
414
+ * # Inserts a file name and its contents as NCLOB.
415
+ * clob = STACI::NCLOB.new(conn, File.read(file_name))
416
+ * conn.exec('insert into file_contents values (:1, :2)', file_name, clob)
417
+ *
418
+ * @param [STACI] conn
419
+ * @param [String] contents
420
+ * @return [STACI::NCLOB]
421
+ */
422
+ static VALUE oci8_nclob_initialize(int argc, VALUE *argv, VALUE self)
423
+ {
424
+ oci8_lob_do_initialize(argc, argv, self, SQLCS_NCHAR, ACI_TEMP_CLOB);
425
+ return Qnil;
426
+ }
427
+
428
+ /*
429
+ * call-seq:
430
+ * initialize(conn, contents = nil)
431
+ *
432
+ * Creates a temporary BLOB when <i>contents</i> is not nil.
433
+ * Otherwise, it creates an uninitialized lob, which is used internally
434
+ * to fetch BLOB column data.
435
+ *
436
+ * @example
437
+ * # Inserts a file name and its contents as BLOB.
438
+ * clob = STACI::BLOB.new(conn, File.read(file_name, :mode => 'rb'))
439
+ * conn.exec('insert into file_contents values (:1, :2)', file_name, clob)
440
+ *
441
+ * @param [STACI] conn
442
+ * @param [String] contents
443
+ * @return [STACI::BLOB]
444
+ */
445
+ static VALUE oci8_blob_initialize(int argc, VALUE *argv, VALUE self)
446
+ {
447
+ oci8_lob_do_initialize(argc, argv, self, SQLCS_IMPLICIT, ACI_TEMP_BLOB);
448
+ return Qnil;
449
+ }
450
+
451
+ /*
452
+ * Returns +true+ when <i>self</i> is initialized.
453
+ *
454
+ * @return [true or false]
455
+ */
456
+ static VALUE oci8_lob_available_p(VALUE self)
457
+ {
458
+ oci8_lob_t *lob = TO_LOB(self);
459
+ boolean is_initialized;
460
+
461
+ chker2(ACILobLocatorIsInit(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_initialized),
462
+ &lob->base);
463
+ return is_initialized ? Qtrue : Qfalse;
464
+ }
465
+
466
+ /*
467
+ * Returns the size.
468
+ * For CLOB and NCLOB it is the number of characters,
469
+ * for BLOB and BFILE it is the number of bytes.
470
+ *
471
+ * @return [Integer]
472
+ */
473
+ static VALUE oci8_lob_get_size(VALUE self)
474
+ {
475
+ return ULL2NUM(oci8_lob_get_length(TO_LOB(self)));
476
+ }
477
+
478
+ /*
479
+ * Returns the current offset.
480
+ * For CLOB and NCLOB it is the number of characters,
481
+ * for BLOB and BFILE it is the number of bytes.
482
+ *
483
+ * @return [Integer]
484
+ */
485
+ static VALUE oci8_lob_get_pos(VALUE self)
486
+ {
487
+ oci8_lob_t *lob = TO_LOB(self);
488
+ return ULL2NUM(lob->pos);
489
+ }
490
+
491
+ /*
492
+ * Returns true if the current offset is at end of lob.
493
+ *
494
+ * @return [true or false]
495
+ */
496
+ static VALUE oci8_lob_eof_p(VALUE self)
497
+ {
498
+ oci8_lob_t *lob = TO_LOB(self);
499
+ if (oci8_lob_get_length(lob) < lob->pos)
500
+ return Qfalse;
501
+ else
502
+ return Qtrue;
503
+ }
504
+
505
+ /*
506
+ * call-seq:
507
+ * seek(amount, whence=IO::SEEK_SET)
508
+ *
509
+ * Seeks to the given offset in the stream. The new position, measured in characters,
510
+ * is obtained by adding offset <i>amount</i> to the position specified by <i>whence</i>.
511
+ * If <i>whence</i> is set to IO::SEEK_SET, IO::SEEK_CUR, or IO::SEEK_END,
512
+ * the offset is relative to the start of the file, the current position
513
+ * indicator, or end-of-file, respectively.
514
+ *
515
+ * @param [Integer] amount
516
+ * @param [IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END] whence
517
+ * @return [self]
518
+ */
519
+ static VALUE oci8_lob_seek(int argc, VALUE *argv, VALUE self)
520
+ {
521
+ oci8_lob_t *lob = TO_LOB(self);
522
+ VALUE position, whence;
523
+
524
+ rb_scan_args(argc, argv, "11", &position, &whence);
525
+ if (argc == 2 && (whence != seek_set && whence != seek_cur && whence != seek_end)) {
526
+ if (FIXNUM_P(whence)) {
527
+ rb_raise(rb_eArgError, "expect IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END but %d",
528
+ FIX2INT(whence));
529
+ } else {
530
+ rb_raise(rb_eArgError, "expect IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END but %s",
531
+ rb_class2name(CLASS_OF(whence)));
532
+ }
533
+ }
534
+ if (whence == seek_cur) {
535
+ position = rb_funcall(ULL2NUM(lob->pos), id_plus, 1, position);
536
+ } else if (whence == seek_end) {
537
+ position = rb_funcall(ULL2NUM(oci8_lob_get_length(lob)), id_plus, 1, position);
538
+ }
539
+ lob->pos = NUM2ULL(position);
540
+ return self;
541
+ }
542
+
543
+ /*
544
+ * Sets the current offset at the beginning.
545
+ *
546
+ * @return [true or false]
547
+ */
548
+ static VALUE oci8_lob_rewind(VALUE self)
549
+ {
550
+ oci8_lob_t *lob = TO_LOB(self);
551
+ lob->pos = 0;
552
+ return self;
553
+ }
554
+
555
+ /*
556
+ * call-seq:
557
+ * truncate(length)
558
+ *
559
+ * @param [Integer] length length in characters if +self+ is a {CLOB} or a {NCLOB}.
560
+ * length in bytes if +self+ is a {BLOB} or a {BFILE}.
561
+ * @return [self]
562
+ * @see #size=
563
+ */
564
+ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
565
+ {
566
+ oci8_lob_t *lob = TO_LOB(self);
567
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
568
+
569
+ chker2(ACILobTrim2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2ULL(len)),
570
+ &svcctx->base);
571
+ return self;
572
+ }
573
+
574
+ /*
575
+ * @overload size=(length)
576
+ *
577
+ * Changes the lob size to the given <i>length</i>.
578
+ *
579
+ * @param [Integer] length length in characters if +self+ is a {CLOB} or a {NCLOB}.
580
+ * length in bytes if +self+ is a {BLOB} or a {BFILE}.
581
+ * @see #truncate
582
+ */
583
+ static VALUE oci8_lob_set_size(VALUE self, VALUE len)
584
+ {
585
+ oci8_lob_truncate(self, len);
586
+ return len;
587
+ }
588
+
589
+ static void open_bfile(oci8_svcctx_t *svcctx, oci8_lob_t *lob, ACIError *errhp)
590
+ {
591
+ while (1) {
592
+ sword rv = ACILobFileOpen_nb(svcctx, svcctx->base.hp.svc, errhp, lob->base.hp.lob, ACI_FILE_READONLY);
593
+ if (rv == ACI_ERROR && oci8_get_error_code(oci8_errhp) == 22290) {
594
+ /* ORA-22290: operation would exceed the maximum number of opened files or LOBs */
595
+ /* close all opened BFILE implicitly. */
596
+ oci8_base_t *base;
597
+ for (base = &lob->base; base != &lob->base; base = base->next) {
598
+ if (base->type == ACI_DTYPE_LOB) {
599
+ oci8_lob_t *tmp = (oci8_lob_t *)base;
600
+ if (tmp->state == S_BFILE_OPEN) {
601
+ chker2(ACILobFileClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, tmp->base.hp.lob),
602
+ &svcctx->base);
603
+ tmp->state = S_BFILE_CLOSE;
604
+ }
605
+ }
606
+ }
607
+ } else {
608
+ chker2(rv, &svcctx->base);
609
+ lob->state = S_BFILE_OPEN;
610
+ return;
611
+ }
612
+ }
613
+ }
614
+
615
+ /*
616
+ * @overload read
617
+ *
618
+ *
619
+ *
620
+ * @param [Integer] length number of characters if +self+ is a {CLOB} or a {NCLOB}.
621
+ * number of bytes if +self+ is a {BLOB} or a {BFILE}.
622
+ * @return [String or nil] data read. <code>nil</code> means it
623
+ * met EOF at beginning. It returns an empty string '' as a special exception
624
+ * when <i>length</i> is <code>nil</code> and the lob is empty.
625
+ *
626
+ * @overload read(length)
627
+ *
628
+ * Reads <i>length</i> characters for {CLOB} and {NCLOB} or <i>length</i>
629
+ * bytes for {BLOB} and {BFILE} from the current position.
630
+ * If <i>length</i> is <code>nil</code>, it reads data until EOF.
631
+ *
632
+ * @param [Integer] length number of characters if +self+ is a {CLOB} or a {NCLOB}.
633
+ * number of bytes if +self+ is a {BLOB} or a {BFILE}.
634
+ * @return [String or nil] data read. <code>nil</code> means it
635
+ * met EOF at beginning. It returns an empty string '' as a special exception
636
+ * when <i>length</i> is <code>nil</code> and the lob is empty.
637
+ */
638
+ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
639
+ {
640
+ oci8_lob_t *lob = TO_LOB(self);
641
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
642
+ ub8 pos = lob->pos;
643
+ long strbufsiz = 512;
644
+ ub8 sz;
645
+ ub8 byte_amt;
646
+ ub8 char_amt;
647
+ sword rv;
648
+ VALUE size;
649
+ VALUE v = rb_ary_new();
650
+ ACIError *errhp = oci8_errhp;
651
+ ub1 piece = ACI_FIRST_PIECE;
652
+
653
+ rb_scan_args(argc, argv, "01", &size);
654
+ if (NIL_P(size)) {
655
+ sz = UB4MAXVAL;
656
+ } else {
657
+ sz = NUM2ULL(size);
658
+ }
659
+ if (lob->state == S_BFILE_CLOSE) {
660
+ open_bfile(svcctx, lob, errhp);
661
+ }
662
+ read_more_data:
663
+ if (lob->lobtype == ACI_TEMP_CLOB) {
664
+ byte_amt = 0;
665
+ char_amt = sz;
666
+ } else {
667
+ byte_amt = sz;
668
+ char_amt = 0;
669
+ }
670
+ do {
671
+ VALUE strbuf = rb_str_buf_new(strbufsiz);
672
+ char *buf = RSTRING_PTR(strbuf);
673
+
674
+ rv = ACILobRead2_nb(svcctx, svcctx->base.hp.svc, errhp, lob->base.hp.lob, &byte_amt, &char_amt, pos + 1, buf, strbufsiz, piece, NULL, NULL, 0, lob->csfrm);
675
+ svcctx->suppress_free_temp_lobs = 0;
676
+ switch (rv) {
677
+ case ACI_SUCCESS:
678
+ break;
679
+ case ACI_NEED_DATA:
680
+ /* prevent ACILobFreeTemporary() from being called.
681
+ * See: https://github.com/kubo/ruby-oci8/issues/20
682
+ */
683
+ svcctx->suppress_free_temp_lobs = 1;
684
+ piece = ACI_NEXT_PIECE;
685
+ break;
686
+ default:
687
+ chker2(rv, &svcctx->base);
688
+ }
689
+ if (byte_amt == 0)
690
+ break;
691
+ if (lob->lobtype == ACI_TEMP_CLOB) {
692
+ pos += char_amt;
693
+ } else {
694
+ pos += byte_amt;
695
+ }
696
+ rb_str_set_len(strbuf, byte_amt);
697
+ rb_ary_push(v, strbuf);
698
+ if (strbufsiz < 128 * 1024 * 1024) {
699
+ strbufsiz *= 2;
700
+ }
701
+ } while (rv == ACI_NEED_DATA);
702
+
703
+ if (NIL_P(size) && pos - lob->pos == sz) {
704
+ lob->pos = pos;
705
+ piece = ACI_FIRST_PIECE;
706
+ goto read_more_data;
707
+ }
708
+ lob->pos = pos;
709
+ switch (RARRAY_LEN(v)) {
710
+ case 0:
711
+ if (NIL_P(size) && pos == 0) {
712
+ return rb_usascii_str_new("", 0);
713
+ } else {
714
+ return Qnil;
715
+ }
716
+ case 1:
717
+ v = RARRAY_AREF(v, 0);
718
+ break;
719
+ default:
720
+ v = rb_ary_join(v, Qnil);
721
+ }
722
+ OBJ_TAINT(v);
723
+ if (lob->lobtype == ACI_TEMP_CLOB) {
724
+ /* set encoding */
725
+ rb_enc_associate(v, oci8_encoding);
726
+ return rb_str_conv_enc(v, oci8_encoding, rb_default_internal_encoding());
727
+ } else {
728
+ /* ASCII-8BIT */
729
+ return v;
730
+ }
731
+ }
732
+
733
+ /*
734
+ * @overload write(data)
735
+ *
736
+ * Writes +data+ to LOB.
737
+ *
738
+ * @param [String] data
739
+ * @return [Integer] number of characters written if +self+ is a {CLOB} or a {NCLOB}.
740
+ * number of bytes written if +self+ is a {BLOB} or a {BFILE}.
741
+ */
742
+ static VALUE oci8_lob_write(VALUE self, VALUE data)
743
+ {
744
+ oci8_lob_t *lob = TO_LOB(self);
745
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
746
+ volatile VALUE str;
747
+ ub8 byte_amt;
748
+ ub8 char_amt;
749
+
750
+ if (TYPE(data) != T_STRING) {
751
+ str = rb_obj_as_string(data);
752
+ } else {
753
+ str = data;
754
+ }
755
+ if (lob->lobtype == ACI_TEMP_CLOB) {
756
+ str = rb_str_export_to_enc(str, oci8_encoding);
757
+ }
758
+ byte_amt = RSTRING_LEN(str);
759
+ if (byte_amt == 0) {
760
+ /* to avoid ORA-24801: illegal parameter value in ACI lob function */
761
+ return INT2FIX(0);
762
+ }
763
+ char_amt = 0;
764
+ chker2(ACILobWrite2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &byte_amt, &char_amt, lob->pos + 1, RSTRING_PTR(str), byte_amt, ACI_ONE_PIECE, NULL, NULL, 0, lob->csfrm),
765
+ &svcctx->base);
766
+ RB_GC_GUARD(str);
767
+ if (lob->lobtype == ACI_TEMP_CLOB) {
768
+ lob->pos += char_amt;
769
+ return UINT2NUM(char_amt);
770
+ } else {
771
+ lob->pos += byte_amt;
772
+ return UINT2NUM(byte_amt);
773
+ }
774
+ }
775
+
776
+ /*
777
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
778
+ * @private
779
+ */
780
+ static VALUE oci8_lob_get_sync(VALUE self)
781
+ {
782
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
783
+ return Qfalse;
784
+ }
785
+
786
+ /*
787
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
788
+ * @private
789
+ */
790
+ static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
791
+ {
792
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
793
+ return b;
794
+ }
795
+
796
+ /*
797
+ * @deprecated LOB#flush had not worked by mistake. Do nothing now.
798
+ * @private
799
+ */
800
+ static VALUE oci8_lob_flush(VALUE self)
801
+ {
802
+ rb_warning("LOB#flush had not worked by mistake. Do nothing now.");
803
+ return self;
804
+ }
805
+
806
+ /*
807
+ * Returns the chunk size of a LOB.
808
+ *
809
+ * @see http://docs.oracle.com/database/121/ARPLS/d_lob.htm#ARPLS66706 DBMS_LOB.GETCHUNKSIZE
810
+ * @return [Integer]
811
+ */
812
+ static VALUE oci8_lob_get_chunk_size(VALUE self)
813
+ {
814
+ oci8_lob_t *lob = TO_LOB(self);
815
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
816
+ ub4 len;
817
+
818
+ chker2(ACILobGetChunkSize_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len),
819
+ &svcctx->base);
820
+ return UINT2NUM(len);
821
+ }
822
+
823
+ static VALUE oci8_lob_clone(VALUE self)
824
+ {
825
+ oci8_lob_t *lob = TO_LOB(self);
826
+ oci8_lob_t *newlob;
827
+ VALUE newobj = lob->svcctx ? lob->svcctx->base.self : Qnil;
828
+ boolean is_temporary;
829
+
830
+ newobj = rb_class_new_instance(1, &newobj, CLASS_OF(self));
831
+ newlob = DATA_PTR(newobj);
832
+ if (ACILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == ACI_SUCCESS
833
+ && is_temporary) {
834
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
835
+ chker2(ACILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob),
836
+ &svcctx->base);
837
+ } else {
838
+ chker2(ACILobAssign(oci8_envhp, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob), &lob->base);
839
+ }
840
+ return newobj;
841
+ }
842
+
843
+ static void oci8_bfile_get_name(VALUE self, VALUE *dir_alias_p, VALUE *filename_p)
844
+ {
845
+ int need_get = 0;
846
+ if (dir_alias_p != NULL) {
847
+ *dir_alias_p = rb_ivar_get(self, id_dir_alias);
848
+ if (NIL_P(*dir_alias_p))
849
+ need_get = 1;
850
+ }
851
+ if (filename_p != NULL) {
852
+ *filename_p = rb_ivar_get(self, id_filename);
853
+ if (NIL_P(*filename_p))
854
+ need_get = 1;
855
+ }
856
+ if (need_get) {
857
+ oci8_lob_t *lob = TO_LOB(self);
858
+ char d_buf[31];
859
+ ub2 d_length = sizeof(d_buf);
860
+ char f_buf[256];
861
+ ub2 f_length = sizeof(f_buf);
862
+ VALUE dir_alias;
863
+ VALUE filename;
864
+
865
+ chker2(ACILobFileGetName(oci8_envhp, oci8_errhp, lob->base.hp.lob, TO_ORATEXT(d_buf), &d_length, TO_ORATEXT(f_buf), &f_length),
866
+ &lob->base);
867
+ dir_alias = rb_external_str_new_with_enc(d_buf, d_length, oci8_encoding);
868
+ filename = rb_external_str_new_with_enc(f_buf, f_length, oci8_encoding);
869
+ rb_ivar_set(self, id_dir_alias, dir_alias);
870
+ rb_ivar_set(self, id_filename, filename);
871
+ if (dir_alias_p != NULL) {
872
+ *dir_alias_p = dir_alias;
873
+ }
874
+ if (filename_p != NULL) {
875
+ *filename_p = filename;
876
+ }
877
+ }
878
+ }
879
+
880
+ static void oci8_bfile_set_name(VALUE self, VALUE dir_alias, VALUE filename)
881
+ {
882
+ oci8_lob_t *lob = TO_LOB(self);
883
+
884
+ bfile_close(lob);
885
+ if (RSTRING_LEN(dir_alias) > UB2MAXVAL) {
886
+ rb_raise(rb_eRuntimeError, "dir_alias is too long.");
887
+ }
888
+ if (RSTRING_LEN(filename) > UB2MAXVAL) {
889
+ rb_raise(rb_eRuntimeError, "filename is too long.");
890
+ }
891
+ chker2(ACILobFileSetName(oci8_envhp, oci8_errhp, &lob->base.hp.lob,
892
+ RSTRING_ORATEXT(dir_alias), (ub2)RSTRING_LEN(dir_alias),
893
+ RSTRING_ORATEXT(filename), (ub2)RSTRING_LEN(filename)),
894
+ &lob->base);
895
+ }
896
+
897
+ /*
898
+ * @overload initialize(conn, directory = nil, filename = nil)
899
+ *
900
+ * Creates a BFILE object.
901
+ * This is correspond to {BFILENAME}[https://docs.oracle.com/database/121/SQLRF/functions020.htm].
902
+ *
903
+ * @param [ACI8] conn
904
+ * @param [String] directory a directory object created by
905
+ * {"CREATE DIRECTORY"}[http://docs.oracle.com/database/121/SQLRF/statements_5008.htm].
906
+ * @param [String] filename
907
+ * @return [ACI8::BFILE]
908
+ */
909
+ static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
910
+ {
911
+ oci8_lob_t *lob = TO_LOB(self);
912
+ VALUE svc;
913
+ VALUE dir_alias;
914
+ VALUE filename;
915
+ oci8_svcctx_t *svcctx;
916
+ int rv;
917
+
918
+ rb_scan_args(argc, argv, "12", &svc, &dir_alias, &filename);
919
+ svcctx = oci8_get_svcctx(svc);
920
+ rv = ACIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, ACI_DTYPE_LOB, 0, NULL);
921
+ if (rv != ACI_SUCCESS) {
922
+ oci8_env_raise(oci8_envhp, rv);
923
+ }
924
+ lob->base.type = ACI_DTYPE_LOB;
925
+ lob->pos = 0;
926
+ lob->csfrm = SQLCS_IMPLICIT;
927
+ lob->lobtype = ACI_TEMP_BLOB;
928
+ lob->state = S_BFILE_CLOSE;
929
+ if (argc != 1) {
930
+ OCI8SafeStringValue(dir_alias);
931
+ OCI8SafeStringValue(filename);
932
+ oci8_bfile_set_name(self, dir_alias, filename);
933
+ }
934
+ oci8_link_to_parent(&lob->base, &svcctx->base);
935
+ lob->svcctx = svcctx;
936
+ return Qnil;
937
+ }
938
+
939
+ /*
940
+ * @overload dir_alias
941
+ *
942
+ * Returns the directory object name.
943
+ *
944
+ * @return [String]
945
+ */
946
+ static VALUE oci8_bfile_get_dir_alias(VALUE self)
947
+ {
948
+ VALUE dir_alias;
949
+
950
+ oci8_bfile_get_name(self, &dir_alias, NULL);
951
+ return dir_alias;
952
+ }
953
+
954
+ /*
955
+ * @overload filename
956
+ *
957
+ * Returns the file name.
958
+ *
959
+ * @return [String]
960
+ */
961
+ static VALUE oci8_bfile_get_filename(VALUE self)
962
+ {
963
+ VALUE filename;
964
+
965
+ oci8_bfile_get_name(self, NULL, &filename);
966
+ return filename;
967
+ }
968
+
969
+ /*
970
+ * @overload dir_alias=(dir_alias)
971
+ *
972
+ * Changes the directory object name.
973
+ *
974
+ * @param [String] dir_alias
975
+ */
976
+ static VALUE oci8_bfile_set_dir_alias(VALUE self, VALUE dir_alias)
977
+ {
978
+ VALUE filename;
979
+
980
+ OCI8SafeStringValue(dir_alias);
981
+ oci8_bfile_get_name(self, NULL, &filename);
982
+ oci8_bfile_set_name(self, dir_alias, filename);
983
+ rb_ivar_set(self, id_dir_alias, dir_alias);
984
+ return dir_alias;
985
+ }
986
+
987
+ /*
988
+ * @overload filename=(filename)
989
+ *
990
+ * Changes the file name.
991
+ *
992
+ * @param [String] filename
993
+ */
994
+ static VALUE oci8_bfile_set_filename(VALUE self, VALUE filename)
995
+ {
996
+ VALUE dir_alias;
997
+
998
+ OCI8SafeStringValue(filename);
999
+ oci8_bfile_get_name(self, &dir_alias, NULL);
1000
+ oci8_bfile_set_name(self, dir_alias, filename);
1001
+ rb_ivar_set(self, id_filename, filename);
1002
+ return filename;
1003
+ }
1004
+
1005
+ /*
1006
+ * @overload exists?
1007
+ *
1008
+ * Returns <code>true</code> when the BFILE exists on the server's operating system.
1009
+ */
1010
+ static VALUE oci8_bfile_exists_p(VALUE self)
1011
+ {
1012
+ oci8_lob_t *lob = TO_LOB(self);
1013
+ oci8_svcctx_t *svcctx = check_svcctx(lob);
1014
+ boolean flag;
1015
+
1016
+ chker2(ACILobFileExists_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &flag),
1017
+ &svcctx->base);
1018
+ return flag ? Qtrue : Qfalse;
1019
+ }
1020
+
1021
+ /*
1022
+ * Raises <code>RuntimeError</code> always.
1023
+ *
1024
+ * @raise [RuntimeError] cannot modify a read-only BFILE object
1025
+ */
1026
+ static VALUE oci8_bfile_error(VALUE self, VALUE dummy)
1027
+ {
1028
+ rb_raise(rb_eRuntimeError, "cannot modify a read-only BFILE object");
1029
+ }
1030
+
1031
+ /*
1032
+ * bind_clob/blob/bfile
1033
+ */
1034
+
1035
+ typedef struct {
1036
+ oci8_bind_data_type_t bind;
1037
+ VALUE *klass;
1038
+ } oci8_bind_lob_data_type_t;
1039
+
1040
+ static VALUE bind_lob_get(oci8_bind_t *obind, void *data, void *null_struct)
1041
+ {
1042
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
1043
+ return oci8_lob_clone(oho->obj);
1044
+ }
1045
+
1046
+ static void bind_lob_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
1047
+ {
1048
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
1049
+ const oci8_handle_data_type_t *bind_data_type = obind->base.data_type;
1050
+ const oci8_handle_data_type_t *lob_data_type = bind_data_type->rb_data_type.data;
1051
+ oci8_base_t *h = oci8_check_typeddata(val, lob_data_type, 1);
1052
+ oho->hp = h->hp.ptr;
1053
+ RB_OBJ_WRITE(obind->base.self, &oho->obj, val);
1054
+ }
1055
+
1056
+ static void bind_lob_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
1057
+ {
1058
+ obind->value_sz = sizeof(void *);
1059
+ obind->alloc_sz = sizeof(oci8_hp_obj_t);
1060
+ }
1061
+
1062
+ static void bind_lob_init_elem(oci8_bind_t *obind, VALUE svc)
1063
+ {
1064
+ const oci8_bind_lob_data_type_t *data_type = (const oci8_bind_lob_data_type_t *)obind->base.data_type;
1065
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
1066
+ oci8_base_t *h;
1067
+ ub4 idx = 0;
1068
+
1069
+ do {
1070
+ oho[idx].obj = rb_class_new_instance(1, &svc, *data_type->klass);
1071
+ RB_OBJ_WRITTEN(obind->base.self, Qundef, oho[idx].obj);
1072
+ h = DATA_PTR(oho[idx].obj);
1073
+ oho[idx].hp = h->hp.ptr;
1074
+ } while (++idx < obind->maxar_sz);
1075
+ }
1076
+
1077
+ static void bind_lob_post_bind_hook_for_nclob(oci8_bind_t *obind)
1078
+ {
1079
+ ub1 csfrm = SQLCS_NCHAR;
1080
+
1081
+ chker2(ACIAttrSet(obind->base.hp.ptr, obind->base.type, (void*)&csfrm, 0, ACI_ATTR_CHARSET_FORM, oci8_errhp),
1082
+ &obind->base);
1083
+ }
1084
+
1085
+ static const oci8_bind_lob_data_type_t bind_clob_data_type = {
1086
+ {
1087
+ {
1088
+ {
1089
+ "STACI::BindType::CLOB",
1090
+ {
1091
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1092
+ oci8_handle_cleanup,
1093
+ oci8_handle_size,
1094
+ },
1095
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_clob_data_type,
1096
+ #ifdef RUBY_TYPED_WB_PROTECTED
1097
+ RUBY_TYPED_WB_PROTECTED,
1098
+ #endif
1099
+ },
1100
+ oci8_bind_free,
1101
+ sizeof(oci8_bind_t)
1102
+ },
1103
+ bind_lob_get,
1104
+ bind_lob_set,
1105
+ bind_lob_init,
1106
+ bind_lob_init_elem,
1107
+ NULL,
1108
+ SQLT_CLOB
1109
+ },
1110
+ &cOCI8CLOB
1111
+ };
1112
+
1113
+ static VALUE bind_clob_alloc(VALUE klass)
1114
+ {
1115
+ return oci8_allocate_typeddata(klass, &bind_clob_data_type.bind.base);
1116
+ }
1117
+
1118
+ static const oci8_bind_lob_data_type_t bind_nclob_data_type = {
1119
+ {
1120
+ {
1121
+ {
1122
+ "STACI::BindType::NCLOB",
1123
+ {
1124
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1125
+ oci8_handle_cleanup,
1126
+ oci8_handle_size,
1127
+ },
1128
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_nclob_data_type,
1129
+ #ifdef RUBY_TYPED_WB_PROTECTED
1130
+ RUBY_TYPED_WB_PROTECTED,
1131
+ #endif
1132
+ },
1133
+ oci8_bind_free,
1134
+ sizeof(oci8_bind_t)
1135
+ },
1136
+ bind_lob_get,
1137
+ bind_lob_set,
1138
+ bind_lob_init,
1139
+ bind_lob_init_elem,
1140
+ NULL,
1141
+ SQLT_CLOB,
1142
+ bind_lob_post_bind_hook_for_nclob,
1143
+ },
1144
+ &cOCI8NCLOB
1145
+ };
1146
+
1147
+ static VALUE bind_nclob_alloc(VALUE klass)
1148
+ {
1149
+ return oci8_allocate_typeddata(klass, &bind_nclob_data_type.bind.base);
1150
+ }
1151
+
1152
+ static const oci8_bind_lob_data_type_t bind_blob_data_type = {
1153
+ {
1154
+ {
1155
+ {
1156
+ "STACI::BindType::BLOB",
1157
+ {
1158
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1159
+ oci8_handle_cleanup,
1160
+ oci8_handle_size,
1161
+ },
1162
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_blob_data_type,
1163
+ #ifdef RUBY_TYPED_WB_PROTECTED
1164
+ RUBY_TYPED_WB_PROTECTED,
1165
+ #endif
1166
+ },
1167
+ oci8_bind_free,
1168
+ sizeof(oci8_bind_t)
1169
+ },
1170
+ bind_lob_get,
1171
+ bind_lob_set,
1172
+ bind_lob_init,
1173
+ bind_lob_init_elem,
1174
+ NULL,
1175
+ SQLT_BLOB
1176
+ },
1177
+ &cOCI8BLOB
1178
+ };
1179
+
1180
+ static VALUE bind_blob_alloc(VALUE klass)
1181
+ {
1182
+ return oci8_allocate_typeddata(klass, &bind_blob_data_type.bind.base);
1183
+ }
1184
+
1185
+ static const oci8_bind_lob_data_type_t bind_bfile_data_type = {
1186
+ {
1187
+ {
1188
+ {
1189
+ "STACI::BindType::BFILE",
1190
+ {
1191
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1192
+ oci8_handle_cleanup,
1193
+ oci8_handle_size,
1194
+ },
1195
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_bfile_data_type,
1196
+ #ifdef RUBY_TYPED_WB_PROTECTED
1197
+ RUBY_TYPED_WB_PROTECTED,
1198
+ #endif
1199
+ },
1200
+ oci8_bind_free,
1201
+ sizeof(oci8_bind_t)
1202
+ },
1203
+ bind_lob_get,
1204
+ bind_lob_set,
1205
+ bind_lob_init,
1206
+ bind_lob_init_elem,
1207
+ NULL,
1208
+ SQLT_BFILE
1209
+ },
1210
+ &cOCI8BFILE
1211
+ };
1212
+
1213
+ static VALUE bind_bfile_alloc(VALUE klass)
1214
+ {
1215
+ return oci8_allocate_typeddata(klass, &bind_bfile_data_type.bind.base);
1216
+ }
1217
+
1218
+ void Init_oci8_lob(VALUE cOCI8)
1219
+ {
1220
+ id_plus = rb_intern("+");
1221
+ id_dir_alias = rb_intern("@dir_alias");
1222
+ id_filename = rb_intern("@filename");
1223
+ seek_set = rb_eval_string("::IO::SEEK_SET");
1224
+ seek_cur = rb_eval_string("::IO::SEEK_CUR");
1225
+ seek_end = rb_eval_string("::IO::SEEK_END");
1226
+
1227
+ #if 0
1228
+ /* for yard */
1229
+ cOCIHandle = rb_define_class("ACIHandle", rb_cObject);
1230
+ cOCI8 = rb_define_class("STACI", cOCIHandle);
1231
+ cOCI8LOB = rb_define_class_under(cOCI8, "LOB", cOCIHandle);
1232
+ cOCI8CLOB = rb_define_class_under(cOCI8, "CLOB", cOCI8LOB);
1233
+ cOCI8NCLOB = rb_define_class_under(cOCI8, "NCLOB", cOCI8LOB);
1234
+ cOCI8BLOB = rb_define_class_under(cOCI8, "BLOB", cOCI8LOB);
1235
+ cOCI8BFILE = rb_define_class_under(cOCI8, "BFILE", cOCI8LOB);
1236
+ #endif
1237
+
1238
+ cOCI8LOB = oci8_define_class_under(cOCI8, "LOB", &oci8_lob_data_type, oci8_lob_alloc);
1239
+ cOCI8CLOB = oci8_define_class_under(cOCI8, "CLOB", &oci8_clob_data_type, oci8_clob_alloc);
1240
+ cOCI8NCLOB = oci8_define_class_under(cOCI8, "NCLOB", &oci8_nclob_data_type, oci8_nclob_alloc);
1241
+ cOCI8BLOB = oci8_define_class_under(cOCI8, "BLOB", &oci8_blob_data_type, oci8_blob_alloc);
1242
+ cOCI8BFILE = oci8_define_class_under(cOCI8, "BFILE", &oci8_bfile_data_type, oci8_bfile_alloc);
1243
+
1244
+ rb_define_method(cOCI8CLOB, "initialize", oci8_clob_initialize, -1);
1245
+ rb_define_method(cOCI8NCLOB, "initialize", oci8_nclob_initialize, -1);
1246
+ rb_define_method(cOCI8BLOB, "initialize", oci8_blob_initialize, -1);
1247
+ rb_define_method(cOCI8LOB, "available?", oci8_lob_available_p, 0);
1248
+ rb_define_method(cOCI8LOB, "size", oci8_lob_get_size, 0);
1249
+ rb_define_method(cOCI8LOB, "pos", oci8_lob_get_pos, 0);
1250
+ rb_define_alias(cOCI8LOB, "tell", "pos");
1251
+ rb_define_method(cOCI8LOB, "eof?", oci8_lob_eof_p, 0);
1252
+ rb_define_method(cOCI8LOB, "seek", oci8_lob_seek, -1);
1253
+ rb_define_method(cOCI8LOB, "rewind", oci8_lob_rewind, 0);
1254
+ rb_define_method(cOCI8LOB, "truncate", oci8_lob_truncate, 1);
1255
+ rb_define_method(cOCI8LOB, "size=", oci8_lob_set_size, 1);
1256
+ rb_define_method(cOCI8LOB, "read", oci8_lob_read, -1);
1257
+ rb_define_method(cOCI8LOB, "write", oci8_lob_write, 1);
1258
+ rb_define_method(cOCI8LOB, "close", oci8_lob_close, 0);
1259
+ rb_define_method(cOCI8LOB, "sync", oci8_lob_get_sync, 0);
1260
+ rb_define_method(cOCI8LOB, "sync=", oci8_lob_set_sync, 1);
1261
+ rb_define_method(cOCI8LOB, "flush", oci8_lob_flush, 0);
1262
+ rb_define_method(cOCI8LOB, "chunk_size", oci8_lob_get_chunk_size, 0);
1263
+
1264
+ rb_define_method(cOCI8BFILE, "initialize", oci8_bfile_initialize, -1);
1265
+ rb_define_method(cOCI8BFILE, "dir_alias", oci8_bfile_get_dir_alias, 0);
1266
+ rb_define_method(cOCI8BFILE, "filename", oci8_bfile_get_filename, 0);
1267
+ rb_define_method(cOCI8BFILE, "dir_alias=", oci8_bfile_set_dir_alias, 1);
1268
+ rb_define_method(cOCI8BFILE, "filename=", oci8_bfile_set_filename, 1);
1269
+ rb_define_method(cOCI8BFILE, "exists?", oci8_bfile_exists_p, 0);
1270
+ rb_define_method(cOCI8BFILE, "truncate", oci8_bfile_error, 1);
1271
+ rb_define_method(cOCI8BFILE, "size=", oci8_bfile_error, 1);
1272
+ rb_define_method(cOCI8BFILE, "write", oci8_bfile_error, 1);
1273
+
1274
+ oci8_define_bind_class("CLOB", &bind_clob_data_type.bind, bind_clob_alloc);
1275
+ oci8_define_bind_class("NCLOB", &bind_nclob_data_type.bind, bind_nclob_alloc);
1276
+ oci8_define_bind_class("BLOB", &bind_blob_data_type.bind, bind_blob_alloc);
1277
+ oci8_define_bind_class("BFILE", &bind_bfile_data_type.bind, bind_bfile_alloc);
1278
+ }