ruby-oci8 1.0.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }