ruby-oci8 1.0.7 → 2.0.0

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 (89) hide show
  1. data/ChangeLog +1254 -390
  2. data/Makefile +10 -13
  3. data/README +56 -385
  4. data/VERSION +1 -1
  5. data/dist-files +26 -27
  6. data/ext/oci8/.document +1 -0
  7. data/ext/oci8/MANIFEST +0 -4
  8. data/ext/oci8/apiwrap.c.tmpl +172 -0
  9. data/ext/oci8/apiwrap.h.tmpl +61 -0
  10. data/ext/oci8/apiwrap.rb +91 -0
  11. data/ext/oci8/apiwrap.yml +1243 -0
  12. data/ext/oci8/attr.c +124 -384
  13. data/ext/oci8/bind.c +472 -164
  14. data/ext/oci8/encoding.c +196 -0
  15. data/ext/oci8/env.c +84 -253
  16. data/ext/oci8/error.c +196 -127
  17. data/ext/oci8/extconf.rb +82 -59
  18. data/ext/oci8/lob.c +710 -370
  19. data/ext/oci8/metadata.c +359 -0
  20. data/ext/oci8/object.c +622 -0
  21. data/ext/oci8/oci8.c +577 -161
  22. data/ext/oci8/oci8.h +354 -258
  23. data/ext/oci8/oci8lib.c +493 -0
  24. data/ext/oci8/ocidatetime.c +473 -0
  25. data/ext/oci8/ocinumber.c +1123 -24
  26. data/ext/oci8/oraconf.rb +72 -106
  27. data/ext/oci8/oradate.c +511 -321
  28. data/ext/oci8/stmt.c +752 -572
  29. data/ext/oci8/win32.c +131 -0
  30. data/ext/oci8/xmldb.c +383 -0
  31. data/lib/.document +2 -0
  32. data/lib/dbd/OCI8.rb +2 -17
  33. data/lib/oci8.rb.in +41 -1622
  34. data/lib/oci8/.document +5 -0
  35. data/lib/oci8/compat.rb +108 -0
  36. data/lib/oci8/datetime.rb +489 -0
  37. data/lib/oci8/encoding-init.rb +40 -0
  38. data/lib/oci8/encoding.yml +537 -0
  39. data/lib/oci8/metadata.rb +2077 -0
  40. data/lib/oci8/object.rb +548 -0
  41. data/lib/oci8/oci8.rb +773 -0
  42. data/lib/oci8/oracle_version.rb +144 -0
  43. data/metaconfig +3 -3
  44. data/ruby-oci8.gemspec +5 -5
  45. data/setup.rb +4 -4
  46. data/test/config.rb +64 -84
  47. data/test/test_all.rb +14 -21
  48. data/test/test_array_dml.rb +317 -0
  49. data/test/test_bind_raw.rb +18 -25
  50. data/test/test_bind_time.rb +78 -91
  51. data/test/test_break.rb +37 -35
  52. data/test/test_clob.rb +33 -89
  53. data/test/test_connstr.rb +5 -4
  54. data/test/test_datetime.rb +469 -0
  55. data/test/test_dbi.rb +99 -60
  56. data/test/test_dbi_clob.rb +3 -8
  57. data/test/test_metadata.rb +65 -51
  58. data/test/test_oci8.rb +151 -55
  59. data/test/test_oracle_version.rb +70 -0
  60. data/test/test_oradate.rb +76 -83
  61. data/test/test_oranumber.rb +405 -71
  62. data/test/test_rowid.rb +6 -11
  63. metadata +31 -32
  64. data/NEWS +0 -420
  65. data/ext/oci8/const.c +0 -165
  66. data/ext/oci8/define.c +0 -53
  67. data/ext/oci8/describe.c +0 -81
  68. data/ext/oci8/descriptor.c +0 -39
  69. data/ext/oci8/handle.c +0 -273
  70. data/ext/oci8/oranumber.c +0 -445
  71. data/ext/oci8/param.c +0 -37
  72. data/ext/oci8/server.c +0 -182
  73. data/ext/oci8/session.c +0 -99
  74. data/ext/oci8/svcctx.c +0 -238
  75. data/ruby-oci8.spec +0 -62
  76. data/support/README +0 -4
  77. data/support/runit/assert.rb +0 -281
  78. data/support/runit/cui/testrunner.rb +0 -101
  79. data/support/runit/error.rb +0 -4
  80. data/support/runit/method_mappable.rb +0 -20
  81. data/support/runit/robserver.rb +0 -25
  82. data/support/runit/setuppable.rb +0 -15
  83. data/support/runit/teardownable.rb +0 -16
  84. data/support/runit/testcase.rb +0 -113
  85. data/support/runit/testfailure.rb +0 -25
  86. data/support/runit/testresult.rb +0 -121
  87. data/support/runit/testsuite.rb +0 -43
  88. data/support/runit/version.rb +0 -3
  89. data/test/test_describe.rb +0 -137
@@ -1,403 +1,743 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
1
2
  #include "oci8.h"
2
3
 
3
- static VALUE sym_file_readonly;
4
+ static ID id_plus;
5
+ static ID id_dir_alias;
6
+ static ID id_filename;
7
+ static VALUE cOCI8LOB;
8
+ static VALUE cOCI8CLOB;
9
+ static VALUE cOCI8NCLOB;
10
+ static VALUE cOCI8BLOB;
11
+ static VALUE cOCI8BFILE;
12
+ static VALUE seek_set;
13
+ static VALUE seek_cur;
14
+ static VALUE seek_end;
15
+
16
+ enum state {
17
+ S_NO_OPEN_CLOSE,
18
+ S_OPEN,
19
+ S_CLOSE,
20
+ S_BFILE_CLOSE,
21
+ S_BFILE_OPEN,
22
+ };
23
+ typedef struct {
24
+ oci8_base_t base;
25
+ VALUE svc;
26
+ ub4 pos;
27
+ int char_width;
28
+ ub1 csfrm;
29
+ enum state state;
30
+ } oci8_lob_t;
31
+
32
+ static VALUE oci8_lob_write(VALUE self, VALUE data);
33
+
34
+ static VALUE oci8_make_lob(VALUE klass, oci8_svcctx_t *svcctx, OCILobLocator *s)
35
+ {
36
+ oci8_lob_t *lob;
37
+ VALUE lob_obj;
38
+
39
+ lob_obj = rb_funcall(klass, oci8_id_new, 1, svcctx->base.self);
40
+ lob = DATA_PTR(lob_obj);
41
+ /* If 's' is a temporary lob, use OCILobLocatorAssign instead. */
42
+ oci_lc(OCILobAssign(oci8_envhp, oci8_errhp, s, &lob->base.hp.lob));
43
+ return lob_obj;
44
+ }
4
45
 
5
- #ifndef OCI8_USE_CALLBACK_LOB_READ
6
- static VALUE oci8_lob_set_char_width(VALUE self, VALUE vsize)
46
+ VALUE oci8_make_clob(oci8_svcctx_t *svcctx, OCILobLocator *s)
7
47
  {
8
- oci8_handle_t *h;
9
- int size;
48
+ return oci8_make_lob(cOCI8CLOB, svcctx, s);
49
+ }
10
50
 
11
- Get_Handle(self, h); /* 0 */
12
- size = NUM2INT(vsize); /* 1 */
51
+ VALUE oci8_make_nclob(oci8_svcctx_t *svcctx, OCILobLocator *s)
52
+ {
53
+ return oci8_make_lob(cOCI8NCLOB, svcctx, s);
54
+ }
13
55
 
14
- if (size <= 0)
15
- rb_raise(rb_eArgError, "size must be more than one.");
16
- h->u.lob_locator.char_width = size;
17
- return vsize;
56
+ VALUE oci8_make_blob(oci8_svcctx_t *svcctx, OCILobLocator *s)
57
+ {
58
+ return oci8_make_lob(cOCI8BLOB, svcctx, s);
18
59
  }
19
- #endif
20
60
 
21
- static VALUE oci8_lob_is_initialized_p(VALUE self, VALUE venv)
61
+ VALUE oci8_make_bfile(oci8_svcctx_t *svcctx, OCILobLocator *s)
22
62
  {
23
- oci8_handle_t *h;
24
- oci8_handle_t *envh;
25
- boolean is_initialized;
26
- sword rv;
63
+ return oci8_make_lob(cOCI8BFILE, svcctx, s);
64
+ }
27
65
 
28
- Get_Handle(self, h); /* 0 */
29
- Check_Handle(venv, OCIEnv, envh); /* 1 */
66
+ static void oci8_lob_mark(oci8_base_t *base)
67
+ {
68
+ oci8_lob_t *lob = (oci8_lob_t *)base;
69
+ rb_gc_mark(lob->svc);
70
+ }
30
71
 
31
- rv = OCILobLocatorIsInit(envh->hp, h->errhp, h->hp, &is_initialized);
32
- if (rv != OCI_SUCCESS)
33
- oci8_raise(h->errhp, rv, NULL);
34
- return is_initialized ? Qtrue : Qfalse;
72
+ static void oci8_lob_free(oci8_base_t *base)
73
+ {
74
+ oci8_lob_t *lob = (oci8_lob_t *)base;
75
+ lob->svc = Qnil;
35
76
  }
36
77
 
78
+ static oci8_base_class_t oci8_lob_class = {
79
+ oci8_lob_mark,
80
+ oci8_lob_free,
81
+ sizeof(oci8_lob_t),
82
+ };
37
83
 
38
- /*
39
- =begin
40
- --- OCILobLocator#GetLength()
41
- get the length of LOB.
42
- counts by bytes for BLOB, by charactors for CLOB.
43
- =end
44
- */
45
- static VALUE oci8_lob_get_length(VALUE self, VALUE vsvc)
84
+ static ub4 oci8_lob_get_length(oci8_lob_t *lob)
46
85
  {
47
- oci8_handle_t *h;
48
- oci8_handle_t *svch;
49
- ub4 len;
50
- sword rv;
86
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
87
+ ub4 len;
88
+
89
+ oci_lc(OCILobGetLength_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len));
90
+ return len;
91
+ }
92
+
93
+ static void lob_open(oci8_lob_t *lob)
94
+ {
95
+ if (lob->state == S_CLOSE) {
96
+ if (have_OCILobOpen_nb) {
97
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
98
+
99
+ oci_lc(OCILobOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_DEFAULT));
100
+ }
101
+ lob->state = S_OPEN;
102
+ }
103
+ }
51
104
 
52
- Get_Handle(self, h); /* 0 */
53
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
105
+ static void lob_close(oci8_lob_t *lob)
106
+ {
107
+ if (lob->state == S_OPEN) {
108
+ if (have_OCILobClose_nb) {
109
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
54
110
 
55
- rv = OCILobGetLength(svch->hp, h->errhp, h->hp, &len);
56
- if (rv != OCI_SUCCESS)
57
- oci8_raise(h->errhp, rv, NULL);
58
- return UINT2NUM(len);
111
+ oci_lc(OCILobClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob));
112
+ }
113
+ lob->state = S_CLOSE;
114
+ }
59
115
  }
60
116
 
61
- #ifdef HAVE_OCILOBGETCHUNKSIZE
62
- static VALUE oci8_lob_get_chunk_size(VALUE self, VALUE vsvc)
117
+ static void bfile_close(oci8_lob_t *lob)
63
118
  {
64
- oci8_handle_t *h;
65
- oci8_handle_t *svch;
66
- ub4 len;
67
- sword rv;
119
+ if (lob->state == S_BFILE_OPEN) {
120
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
68
121
 
69
- Get_Handle(self, h); /* 0 */
70
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
122
+ oci_lc(OCILobFileClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob));
123
+ lob->state = S_BFILE_CLOSE;
124
+ }
125
+ }
71
126
 
72
- rv = OCILobGetChunkSize(svch->hp, h->errhp, h->hp, &len);
73
- if (rv != OCI_SUCCESS)
74
- oci8_raise(h->errhp, rv, NULL);
75
- return UINT2NUM(len);
127
+ static VALUE oci8_lob_close(VALUE self)
128
+ {
129
+ oci8_lob_t *lob = DATA_PTR(self);
130
+ lob_close(lob);
131
+ oci8_base_free(DATA_PTR(self));
132
+ return self;
76
133
  }
77
- #endif
78
134
 
79
- #ifdef OCI8_USE_CALLBACK_LOB_READ
80
- static sb4 oci8_callback_lob_read(dvoid *ctxp, CONST dvoid *bufp, ub4 len, ub1 piece)
135
+ static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm, ub1 lobtype)
81
136
  {
82
- VALUE v = *((VALUE *)ctxp);
137
+ oci8_lob_t *lob = DATA_PTR(self);
138
+ VALUE svc;
139
+ VALUE val;
140
+ sword rv;
141
+
142
+ rb_scan_args(argc, argv, "11", &svc, &val);
143
+ TO_SVCCTX(svc); /* check argument type */
144
+ rv = OCIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, OCI_DTYPE_LOB, 0, NULL);
145
+ if (rv != OCI_SUCCESS)
146
+ oci8_env_raise(oci8_envhp, rv);
147
+ lob->base.type = OCI_DTYPE_LOB;
148
+ lob->svc = svc;
149
+ lob->pos = 0;
150
+ lob->char_width = 1;
151
+ lob->csfrm = csfrm;
152
+ lob->state = S_NO_OPEN_CLOSE;
153
+ oci8_link_to_parent((oci8_base_t*)lob, (oci8_base_t*)DATA_PTR(svc));
154
+ if (!NIL_P(val)) {
155
+ if (have_OCILobCreateTemporary_nb) {
156
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
157
+ OCI8StringValue(val);
158
+ oci_lc(OCILobCreateTemporary_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, 0, csfrm, lobtype, TRUE, OCI_DURATION_SESSION));
159
+ oci8_lob_write(self, val);
160
+ } else {
161
+ rb_raise(rb_eRuntimeError, "creating a temporary lob is not supported on this Oracle version");
162
+ }
163
+ }
164
+ return Qnil;
165
+ }
83
166
 
84
- if (v == Qnil)
85
- v = rb_str_new(bufp, len);
86
- else
87
- v = rb_str_cat(v, bufp, len);
167
+ static VALUE oci8_clob_initialize(int argc, VALUE *argv, VALUE self)
168
+ {
169
+ oci8_lob_do_initialize(argc, argv, self, SQLCS_IMPLICIT, OCI_TEMP_CLOB);
170
+ return Qnil;
171
+ }
88
172
 
89
- *((VALUE *)ctxp) = v;
90
- return OCI_CONTINUE;
173
+ static VALUE oci8_nclob_initialize(int argc, VALUE *argv, VALUE self)
174
+ {
175
+ oci8_lob_do_initialize(argc, argv, self, SQLCS_NCHAR, OCI_TEMP_CLOB);
176
+ return Qnil;
177
+ }
178
+
179
+ static VALUE oci8_blob_initialize(int argc, VALUE *argv, VALUE self)
180
+ {
181
+ oci8_lob_do_initialize(argc, argv, self, SQLCS_IMPLICIT, OCI_TEMP_BLOB);
182
+ return Qnil;
183
+ }
184
+
185
+ static VALUE oci8_lob_set_char_width(VALUE self, VALUE vsize)
186
+ {
187
+ oci8_lob_t *lob = DATA_PTR(self);
188
+ int size;
189
+
190
+ size = NUM2INT(vsize); /* 1 */
191
+
192
+ if (size <= 0)
193
+ rb_raise(rb_eArgError, "size must be more than one.");
194
+ lob->char_width = size;
195
+ return vsize;
196
+ }
197
+
198
+ static VALUE oci8_lob_available_p(VALUE self)
199
+ {
200
+ oci8_lob_t *lob = DATA_PTR(self);
201
+ boolean is_initialized;
202
+
203
+ oci_lc(OCILobLocatorIsInit(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_initialized));
204
+ return is_initialized ? Qtrue : Qfalse;
205
+ }
206
+
207
+ static VALUE oci8_lob_get_size(VALUE self)
208
+ {
209
+ return UB4_TO_NUM(oci8_lob_get_length(DATA_PTR(self)));
210
+ }
211
+
212
+ static VALUE oci8_lob_get_pos(VALUE self)
213
+ {
214
+ oci8_lob_t *lob = DATA_PTR(self);
215
+ return UB4_TO_NUM(lob->pos);
216
+ }
217
+
218
+ static VALUE oci8_lob_eof_p(VALUE self)
219
+ {
220
+ oci8_lob_t *lob = DATA_PTR(self);
221
+ if (oci8_lob_get_length(lob) < lob->pos)
222
+ return Qfalse;
223
+ else
224
+ return Qtrue;
225
+ }
226
+
227
+ static VALUE oci8_lob_seek(int argc, VALUE *argv, VALUE self)
228
+ {
229
+ oci8_lob_t *lob = DATA_PTR(self);
230
+ VALUE position, whence;
231
+
232
+ rb_scan_args(argc, argv, "11", &position, &whence);
233
+ if (argc == 2 && (whence != seek_set && whence != seek_cur && whence != seek_end)) {
234
+ if (FIXNUM_P(whence)) {
235
+ rb_raise(rb_eArgError, "expect IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END but %d",
236
+ FIX2INT(whence));
237
+ } else {
238
+ rb_raise(rb_eArgError, "expect IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END but %s",
239
+ rb_class2name(CLASS_OF(whence)));
240
+ }
241
+ }
242
+ if (whence == seek_cur) {
243
+ position = rb_funcall(UB4_TO_NUM(lob->pos), id_plus, 1, position);
244
+ } else if (whence == seek_end) {
245
+ position = rb_funcall(UB4_TO_NUM(oci8_lob_get_length(lob)), id_plus, 1, position);
246
+ }
247
+ lob->pos = NUM2UINT(position);
248
+ return self;
249
+ }
250
+
251
+ static VALUE oci8_lob_rewind(VALUE self)
252
+ {
253
+ oci8_lob_t *lob = DATA_PTR(self);
254
+ lob->pos = 0;
255
+ return self;
256
+ }
257
+
258
+ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
259
+ {
260
+ oci8_lob_t *lob = DATA_PTR(self);
261
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
262
+
263
+ lob_open(lob);
264
+ oci_lc(OCILobTrim_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2UINT(len)));
265
+ return self;
266
+ }
267
+
268
+ static VALUE oci8_lob_set_size(VALUE self, VALUE len)
269
+ {
270
+ oci8_lob_truncate(self, len);
271
+ return len;
91
272
  }
92
- #endif
93
273
 
94
274
  static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
95
275
  {
96
- VALUE vsvc, voffset, vamt, vcsid, vcsfrm;
97
- oci8_handle_t *h;
98
- oci8_handle_t *svch;
99
- ub4 offset;
100
- ub2 csid;
101
- ub1 csfrm;
102
- ub4 amt;
103
- sword rv;
104
- char buf[8192]; /* 8192 is chunk size in a platform. */
105
- #ifndef OCI8_USE_CALLBACK_LOB_READ
106
- size_t buf_size_in_char;
107
- #endif
108
- VALUE v = Qnil;
109
-
110
- rb_scan_args(argc, argv, "32", &vsvc, &voffset, &vamt, &vcsid, &vcsfrm);
111
- Get_Handle(self, h); /* 0 */
112
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
113
- offset = NUM2UINT(voffset); /* 2 */
114
- amt = NUM2UINT(vamt); /* 3 */
115
- csid = NIL_P(vcsid) ? 0 : NUM2INT(vcsid); /* 4 */
116
- csfrm = NIL_P(vcsfrm) ? SQLCS_IMPLICIT : NUM2INT(vcsfrm); /* 5 */
117
-
118
- #ifdef OCI8_USE_CALLBACK_LOB_READ
119
- /* This raises ORA-24812, when the size of readed data is two or
120
- * three times longer than the size of buf. I couldn't fix it. Thus
121
- * I use polling way instead of callback method.
122
- */
123
- rv = OCILobRead(svch->hp, h->errhp, h->hp, &amt, offset, buf, sizeof(buf), &v, oci8_callback_lob_read, csid, csfrm);
124
- if (rv != OCI_SUCCESS)
125
- oci8_raise(h->errhp, rv, NULL);
126
- #else
127
- /* Disadvantage of polling way in contrast with callback method is
128
- * that it sets 'amt' the number of characters readed, when charset
129
- * is fixed size. For single byte charset or variable size charset,
130
- * it cause no problem because the unit of 'amt' is byte. But for
131
- * fixed size multibyte charset, how can I know the size of a
132
- * character from system? Therefore who want to use fixed size
133
- * multibyte charset must set the size explicitly.
134
- *
135
- * Umm, if I could use callback method, I have no need to care about
136
- * it.
137
- */
138
- buf_size_in_char = sizeof(buf) / h->u.lob_locator.char_width;
139
- do {
140
- /* initialize buf in zeros everytime to check a nul characters. */
141
- memset(buf, 0, sizeof(buf));
142
- rv = OCILobRead(svch->hp, h->errhp, h->hp, &amt, offset, buf, sizeof(buf), NULL, NULL, csid, csfrm);
143
- if (rv != OCI_SUCCESS && rv != OCI_NEED_DATA)
144
- oci8_raise(h->errhp, rv, NULL);
145
-
146
- /* Workaround when using Oracle 10.2.0.4 or 11.1.0.6 client and
147
- * variable-length character set (e.g. AL32UTF8).
148
- *
149
- * When the above mentioned condition, amt may be shorter. So
150
- * amt is increaded until a nul character to know the actually
151
- * read size.
152
- */
153
- while (amt < sizeof(buf) && buf[amt] != '\0') {
154
- amt++;
276
+ oci8_lob_t *lob = DATA_PTR(self);
277
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
278
+ ub4 length;
279
+ ub4 nchar;
280
+ ub4 amt;
281
+ sword rv;
282
+ char buf[8192];
283
+ size_t buf_size_in_char;
284
+ VALUE size;
285
+ VALUE v = rb_ary_new();
286
+
287
+ rb_scan_args(argc, argv, "01", &size);
288
+ length = oci8_lob_get_length(lob);
289
+ if (length <= lob->pos) /* EOF */
290
+ return Qnil;
291
+ length -= lob->pos;
292
+ if (NIL_P(size)) {
293
+ nchar = length; /* read until EOF */
294
+ } else {
295
+ nchar = NUM2UINT(size);
296
+ if (nchar > length)
297
+ nchar = length;
155
298
  }
156
- if (amt == 0)
157
- break;
158
- /* for fixed size charset, amt is the number of characters stored in buf. */
159
- if (amt > buf_size_in_char)
160
- rb_raise(eOCIException, "Too large buffer fetched or you set too large size of a character.");
161
- amt *= h->u.lob_locator.char_width;
162
- if (v == Qnil)
163
- v = rb_str_new(buf, amt);
164
- else
165
- v = rb_str_cat(v, buf, amt);
166
- } while (rv == OCI_NEED_DATA);
167
- #endif
168
- return v;
169
- }
170
-
171
- static VALUE oci8_lob_write(int argc, VALUE *argv, VALUE self)
172
- {
173
- VALUE vsvc, voffset, vbuf, vcsid, vcsfrm;
174
- oci8_handle_t *h;
175
- oci8_handle_t *svch;
176
- oci8_string_t buf;
177
- ub4 offset;
178
- ub2 csid;
179
- ub1 csfrm;
180
- ub4 amt;
181
- sword rv;
182
-
183
- rb_scan_args(argc, argv, "32", &vsvc, &voffset, &vbuf, &vcsid, &vcsfrm);
184
- Get_Handle(self, h); /* 0 */
185
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
186
- offset = NUM2UINT(voffset); /* 2 */
187
- if (TYPE(vbuf) != T_STRING) {
188
- vbuf = rb_obj_as_string(vbuf);
189
- }
190
- RB_GC_GUARD(vbuf);
191
- Get_String(vbuf, buf); /* 3 */
192
- csid = NIL_P(vcsid) ? 0 : NUM2INT(vcsid); /* 4 */
193
- csfrm = NIL_P(vcsfrm) ? SQLCS_IMPLICIT : NUM2INT(vcsfrm); /* 5 */
194
-
195
- amt = buf.len;
196
- rv = OCILobWrite(svch->hp, h->errhp, h->hp, &amt, offset, buf.ptr, buf.len, OCI_ONE_PIECE, NULL, NULL, csid, csfrm);
197
- if (rv != OCI_SUCCESS)
198
- oci8_raise(h->errhp, rv, NULL);
199
- return INT2FIX(amt);
200
- }
201
-
202
- static VALUE oci8_lob_trim(VALUE self, VALUE vsvc, VALUE len)
203
- {
204
- oci8_handle_t *h;
205
- oci8_handle_t *svch;
206
- sword rv;
207
-
208
- Get_Handle(self, h); /* 0 */
209
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
210
-
211
- rv = OCILobTrim(svch->hp, h->errhp, h->hp, NUM2INT(len));
212
- if (rv != OCI_SUCCESS)
213
- oci8_raise(h->errhp, rv, NULL);
214
- return self;
215
- }
216
-
217
- static VALUE oci8_lob_clone(VALUE self, VALUE vsvc)
218
- {
219
- oci8_handle_t *h;
220
- oci8_handle_t *svch;
221
- oci8_handle_t *envh;
222
- oci8_handle_t *newh;
223
- OCILobLocator *hp;
224
- sword rv;
225
-
226
- Get_Handle(self, h); /* 0 */
227
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
228
-
229
- /* get environment handle */
230
- for (envh = h; envh->type != OCI_HTYPE_ENV; envh = envh->parent);
231
- rv = OCIDescriptorAlloc(envh->hp, (void *)&hp, h->type, 0, NULL);
232
- if (rv != OCI_SUCCESS) {
233
- oci8_env_raise(envh->hp, rv);
234
- }
235
- #ifdef HAVE_OCILOBLOCATORASSIGN
236
- /* Oracle 8.1 or upper */
237
- rv = OCILobLocatorAssign(svch->hp, h->errhp, h->hp, &hp);
238
- #else
239
- /* Oracle 8.0 */
240
- rv = OCILobAssign(envh->hp, h->errhp, h->hp, &hp);
241
- #endif
242
- if (rv != OCI_SUCCESS) {
243
- OCIDescriptorFree(hp, h->type);
244
- oci8_raise(h->errhp, rv, NULL);
245
- }
246
- newh = oci8_make_handle(h->type, hp, h->errhp, h->parent, 0);
247
- if (rv != OCI_SUCCESS)
248
- oci8_raise(h->errhp, rv, NULL);
249
- return newh->self;
250
- }
251
-
252
- #ifdef HAVE_OCILOBOPEN
253
- static VALUE oci8_lob_open(int argc, VALUE *argv, VALUE self)
254
- {
255
- VALUE vsvc;
256
- VALUE vmode = Qnil;
257
- oci8_handle_t *h;
258
- oci8_handle_t *svch;
259
- ub1 mode;
260
- sword rv;
261
-
262
- rb_scan_args(argc, argv, "11", &vsvc, &vmode);
263
- Get_Handle(self, h); /* 0 */
264
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
265
- if (vmode == Qnil)
266
- mode = OCI_DEFAULT;
267
- else if (vmode == sym_file_readonly)
268
- mode = OCI_FILE_READONLY;
269
- else
270
- rb_raise(rb_eArgError, "expect nil or :file_readonly");
271
- rv = OCILobOpen(svch->hp, h->errhp, h->hp, mode);
272
- if (rv != OCI_SUCCESS)
273
- oci8_raise(h->errhp, rv, NULL);
274
- return self;
275
- }
276
- #endif
277
-
278
- #ifdef HAVE_OCILOBCLOSE
279
- static VALUE oci8_lob_close(VALUE self, VALUE vsvc)
280
- {
281
- oci8_handle_t *h;
282
- oci8_handle_t *svch;
283
- sword rv;
284
-
285
- Get_Handle(self, h); /* 0 */
286
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
287
-
288
- rv = OCILobClose(svch->hp, h->errhp, h->hp);
289
- if (rv != OCI_SUCCESS)
290
- oci8_raise(h->errhp, rv, NULL);
291
- return self;
292
- }
293
- #endif
294
-
295
- static VALUE oci8_lobfile_name(VALUE self, VALUE venv)
296
- {
297
- oci8_handle_t *h;
298
- oci8_handle_t *envh;
299
- char dir_alias[31];
300
- ub2 d_length = sizeof(dir_alias);
301
- char filename[256];
302
- ub2 f_length = sizeof(filename);
303
- sword rv;
304
-
305
- Get_Handle(self, h); /* 0 */
306
- Check_Handle(venv, OCIEnv, envh); /* 1 */
307
-
308
- rv = OCILobFileGetName(envh->hp, h->errhp, h->hp, (OraText*)dir_alias, &d_length, (OraText*)filename, &f_length);
309
- if (rv != OCI_SUCCESS)
310
- oci8_raise(h->errhp, rv, NULL);
311
- return rb_ary_new3(2, rb_str_new(dir_alias, d_length), rb_str_new(filename, f_length));
312
- }
313
-
314
- static VALUE oci8_lobfile_set_name(VALUE self, VALUE venv, VALUE vdir, VALUE vfile)
315
- {
316
- oci8_handle_t *h;
317
- oci8_handle_t *envh;
318
- sword rv;
319
-
320
- Get_Handle(self, h); /* 0 */
321
- Check_Handle(venv, OCIEnv, envh); /* 1 */
322
- StringValue(vdir); /* 2 */
323
- StringValue(vfile); /* 3 */
324
-
325
- rv = OCILobFileSetName(envh->hp, h->errhp, (OCILobLocator **)&h->hp,
326
- RSTRING_ORATEXT(vdir), RSTRING_LEN(vdir),
327
- RSTRING_ORATEXT(vfile), RSTRING_LEN(vfile));
328
- if (rv != OCI_SUCCESS)
329
- oci8_raise(h->errhp, rv, NULL);
330
- return self;
331
- }
332
-
333
- static VALUE oci8_lobfile_exist_p(VALUE self, VALUE vsvc)
334
- {
335
- oci8_handle_t *h;
336
- oci8_handle_t *svch;
337
- boolean flag;
338
- sword rv;
339
-
340
- Get_Handle(self, h); /* 0 */
341
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
342
-
343
- rv = OCILobFileExists(svch->hp, h->errhp, h->hp, &flag);
344
- if (rv != OCI_SUCCESS)
345
- oci8_raise(h->errhp, rv, NULL);
346
- return flag ? Qtrue : Qfalse;
347
- }
348
-
349
- static VALUE oci8_lob_create_temporary(VALUE self, VALUE vsvc, VALUE vcsid, VALUE vcsfrm, VALUE vlobtype, VALUE vcache, VALUE vduration)
350
- {
351
- #ifdef HAVE_OCILOBCREATETEMPORARY
352
- oci8_handle_t *h;
353
- oci8_handle_t *svch;
354
- ub2 csid;
355
- ub1 csfrm;
356
- ub1 lobtype;
357
- boolean cache;
358
- OCIDuration duration;
359
- sword rv;
360
-
361
- Get_Handle(self, h); /* 0 */
362
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
363
- csid = NIL_P(vcsid) ? 0 : NUM2INT(vcsid); /* 2 */
364
- csfrm = NIL_P(vcsfrm) ? SQLCS_IMPLICIT : NUM2INT(vcsfrm); /* 3 */
365
- lobtype = NUM2INT(vlobtype); /* 4 */
366
- cache = RTEST(vcache) ? TRUE : FALSE; /* 5 */
367
- duration = NIL_P(vduration) ? OCI_DURATION_SESSION : NUM2INT(vduration); /* 6 */
368
-
369
- rv = OCILobCreateTemporary(svch->hp, h->errhp, h->hp, csid, csfrm, lobtype, cache, duration);
370
- if (rv != OCI_SUCCESS)
371
- oci8_raise(h->errhp, rv, NULL);
372
- return self;
373
- #else
374
- rb_notimplement();
375
- #endif
376
- }
377
-
378
- void Init_oci8_lob(void)
379
- {
380
- sym_file_readonly = ID2SYM(rb_intern("file_readonly"));
381
- #ifndef OCI8_USE_CALLBACK_LOB_READ
382
- rb_define_method(cOCILobLocator, "char_width=", oci8_lob_set_char_width, 1);
383
- #endif
384
- rb_define_method(cOCILobLocator, "is_initialized?", oci8_lob_is_initialized_p, 1);
385
- rb_define_method(cOCILobLocator, "getLength", oci8_lob_get_length, 1);
386
- #ifdef HAVE_OCILOBGETCHUNKSIZE
387
- rb_define_method(cOCILobLocator, "getChunkSize", oci8_lob_get_chunk_size, 1);
388
- #endif
389
- rb_define_method(cOCILobLocator, "read", oci8_lob_read, -1);
390
- rb_define_method(cOCILobLocator, "write", oci8_lob_write, -1);
391
- rb_define_method(cOCILobLocator, "trim", oci8_lob_trim, 2);
392
- rb_define_method(cOCILobLocator, "clone", oci8_lob_clone, 1);
393
- #ifdef HAVE_OCILOBOPEN
394
- rb_define_method(cOCILobLocator, "open", oci8_lob_open, -1);
395
- #endif
396
- #ifdef HAVE_OCILOBCLOSE
397
- rb_define_method(cOCILobLocator, "close", oci8_lob_close, 1);
398
- #endif
399
- rb_define_method(cOCIFileLocator, "name", oci8_lobfile_name, 1);
400
- rb_define_method(cOCIFileLocator, "set_name", oci8_lobfile_set_name, 3);
401
- rb_define_method(cOCIFileLocator, "exists?", oci8_lobfile_exist_p, 1);
402
- rb_define_method(cOCILobLocator, "create_temporary", oci8_lob_create_temporary, 6);
299
+ amt = nchar;
300
+ buf_size_in_char = sizeof(buf) / lob->char_width;
301
+ do {
302
+ if (lob->state == S_BFILE_CLOSE) {
303
+ rv = OCILobFileOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_FILE_READONLY);
304
+ if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22290) {
305
+ /* ORA-22290: operation would exceed the maximum number of opened files or LOBs */
306
+ /* close all opened BFILE implicitly. */
307
+ oci8_base_t *base;
308
+ for (base = &lob->base; base != &lob->base; base = base->next) {
309
+ if (base->type == OCI_DTYPE_LOB) {
310
+ oci8_lob_t *tmp = (oci8_lob_t *)base;
311
+ if (tmp->state == S_BFILE_OPEN) {
312
+ tmp->state = S_BFILE_CLOSE;
313
+ }
314
+ }
315
+ }
316
+ oci_lc(OCILobFileCloseAll_nb(svcctx, svcctx->base.hp.svc, oci8_errhp));
317
+ continue;
318
+ }
319
+ if (rv != OCI_SUCCESS)
320
+ oci8_raise(oci8_errhp, rv, NULL);
321
+ lob->state = S_BFILE_OPEN;
322
+ }
323
+ /* initialize buf in zeros everytime to check a nul characters. */
324
+ memset(buf, 0, sizeof(buf));
325
+ rv = OCILobRead_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, buf, sizeof(buf), NULL, NULL, 0, lob->csfrm);
326
+ if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22289) {
327
+ /* ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB */
328
+ if (lob->state == S_BFILE_CLOSE)
329
+ continue;
330
+ }
331
+ if (rv != OCI_SUCCESS && rv != OCI_NEED_DATA)
332
+ oci8_raise(oci8_errhp, rv, NULL);
333
+
334
+ /* Workaround when using Oracle 10.2.0.4 or 11.1.0.6 client and
335
+ * variable-length character set (e.g. AL32UTF8).
336
+ *
337
+ * When the above mentioned condition, amt may be shorter. So
338
+ * amt is increaded until a nul character to know the actually
339
+ * read size.
340
+ */
341
+ while (amt < sizeof(buf) && buf[amt] != '\0') {
342
+ amt++;
343
+ }
344
+
345
+ if (amt == 0)
346
+ break;
347
+ /* for fixed size charset, amt is the number of characters stored in buf. */
348
+ if (amt > buf_size_in_char)
349
+ rb_raise(eOCIException, "Too large buffer fetched or you set too large size of a character.");
350
+ amt *= lob->char_width;
351
+ rb_ary_push(v, rb_str_new(buf, amt));
352
+ } while (rv == OCI_NEED_DATA);
353
+ lob->pos += nchar;
354
+ if (nchar == length) {
355
+ lob_close(lob);
356
+ bfile_close(lob);
357
+ }
358
+ if (RARRAY_LEN(v) == 0) {
359
+ return Qnil;
360
+ }
361
+ v = rb_ary_join(v, Qnil);
362
+ OBJ_TAINT(v);
363
+ rb_enc_associate(v, oci8_encoding);
364
+ return rb_str_conv_enc(v, oci8_encoding, rb_default_internal_encoding());
365
+ }
366
+
367
+ static VALUE oci8_lob_write(VALUE self, VALUE data)
368
+ {
369
+ oci8_lob_t *lob = DATA_PTR(self);
370
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
371
+ ub4 amt;
372
+
373
+ lob_open(lob);
374
+ OCI8StringValue(data);
375
+ amt = RSTRING_LEN(data);
376
+ oci_lc(OCILobWrite_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, RSTRING_PTR(data), amt, OCI_ONE_PIECE, NULL, NULL, 0, lob->csfrm));
377
+ lob->pos += amt;
378
+ return UINT2NUM(amt);
379
+ }
380
+
381
+ static VALUE oci8_lob_get_sync(VALUE self)
382
+ {
383
+ oci8_lob_t *lob = DATA_PTR(self);
384
+ return (lob->state == S_NO_OPEN_CLOSE) ? Qtrue : Qfalse;
385
+ }
386
+
387
+ static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
388
+ {
389
+ oci8_lob_t *lob = DATA_PTR(self);
390
+ if (RTEST(b)) {
391
+ lob_close(lob);
392
+ lob->state = S_NO_OPEN_CLOSE;
393
+ } else {
394
+ if (lob->state == S_NO_OPEN_CLOSE)
395
+ lob->state = S_CLOSE;
396
+ }
397
+ return b;
398
+ }
399
+
400
+ static VALUE oci8_lob_flush(VALUE self)
401
+ {
402
+ oci8_lob_t *lob = DATA_PTR(self);
403
+ lob_close(lob);
404
+ return self;
405
+ }
406
+
407
+ static VALUE oci8_lob_get_chunk_size(VALUE self)
408
+ {
409
+ if (have_OCILobGetChunkSize_nb) {
410
+ oci8_lob_t *lob = DATA_PTR(self);
411
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
412
+ ub4 len;
413
+
414
+ oci_lc(OCILobGetChunkSize_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len));
415
+ return UINT2NUM(len);
416
+ } else {
417
+ rb_notimplement();
418
+ }
419
+ }
420
+
421
+ static VALUE oci8_lob_clone(VALUE self)
422
+ {
423
+ oci8_lob_t *lob = DATA_PTR(self);
424
+ oci8_lob_t *newlob;
425
+ VALUE newobj;
426
+ sword rv;
427
+ boolean is_temporary;
428
+
429
+ newobj = rb_funcall(CLASS_OF(self), oci8_id_new, 1, lob->svc);
430
+ newlob = DATA_PTR(newobj);
431
+ if (have_OCILobLocatorAssign_nb && have_OCILobIsTemporary
432
+ && OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS
433
+ && is_temporary) {
434
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
435
+ rv = OCILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob);
436
+ } else {
437
+ rv = OCILobAssign(oci8_envhp, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob);
438
+ }
439
+ if (rv != OCI_SUCCESS) {
440
+ oci8_raise(oci8_errhp, rv, NULL);
441
+ }
442
+ return newobj;
443
+ }
444
+
445
+ static void oci8_bfile_get_name(VALUE self, VALUE *dir_alias_p, VALUE *filename_p)
446
+ {
447
+ int need_get = 0;
448
+ if (dir_alias_p != NULL) {
449
+ *dir_alias_p = rb_ivar_get(self, id_dir_alias);
450
+ if (NIL_P(*dir_alias_p))
451
+ need_get = 1;
452
+ }
453
+ if (filename_p != NULL) {
454
+ *filename_p = rb_ivar_get(self, id_filename);
455
+ if (NIL_P(*filename_p))
456
+ need_get = 1;
457
+ }
458
+ if (need_get) {
459
+ oci8_lob_t *lob = DATA_PTR(self);
460
+ char d_buf[31];
461
+ ub2 d_length = sizeof(d_buf);
462
+ char f_buf[256];
463
+ ub2 f_length = sizeof(f_buf);
464
+ VALUE dir_alias;
465
+ VALUE filename;
466
+
467
+ oci_lc(OCILobFileGetName(oci8_envhp, oci8_errhp, lob->base.hp.lob, TO_ORATEXT(d_buf), &d_length, TO_ORATEXT(f_buf), &f_length));
468
+ dir_alias = rb_external_str_new_with_enc(d_buf, d_length, oci8_encoding);
469
+ filename = rb_external_str_new_with_enc(f_buf, f_length, oci8_encoding);
470
+ rb_ivar_set(self, id_dir_alias, dir_alias);
471
+ rb_ivar_set(self, id_filename, filename);
472
+ if (dir_alias_p != NULL) {
473
+ *dir_alias_p = dir_alias;
474
+ }
475
+ if (filename_p != NULL) {
476
+ *filename_p = filename;
477
+ }
478
+ }
479
+ }
480
+
481
+ static void oci8_bfile_set_name(VALUE self, VALUE dir_alias, VALUE filename)
482
+ {
483
+ oci8_lob_t *lob = DATA_PTR(self);
484
+
485
+ bfile_close(lob);
486
+ oci_lc(OCILobFileSetName(oci8_envhp, oci8_errhp, &lob->base.hp.lob,
487
+ RSTRING_ORATEXT(dir_alias), RSTRING_LEN(dir_alias),
488
+ RSTRING_ORATEXT(filename), RSTRING_LEN(filename)));
489
+ }
490
+
491
+ static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
492
+ {
493
+ oci8_lob_t *lob = DATA_PTR(self);
494
+ VALUE svc;
495
+ VALUE dir_alias;
496
+ VALUE filename;
497
+
498
+ rb_scan_args(argc, argv, "12", &svc, &dir_alias, &filename);
499
+ TO_SVCCTX(svc); /* check argument type */
500
+ oci_lc(OCIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, OCI_DTYPE_LOB, 0, NULL));
501
+ lob->base.type = OCI_DTYPE_LOB;
502
+ lob->svc = svc;
503
+ lob->pos = 0;
504
+ lob->char_width = 1;
505
+ lob->csfrm = SQLCS_IMPLICIT;
506
+ lob->state = S_BFILE_CLOSE;
507
+ if (argc != 1) {
508
+ OCI8SafeStringValue(dir_alias);
509
+ OCI8SafeStringValue(filename);
510
+ oci8_bfile_set_name(self, dir_alias, filename);
511
+ }
512
+ oci8_link_to_parent((oci8_base_t*)lob, (oci8_base_t*)DATA_PTR(svc));
513
+ return Qnil;
514
+ }
515
+
516
+ static VALUE oci8_bfile_get_dir_alias(VALUE self)
517
+ {
518
+ VALUE dir_alias;
519
+
520
+ oci8_bfile_get_name(self, &dir_alias, NULL);
521
+ return dir_alias;
522
+ }
523
+
524
+ static VALUE oci8_bfile_get_filename(VALUE self)
525
+ {
526
+ VALUE filename;
527
+
528
+ oci8_bfile_get_name(self, NULL, &filename);
529
+ return filename;
530
+ }
531
+
532
+ static VALUE oci8_bfile_set_dir_alias(VALUE self, VALUE dir_alias)
533
+ {
534
+ VALUE filename;
535
+
536
+ OCI8SafeStringValue(dir_alias);
537
+ oci8_bfile_get_name(self, NULL, &filename);
538
+ oci8_bfile_set_name(self, dir_alias, filename);
539
+ rb_ivar_set(self, id_dir_alias, dir_alias);
540
+ return dir_alias;
541
+ }
542
+
543
+ static VALUE oci8_bfile_set_filename(VALUE self, VALUE filename)
544
+ {
545
+ VALUE dir_alias;
546
+
547
+ OCI8SafeStringValue(filename);
548
+ oci8_bfile_get_name(self, &dir_alias, NULL);
549
+ oci8_bfile_set_name(self, dir_alias, filename);
550
+ rb_ivar_set(self, id_filename, filename);
551
+ return filename;
552
+ }
553
+
554
+ static VALUE oci8_bfile_exists_p(VALUE self)
555
+ {
556
+ oci8_lob_t *lob = DATA_PTR(self);
557
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
558
+ boolean flag;
559
+
560
+ oci_lc(OCILobFileExists_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &flag));
561
+ return flag ? Qtrue : Qfalse;
562
+ }
563
+
564
+ static VALUE oci8_bfile_error(VALUE self, VALUE dummy)
565
+ {
566
+ rb_raise(rb_eRuntimeError, "cannot modify a read-only BFILE object");
567
+ }
568
+
569
+ /*
570
+ * bind_clob/blob/bfile
571
+ */
572
+
573
+ typedef struct {
574
+ oci8_bind_class_t bind;
575
+ VALUE *klass;
576
+ } oci8_bind_lob_class_t;
577
+
578
+ static VALUE bind_lob_get(oci8_bind_t *obind, void *data, void *null_struct)
579
+ {
580
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
581
+ return oci8_lob_clone(oho->obj);
582
+ }
583
+
584
+ static void bind_lob_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
585
+ {
586
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
587
+ const oci8_bind_lob_class_t *klass = (const oci8_bind_lob_class_t *)obind->base.klass;
588
+ oci8_base_t *h;
589
+ if (!rb_obj_is_kind_of(val, *klass->klass))
590
+ rb_raise(rb_eArgError, "Invalid argument: %s (expect %s)", rb_class2name(CLASS_OF(val)), rb_class2name(*klass->klass));
591
+ h = DATA_PTR(val);
592
+ oho->hp = h->hp.ptr;
593
+ oho->obj = val;
594
+ }
595
+
596
+ static void bind_lob_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
597
+ {
598
+ obind->value_sz = sizeof(void *);
599
+ obind->alloc_sz = sizeof(oci8_hp_obj_t);
600
+ }
601
+
602
+ static void bind_lob_init_elem(oci8_bind_t *obind, VALUE svc)
603
+ {
604
+ const oci8_bind_lob_class_t *klass = (const oci8_bind_lob_class_t *)obind->base.klass;
605
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
606
+ oci8_base_t *h;
607
+ ub4 idx = 0;
608
+
609
+ do {
610
+ oho[idx].obj = rb_funcall(*klass->klass, oci8_id_new, 1, svc);
611
+ h = DATA_PTR(oho[idx].obj);
612
+ oho[idx].hp = h->hp.ptr;
613
+ } while (++idx < obind->maxar_sz);
614
+ }
615
+
616
+ static const oci8_bind_lob_class_t bind_clob_class = {
617
+ {
618
+ {
619
+ oci8_bind_hp_obj_mark,
620
+ oci8_bind_free,
621
+ sizeof(oci8_bind_t)
622
+ },
623
+ bind_lob_get,
624
+ bind_lob_set,
625
+ bind_lob_init,
626
+ bind_lob_init_elem,
627
+ NULL,
628
+ NULL,
629
+ NULL,
630
+ SQLT_CLOB
631
+ },
632
+ &cOCI8CLOB
633
+ };
634
+
635
+ static const oci8_bind_lob_class_t bind_nclob_class = {
636
+ {
637
+ {
638
+ oci8_bind_hp_obj_mark,
639
+ oci8_bind_free,
640
+ sizeof(oci8_bind_t)
641
+ },
642
+ bind_lob_get,
643
+ bind_lob_set,
644
+ bind_lob_init,
645
+ bind_lob_init_elem,
646
+ NULL,
647
+ NULL,
648
+ NULL,
649
+ SQLT_CLOB,
650
+ SQLCS_NCHAR,
651
+ },
652
+ &cOCI8NCLOB
653
+ };
654
+
655
+ static const oci8_bind_lob_class_t bind_blob_class = {
656
+ {
657
+ {
658
+ oci8_bind_hp_obj_mark,
659
+ oci8_bind_free,
660
+ sizeof(oci8_bind_t)
661
+ },
662
+ bind_lob_get,
663
+ bind_lob_set,
664
+ bind_lob_init,
665
+ bind_lob_init_elem,
666
+ NULL,
667
+ NULL,
668
+ NULL,
669
+ SQLT_BLOB
670
+ },
671
+ &cOCI8BLOB
672
+ };
673
+
674
+ static const oci8_bind_lob_class_t bind_bfile_class = {
675
+ {
676
+ {
677
+ oci8_bind_hp_obj_mark,
678
+ oci8_bind_free,
679
+ sizeof(oci8_bind_t)
680
+ },
681
+ bind_lob_get,
682
+ bind_lob_set,
683
+ bind_lob_init,
684
+ bind_lob_init_elem,
685
+ NULL,
686
+ NULL,
687
+ NULL,
688
+ SQLT_BFILE
689
+ },
690
+ &cOCI8BFILE
691
+ };
692
+
693
+ void Init_oci8_lob(VALUE cOCI8)
694
+ {
695
+ id_plus = rb_intern("+");
696
+ id_dir_alias = rb_intern("@dir_alias");
697
+ id_filename = rb_intern("@filename");
698
+ seek_set = rb_eval_string("::IO::SEEK_SET");
699
+ seek_cur = rb_eval_string("::IO::SEEK_CUR");
700
+ seek_end = rb_eval_string("::IO::SEEK_END");
701
+
702
+ cOCI8LOB = oci8_define_class_under(cOCI8, "LOB", &oci8_lob_class);
703
+ cOCI8CLOB = rb_define_class_under(cOCI8, "CLOB", cOCI8LOB);
704
+ cOCI8NCLOB = rb_define_class_under(cOCI8, "NCLOB", cOCI8LOB);
705
+ cOCI8BLOB = rb_define_class_under(cOCI8, "BLOB", cOCI8LOB);
706
+ cOCI8BFILE = rb_define_class_under(cOCI8, "BFILE", cOCI8LOB);
707
+
708
+ rb_define_method(cOCI8CLOB, "initialize", oci8_clob_initialize, -1);
709
+ rb_define_method(cOCI8NCLOB, "initialize", oci8_nclob_initialize, -1);
710
+ rb_define_method(cOCI8BLOB, "initialize", oci8_blob_initialize, -1);
711
+ rb_define_private_method(cOCI8LOB, "__char_width=", oci8_lob_set_char_width, 1);
712
+ rb_define_method(cOCI8LOB, "available?", oci8_lob_available_p, 0);
713
+ rb_define_method(cOCI8LOB, "size", oci8_lob_get_size, 0);
714
+ rb_define_method(cOCI8LOB, "pos", oci8_lob_get_pos, 0);
715
+ rb_define_alias(cOCI8LOB, "tell", "pos");
716
+ rb_define_method(cOCI8LOB, "eof?", oci8_lob_eof_p, 0);
717
+ rb_define_method(cOCI8LOB, "seek", oci8_lob_seek, -1);
718
+ rb_define_method(cOCI8LOB, "rewind", oci8_lob_rewind, 0);
719
+ rb_define_method(cOCI8LOB, "truncate", oci8_lob_truncate, 1);
720
+ rb_define_method(cOCI8LOB, "size=", oci8_lob_set_size, 1);
721
+ rb_define_method(cOCI8LOB, "read", oci8_lob_read, -1);
722
+ rb_define_method(cOCI8LOB, "write", oci8_lob_write, 1);
723
+ rb_define_method(cOCI8LOB, "close", oci8_lob_close, 0);
724
+ rb_define_method(cOCI8LOB, "sync", oci8_lob_get_sync, 0);
725
+ rb_define_method(cOCI8LOB, "sync=", oci8_lob_set_sync, 1);
726
+ rb_define_method(cOCI8LOB, "flush", oci8_lob_flush, 0);
727
+ rb_define_method(cOCI8LOB, "chunk_size", oci8_lob_get_chunk_size, 0);
728
+
729
+ rb_define_method(cOCI8BFILE, "initialize", oci8_bfile_initialize, -1);
730
+ rb_define_method(cOCI8BFILE, "dir_alias", oci8_bfile_get_dir_alias, 0);
731
+ rb_define_method(cOCI8BFILE, "filename", oci8_bfile_get_filename, 0);
732
+ rb_define_method(cOCI8BFILE, "dir_alias=", oci8_bfile_set_dir_alias, 1);
733
+ rb_define_method(cOCI8BFILE, "filename=", oci8_bfile_set_filename, 1);
734
+ rb_define_method(cOCI8BFILE, "exists?", oci8_bfile_exists_p, 0);
735
+ rb_define_method(cOCI8BFILE, "truncate", oci8_bfile_error, 1);
736
+ rb_define_method(cOCI8BFILE, "size=", oci8_bfile_error, 1);
737
+ rb_define_method(cOCI8BFILE, "write", oci8_bfile_error, 1);
738
+
739
+ oci8_define_bind_class("CLOB", &bind_clob_class.bind);
740
+ oci8_define_bind_class("NCLOB", &bind_nclob_class.bind);
741
+ oci8_define_bind_class("BLOB", &bind_blob_class.bind);
742
+ oci8_define_bind_class("BFILE", &bind_bfile_class.bind);
403
743
  }