ruby-oci8 2.1.7 → 2.1.8

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.
@@ -2,13 +2,15 @@
2
2
  /*
3
3
  * connection_pool.c - part of ruby-oci8
4
4
  *
5
- * Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2010-2014 Kubo Takehiro <kubo@jiubao.org>
6
6
  *
7
7
  */
8
8
  #include "oci8.h"
9
9
 
10
10
  static VALUE cOCIConnectionPool;
11
11
 
12
+ #define TO_CPOOL(obj) ((oci8_cpool_t *)oci8_check_typeddata((obj), &oci8_cpool_data_type, 1))
13
+
12
14
  typedef struct {
13
15
  oci8_base_t base;
14
16
  VALUE pool_name;
@@ -32,23 +34,36 @@ static void oci8_cpool_free(oci8_base_t *base)
32
34
  {
33
35
  oci8_run_native_thread(cpool_free_thread, base->hp.poolhp);
34
36
  base->type = 0;
37
+ base->closed = 1;
35
38
  base->hp.ptr = NULL;
36
39
  }
37
40
 
38
- static void oci8_cpool_init(oci8_base_t *base)
41
+ static const oci8_handle_data_type_t oci8_cpool_data_type = {
42
+ {
43
+ "OCI8::ConnectionPool",
44
+ {
45
+ (RUBY_DATA_FUNC)oci8_cpool_mark,
46
+ oci8_handle_cleanup,
47
+ oci8_handle_size,
48
+ },
49
+ &oci8_handle_data_type.rb_data_type, NULL,
50
+ #ifdef RUBY_TYPED_WB_PROTECTED
51
+ RUBY_TYPED_WB_PROTECTED,
52
+ #endif
53
+ },
54
+ oci8_cpool_free,
55
+ sizeof(oci8_cpool_t),
56
+ };
57
+
58
+ static VALUE oci8_cpool_alloc(VALUE klass)
39
59
  {
40
- oci8_cpool_t *cpool = (oci8_cpool_t *)base;
60
+ VALUE self = oci8_allocate_typeddata(klass, &oci8_cpool_data_type);
61
+ oci8_cpool_t *cpool = (oci8_cpool_t *)RTYPEDDATA_DATA(self);
41
62
 
42
63
  cpool->pool_name = Qnil;
64
+ return self;
43
65
  }
44
66
 
45
- static oci8_base_vtable_t oci8_cpool_vtable = {
46
- oci8_cpool_mark,
47
- oci8_cpool_free,
48
- sizeof(oci8_cpool_t),
49
- oci8_cpool_init,
50
- };
51
-
52
67
  /*
53
68
  * call-seq:
54
69
  * OCI8::ConnectionPool.new(conn_min, conn_max, conn_incr, username = nil, password = nil, dbname = nil) -> connection pool
@@ -89,9 +104,9 @@ static VALUE oci8_cpool_initialize(int argc, VALUE *argv, VALUE self)
89
104
  VALUE username;
90
105
  VALUE password;
91
106
  VALUE dbname;
92
- oci8_cpool_t *cpool = DATA_PTR(self);
93
- OraText *pool_name;
94
- sb4 pool_name_len;
107
+ oci8_cpool_t *cpool = TO_CPOOL(self);
108
+ OraText *pool_name = NULL;
109
+ sb4 pool_name_len = 0;
95
110
  sword rv;
96
111
 
97
112
  /* check arguments */
@@ -138,7 +153,7 @@ static VALUE oci8_cpool_initialize(int argc, VALUE *argv, VALUE self)
138
153
  NIL_P(password) ? 0 : RSTRING_LEN(password),
139
154
  OCI_DEFAULT),
140
155
  &cpool->base);
141
- cpool->pool_name = rb_str_new(TO_CHARPTR(pool_name), pool_name_len);
156
+ RB_OBJ_WRITE(cpool->base.self, &cpool->pool_name, rb_str_new(TO_CHARPTR(pool_name), pool_name_len));
142
157
  rb_str_freeze(cpool->pool_name);
143
158
  return Qnil;
144
159
  }
@@ -152,7 +167,7 @@ static VALUE oci8_cpool_initialize(int argc, VALUE *argv, VALUE self)
152
167
  */
153
168
  static VALUE oci8_cpool_reinitialize(VALUE self, VALUE conn_min, VALUE conn_max, VALUE conn_incr)
154
169
  {
155
- oci8_cpool_t *cpool = DATA_PTR(self);
170
+ oci8_cpool_t *cpool = TO_CPOOL(self);
156
171
  OraText *pool_name;
157
172
  sb4 pool_name_len;
158
173
 
@@ -180,7 +195,7 @@ static VALUE oci8_cpool_reinitialize(VALUE self, VALUE conn_min, VALUE conn_max,
180
195
  */
181
196
  static VALUE oci8_cpool_pool_name(VALUE self)
182
197
  {
183
- oci8_cpool_t *cpool = DATA_PTR(self);
198
+ oci8_cpool_t *cpool = TO_CPOOL(self);
184
199
 
185
200
  return cpool->pool_name;
186
201
  }
@@ -193,7 +208,7 @@ void Init_oci8_connection_pool(VALUE cOCI8)
193
208
  cOCIConnectionPool = rb_define_class_under(cOCI8, "ConnectionPool", cOCIHandle);
194
209
  #endif
195
210
 
196
- cOCIConnectionPool = oci8_define_class_under(cOCI8, "ConnectionPool", &oci8_cpool_vtable);
211
+ cOCIConnectionPool = oci8_define_class_under(cOCI8, "ConnectionPool", &oci8_cpool_data_type, oci8_cpool_alloc);
197
212
 
198
213
  rb_define_private_method(cOCIConnectionPool, "initialize", oci8_cpool_initialize, -1);
199
214
  rb_define_method(cOCIConnectionPool, "reinitialize", oci8_cpool_reinitialize, 3);
@@ -118,10 +118,12 @@ have_header("ruby/thread.h")
118
118
  have_var("ruby_errinfo", "ruby.h") # ruby 1.8
119
119
  have_func("rb_errinfo", "ruby.h") # ruby 1.9
120
120
 
121
+ have_func("rb_str_set_len", "ruby.h")
121
122
  have_func("rb_set_end_proc", "ruby.h")
122
123
  have_func("rb_class_superclass", "ruby.h")
123
124
  have_func("rb_thread_blocking_region", "ruby.h")
124
125
  have_func("rb_thread_call_without_gvl", "ruby/thread.h")
126
+ have_func("rb_sym2str", "ruby.h")
125
127
  if (defined? RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
126
128
  have_func("rb_str_buf_cat_ascii", "ruby.h")
127
129
  have_func("rb_enc_str_buf_cat", "ruby.h")
@@ -181,6 +183,25 @@ else
181
183
  raise 'unsupported ruby engine: ' + RUBY_ENGINE
182
184
  end
183
185
 
186
+ print "checking for plthook... "
187
+ STDOUT.flush
188
+ case RUBY_PLATFORM
189
+ when /mswin32|cygwin|mingw32|bccwin32/
190
+ plthook_src = "plthook_win32.c"
191
+ when /darwin/
192
+ plthook_src = "plthook_osx.c"
193
+ else
194
+ plthook_src = "plthook_elf.c"
195
+ end
196
+ if xsystem(cc_command("").gsub(CONFTEST_C, File.dirname(__FILE__) + "/" + plthook_src))
197
+ puts plthook_src
198
+ $objs << plthook_src.gsub(/\.c$/, '.o')
199
+ $objs << "hook_funcs.o"
200
+ $defs << "-DHAVE_PLTHOOK"
201
+ else
202
+ puts "no"
203
+ end
204
+
184
205
  $defs << "-DInit_oci8lib=Init_#{so_basename}"
185
206
  $defs << "-Doci8lib=#{so_basename}"
186
207
  $defs << "-DOCI8LIB_VERSION=\\\"#{RUBY_OCI8_VERSION}\\\""
@@ -0,0 +1,215 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * hook.c
4
+ *
5
+ * Copyright (C) 2015 Kubo Takehiro <kubo@jiubao.org>
6
+ */
7
+ #include "oci8.h"
8
+ #include "plthook.h"
9
+ #ifndef WIN32
10
+ #include <unistd.h>
11
+ #include <sys/socket.h>
12
+ #endif
13
+
14
+ #define DEBUG_HOOK_FUNCS 1
15
+
16
+ #ifdef WIN32
17
+ static CRITICAL_SECTION lock;
18
+ #define LOCK(lock) EnterCriticalSection(lock)
19
+ #define UNLOCK(lock) LeaveCriticalSection(lock)
20
+ #else
21
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
22
+ #define LOCK(lock) pthread_mutex_lock(lock)
23
+ #define UNLOCK(lock) pthread_mutex_unlock(lock)
24
+ #define SOCKET int
25
+ #define INVALID_SOCKET (-1)
26
+ #endif
27
+
28
+ typedef struct {
29
+ const char *func_name;
30
+ void *func_addr;
31
+ void *old_func_addr;
32
+ } hook_func_entry_t;
33
+
34
+ typedef struct socket_entry {
35
+ struct socket_entry *next;
36
+ struct socket_entry *prev;
37
+ SOCKET sock;
38
+ } socket_entry_t;
39
+
40
+ static socket_entry_t sockets_in_use = {
41
+ &sockets_in_use, &sockets_in_use, INVALID_SOCKET,
42
+ };
43
+
44
+ static void socket_entry_set(socket_entry_t *entry, SOCKET sock)
45
+ {
46
+ LOCK(&lock);
47
+ entry->next = sockets_in_use.next;
48
+ entry->prev = &sockets_in_use;
49
+ sockets_in_use.next->prev = entry;
50
+ sockets_in_use.next = entry;
51
+ entry->sock = sock;
52
+ UNLOCK(&lock);
53
+ }
54
+
55
+ static void socket_entry_clear(socket_entry_t *entry)
56
+ {
57
+ LOCK(&lock);
58
+ entry->next->prev = entry->prev;
59
+ entry->prev->next = entry->next;
60
+ UNLOCK(&lock);
61
+ }
62
+
63
+ static int replace_functions(const char * const *files, hook_func_entry_t *functions)
64
+ {
65
+ int i;
66
+
67
+ for (i = 0; files[i] != NULL; i++) {
68
+ const char *file = files[i];
69
+ plthook_t *ph;
70
+ if (plthook_open(&ph, file) == 0) {
71
+ int j;
72
+ int rv = 0;
73
+
74
+ /* install hooks */
75
+ for (j = 0; functions[j].func_name != NULL ; j++) {
76
+ hook_func_entry_t *function = &functions[j];
77
+ rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
78
+ if (rv != 0) {
79
+ while (--j >= 0) {
80
+ /*restore hooked fuction address */
81
+ plthook_replace(ph, functions[j].func_name, functions[j].old_func_addr, NULL);
82
+ }
83
+ plthook_close(ph);
84
+ rb_raise(rb_eRuntimeError, "Could not replace function %s in %s", function->func_name, file);
85
+ }
86
+ }
87
+ plthook_close(ph);
88
+ return 0;
89
+ }
90
+ }
91
+ return -1;
92
+ }
93
+
94
+ #ifdef WIN32
95
+
96
+ static int locK_is_initialized;
97
+
98
+ static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
99
+
100
+ static const char * const tcp_func_files[] = {
101
+ /* full client */
102
+ "orantcp12.dll",
103
+ "orantcp11.dll",
104
+ "orantcp10.dll",
105
+ "orantcp9.dll",
106
+ /* instant client basic */
107
+ "oraociei12.dll",
108
+ "oraociei11.dll",
109
+ "oraociei10.dll",
110
+ /* instant client basic lite */
111
+ "oraociicus12.dll",
112
+ "oraociicus11.dll",
113
+ "oraociicus10.dll",
114
+ NULL,
115
+ };
116
+
117
+ static hook_func_entry_t tcp_functions[] = {
118
+ {"WSARecv", (void*)hook_WSARecv, NULL},
119
+ {NULL, NULL, NULL},
120
+ };
121
+
122
+ /* WSARecv() is used for TCP connections */
123
+ static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
124
+ {
125
+ socket_entry_t entry;
126
+ int rv;
127
+
128
+ socket_entry_set(&entry, s);
129
+ rv = WSARecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
130
+ socket_entry_clear(&entry);
131
+ return rv;
132
+ }
133
+
134
+ void oci8_install_hook_functions()
135
+ {
136
+ InitializeCriticalSectionAndSpinCount(&lock, 5000);
137
+ locK_is_initialized = 1;
138
+
139
+ if (replace_functions(tcp_func_files, tcp_functions) != 0) {
140
+ rb_raise(rb_eRuntimeError, "No DLL is found to hook.");
141
+ }
142
+ }
143
+
144
+ static void shutdown_socket(socket_entry_t *entry)
145
+ {
146
+ /* This is dangerous. But I don't know how to cancel WSARecv().
147
+ * This technique is usable only at the process termination.
148
+ * Otherwise, Oracle client library may close sockets used by
149
+ * others.
150
+ */
151
+ closesocket(entry->sock);
152
+ }
153
+
154
+ #else
155
+ static ssize_t hook_read(int fd, void *buf, size_t count);
156
+
157
+ #ifdef __APPLE__
158
+ #define SO_EXT "dylib"
159
+ #else
160
+ #define SO_EXT "so"
161
+ #endif
162
+
163
+ static const char * const files[] = {
164
+ "libclntsh." SO_EXT ".12.1",
165
+ "libclntsh." SO_EXT ".11.1",
166
+ "libclntsh." SO_EXT ".10.1",
167
+ "libclntsh." SO_EXT ".9.0",
168
+ NULL,
169
+ };
170
+
171
+ static hook_func_entry_t functions[] = {
172
+ {"read", (void*)hook_read, NULL},
173
+ {NULL, NULL, NULL},
174
+ };
175
+
176
+ static ssize_t hook_read(int fd, void *buf, size_t count)
177
+ {
178
+ socket_entry_t entry;
179
+ ssize_t rv;
180
+
181
+ socket_entry_set(&entry, fd);
182
+ rv = read(fd, buf, count);
183
+ socket_entry_clear(&entry);
184
+ return rv;
185
+ }
186
+
187
+ void oci8_install_hook_functions(void)
188
+ {
189
+ if (replace_functions(files, functions) != 0) {
190
+ rb_raise(rb_eRuntimeError, "No shared library is found to hook.");
191
+ }
192
+ }
193
+
194
+ static void shutdown_socket(socket_entry_t *entry)
195
+ {
196
+ shutdown(entry->sock, SHUT_RDWR);
197
+ }
198
+ #endif
199
+
200
+ void oci8_shutdown_sockets(void)
201
+ {
202
+ socket_entry_t *entry;
203
+
204
+ #ifdef WIN32
205
+ if (!locK_is_initialized) {
206
+ return;
207
+ }
208
+ #endif
209
+
210
+ LOCK(&lock);
211
+ for (entry = sockets_in_use.next; entry != &sockets_in_use; entry = entry->next) {
212
+ shutdown_socket(entry);
213
+ }
214
+ UNLOCK(&lock);
215
+ }
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * lob.c - part of ruby-oci8
4
4
  *
5
- * Copyright (C) 2002-2013 Kubo Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2002-2015 Kubo Takehiro <kubo@jiubao.org>
6
6
  */
7
7
  #include "oci8.h"
8
8
 
@@ -18,6 +18,8 @@ static VALUE seek_set;
18
18
  static VALUE seek_cur;
19
19
  static VALUE seek_end;
20
20
 
21
+ #define TO_LOB(obj) ((oci8_lob_t *)oci8_check_typeddata((obj), &oci8_lob_data_type, 1))
22
+
21
23
  enum state {
22
24
  S_NO_OPEN_CLOSE,
23
25
  S_OPEN,
@@ -46,6 +48,148 @@ static oci8_svcctx_t *check_svcctx(oci8_lob_t *lob)
46
48
 
47
49
  static VALUE oci8_lob_write(VALUE self, VALUE data);
48
50
 
51
+ static void oci8_lob_mark(oci8_base_t *base)
52
+ {
53
+ oci8_lob_t *lob = (oci8_lob_t *)base;
54
+ if (lob->svcctx != NULL) {
55
+ rb_gc_mark(lob->svcctx->base.self);
56
+ }
57
+ }
58
+
59
+ static void oci8_lob_free(oci8_base_t *base)
60
+ {
61
+ oci8_lob_t *lob = (oci8_lob_t *)base;
62
+ boolean is_temporary;
63
+ oci8_svcctx_t *svcctx = lob->svcctx;
64
+
65
+ if (svcctx != NULL
66
+ && OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS
67
+ && is_temporary) {
68
+
69
+ #ifdef NATIVE_THREAD_WITH_GVL
70
+ oci8_temp_lob_t *temp_lob = ALLOC(oci8_temp_lob_t);
71
+
72
+ temp_lob->next = svcctx->temp_lobs;
73
+ temp_lob->lob = lob->base.hp.lob;
74
+ svcctx->temp_lobs = temp_lob;
75
+ lob->base.type = 0;
76
+ lob->base.closed = 1;
77
+ lob->base.hp.ptr = NULL;
78
+ #else
79
+ /* FIXME: This may stall the GC. */
80
+ OCILobFreeTemporary(svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob);
81
+ #endif
82
+ }
83
+ lob->svcctx = NULL;
84
+ }
85
+
86
+ static const oci8_handle_data_type_t oci8_lob_data_type = {
87
+ {
88
+ "OCI8::LOB",
89
+ {
90
+ NULL,
91
+ NULL,
92
+ NULL,
93
+ },
94
+ &oci8_handle_data_type.rb_data_type, NULL,
95
+ },
96
+ NULL,
97
+ sizeof(oci8_lob_t),
98
+ };
99
+
100
+ static VALUE oci8_lob_alloc(VALUE klass)
101
+ {
102
+ rb_raise(rb_eNameError, "private method `new' called for %s:Class", rb_class2name(klass));
103
+ }
104
+
105
+ static const oci8_handle_data_type_t oci8_clob_data_type = {
106
+ {
107
+ "OCI8::CLOB",
108
+ {
109
+ (RUBY_DATA_FUNC)oci8_lob_mark,
110
+ oci8_handle_cleanup,
111
+ oci8_handle_size,
112
+ },
113
+ &oci8_lob_data_type.rb_data_type, NULL,
114
+ #ifdef RUBY_TYPED_WB_PROTECTED
115
+ RUBY_TYPED_WB_PROTECTED,
116
+ #endif
117
+ },
118
+ oci8_lob_free,
119
+ sizeof(oci8_lob_t),
120
+ };
121
+
122
+ static VALUE oci8_clob_alloc(VALUE klass)
123
+ {
124
+ return oci8_allocate_typeddata(klass, &oci8_clob_data_type);
125
+ }
126
+
127
+ static const oci8_handle_data_type_t oci8_nclob_data_type = {
128
+ {
129
+ "OCI8::NCLOB",
130
+ {
131
+ (RUBY_DATA_FUNC)oci8_lob_mark,
132
+ oci8_handle_cleanup,
133
+ oci8_handle_size,
134
+ },
135
+ &oci8_lob_data_type.rb_data_type, NULL,
136
+ #ifdef RUBY_TYPED_WB_PROTECTED
137
+ RUBY_TYPED_WB_PROTECTED,
138
+ #endif
139
+ },
140
+ oci8_lob_free,
141
+ sizeof(oci8_lob_t),
142
+ };
143
+
144
+ static VALUE oci8_nclob_alloc(VALUE klass)
145
+ {
146
+ return oci8_allocate_typeddata(klass, &oci8_nclob_data_type);
147
+ }
148
+
149
+ static const oci8_handle_data_type_t oci8_blob_data_type = {
150
+ {
151
+ "OCI8::BLOB",
152
+ {
153
+ (RUBY_DATA_FUNC)oci8_lob_mark,
154
+ oci8_handle_cleanup,
155
+ oci8_handle_size,
156
+ },
157
+ &oci8_lob_data_type.rb_data_type, NULL,
158
+ #ifdef RUBY_TYPED_WB_PROTECTED
159
+ RUBY_TYPED_WB_PROTECTED,
160
+ #endif
161
+ },
162
+ oci8_lob_free,
163
+ sizeof(oci8_lob_t),
164
+ };
165
+
166
+ static VALUE oci8_blob_alloc(VALUE klass)
167
+ {
168
+ return oci8_allocate_typeddata(klass, &oci8_blob_data_type);
169
+ }
170
+
171
+ static const oci8_handle_data_type_t oci8_bfile_data_type = {
172
+ {
173
+ "OCI8::BFILE",
174
+ {
175
+ (RUBY_DATA_FUNC)oci8_lob_mark,
176
+ oci8_handle_cleanup,
177
+ oci8_handle_size,
178
+ },
179
+ &oci8_lob_data_type.rb_data_type, NULL,
180
+ #ifdef RUBY_TYPED_WB_PROTECTED
181
+ RUBY_TYPED_WB_PROTECTED,
182
+ #endif
183
+ },
184
+ oci8_lob_free,
185
+ sizeof(oci8_lob_t),
186
+ };
187
+
188
+ static VALUE oci8_bfile_alloc(VALUE klass)
189
+ {
190
+ return oci8_allocate_typeddata(klass, &oci8_bfile_data_type);
191
+ }
192
+
49
193
  static VALUE oci8_make_lob(VALUE klass, oci8_svcctx_t *svcctx, OCILobLocator *s)
50
194
  {
51
195
  oci8_lob_t *lob;
@@ -53,7 +197,7 @@ static VALUE oci8_make_lob(VALUE klass, oci8_svcctx_t *svcctx, OCILobLocator *s)
53
197
  VALUE lob_obj;
54
198
 
55
199
  lob_obj = rb_class_new_instance(1, &svcctx->base.self, klass);
56
- lob = DATA_PTR(lob_obj);
200
+ lob = TO_LOB(lob_obj);
57
201
  /* If 's' is a temporary lob, use OCILobLocatorAssign instead. */
58
202
  chker2(OCILobIsTemporary(oci8_envhp, oci8_errhp, s, &is_temp), &svcctx->base);
59
203
  if (is_temp)
@@ -87,7 +231,11 @@ VALUE oci8_make_bfile(oci8_svcctx_t *svcctx, OCILobLocator *s)
87
231
 
88
232
  static void oci8_assign_lob(VALUE klass, oci8_svcctx_t *svcctx, VALUE lob, OCILobLocator **dest)
89
233
  {
90
- oci8_base_t *base = oci8_get_handle(lob, klass);
234
+ oci8_base_t *base = oci8_check_typeddata(lob, &oci8_lob_data_type, 1);
235
+ if (!rb_obj_is_kind_of(lob, klass)) {
236
+ rb_raise(rb_eTypeError, "wrong argument %s (expect %s)",
237
+ rb_obj_classname(lob), rb_class2name(klass));
238
+ }
91
239
  chker2(OCILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, base->hp.lob, dest), base);
92
240
  }
93
241
 
@@ -111,46 +259,6 @@ void oci8_assign_bfile(oci8_svcctx_t *svcctx, VALUE lob, OCILobLocator **dest)
111
259
  oci8_assign_lob(cOCI8BFILE, svcctx, lob, dest);
112
260
  }
113
261
 
114
- static void oci8_lob_mark(oci8_base_t *base)
115
- {
116
- oci8_lob_t *lob = (oci8_lob_t *)base;
117
- if (lob->svcctx != NULL) {
118
- rb_gc_mark(lob->svcctx->base.self);
119
- }
120
- }
121
-
122
- static void oci8_lob_free(oci8_base_t *base)
123
- {
124
- oci8_lob_t *lob = (oci8_lob_t *)base;
125
- boolean is_temporary;
126
- oci8_svcctx_t *svcctx = lob->svcctx;
127
-
128
- if (svcctx != NULL
129
- && OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS
130
- && is_temporary) {
131
-
132
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
133
- oci8_temp_lob_t *temp_lob = ALLOC(oci8_temp_lob_t);
134
-
135
- temp_lob->next = svcctx->temp_lobs;
136
- temp_lob->lob = lob->base.hp.lob;
137
- svcctx->temp_lobs = temp_lob;
138
- lob->base.type = 0;
139
- lob->base.hp.ptr = NULL;
140
- #else
141
- /* FIXME: This may stall the GC. */
142
- OCILobFreeTemporary(svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob);
143
- #endif
144
- }
145
- lob->svcctx = NULL;
146
- }
147
-
148
- static oci8_base_vtable_t oci8_lob_vtable = {
149
- oci8_lob_mark,
150
- oci8_lob_free,
151
- sizeof(oci8_lob_t),
152
- };
153
-
154
262
  static ub4 oci8_lob_get_length(oci8_lob_t *lob)
155
263
  {
156
264
  oci8_svcctx_t *svcctx = check_svcctx(lob);
@@ -197,31 +305,58 @@ static void bfile_close(oci8_lob_t *lob)
197
305
  /*
198
306
  * Document-class: OCI8::LOB
199
307
  *
200
- * This is the abstract base class of large-object data types; BFILE, BLOB, CLOB and NCLOB.
308
+ * This is the abstract base class of large-object data types; {BFILE}, {BLOB}, {CLOB} and {NCLOB}.
201
309
  *
202
310
  */
203
311
 
204
312
  /*
205
313
  * Document-class: OCI8::CLOB
206
314
  *
315
+ * This class is a ruby-side class of {Oracle NCLOB datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref175].
207
316
  */
208
317
 
209
318
  /*
210
319
  * Document-class: OCI8::NCLOB
211
320
  *
321
+ * This class is a ruby-side class of {Oracle CLOB datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref172].
212
322
  */
213
323
 
214
324
  /*
215
325
  * Document-class: OCI8::BLOB
216
326
  *
327
+ * This class is a ruby-side class of {Oracle BLOB datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref168].
328
+ *
217
329
  */
218
330
 
219
331
  /*
220
332
  * Document-class: OCI8::BFILE
221
333
  *
222
- * @method truncate(length)
223
- * @method size = length
224
- * @method write(data)
334
+ * This class is a ruby-side class of {Oracle BFILE datatype}[http://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#sthref164].
335
+ * It is a read-only {LOB}. You cannot change the contents.
336
+ *
337
+ * You can read files on the server-side as follows:
338
+ *
339
+ * 1. Connect to the Oracle server as a user who has CREATE DIRECTORY privilege.
340
+ *
341
+ * # create a directory object on the Oracle server.
342
+ * CREATE DIRECTORY file_storage_dir AS '/opt/file_storage';
343
+ * # grant a privilege to read files on file_storage_dir directory to a user.
344
+ * GRANT READ ON DIRECTORY file_storage_dir TO username;
345
+ *
346
+ * 2. Create a file 'hello_world.txt' in the directory '/opt/file_storage' on the server filesystem.
347
+ *
348
+ * echo 'Hello World!' > /opt/file_storage/hello_world.txt
349
+ *
350
+ * 3. Read the file by ruby-oci8.
351
+ *
352
+ * require 'oci8'
353
+ * # The user must have 'READ ON DIRECTORY file_storage_dir' privilege.
354
+ * conn = OCI8.new('username/password')
355
+ *
356
+ * # The second argument is usually an uppercase string unless the directory
357
+ * # object is explicitly created as *double-quoted* lowercase characters.
358
+ * bfile = OCI8::BFILE.new(conn, 'FILE_STORAGE_DIR', 'hello_world.txt')
359
+ * bfile.read # => "Hello World!\n"
225
360
  */
226
361
 
227
362
  /*
@@ -231,15 +366,15 @@ static void bfile_close(oci8_lob_t *lob)
231
366
  */
232
367
  static VALUE oci8_lob_close(VALUE self)
233
368
  {
234
- oci8_lob_t *lob = DATA_PTR(self);
369
+ oci8_lob_t *lob = TO_LOB(self);
235
370
  lob_close(lob);
236
- oci8_base_free(DATA_PTR(self));
371
+ oci8_base_free(&lob->base);
237
372
  return self;
238
373
  }
239
374
 
240
375
  static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm, ub1 lobtype)
241
376
  {
242
- oci8_lob_t *lob = DATA_PTR(self);
377
+ oci8_lob_t *lob = TO_LOB(self);
243
378
  VALUE svc;
244
379
  VALUE val;
245
380
  oci8_svcctx_t *svcctx;
@@ -256,8 +391,9 @@ static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm
256
391
  lob->csfrm = csfrm;
257
392
  lob->lobtype = lobtype;
258
393
  lob->state = S_NO_OPEN_CLOSE;
259
- oci8_link_to_parent((oci8_base_t*)lob, (oci8_base_t*)DATA_PTR(svc));
394
+ oci8_link_to_parent(&lob->base, &svcctx->base);
260
395
  lob->svcctx = svcctx;
396
+ RB_OBJ_WRITTEN(self, Qundef, svc);
261
397
  if (!NIL_P(val)) {
262
398
  OCI8StringValue(val);
263
399
  chker2(OCILobCreateTemporary_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, 0, csfrm, lobtype, TRUE, OCI_DURATION_SESSION),
@@ -346,7 +482,7 @@ static VALUE oci8_blob_initialize(int argc, VALUE *argv, VALUE self)
346
482
  */
347
483
  static VALUE oci8_lob_set_char_width(VALUE self, VALUE vsize)
348
484
  {
349
- oci8_lob_t *lob = DATA_PTR(self);
485
+ oci8_lob_t *lob = TO_LOB(self);
350
486
  int size;
351
487
 
352
488
  size = NUM2INT(vsize); /* 1 */
@@ -364,7 +500,7 @@ static VALUE oci8_lob_set_char_width(VALUE self, VALUE vsize)
364
500
  */
365
501
  static VALUE oci8_lob_available_p(VALUE self)
366
502
  {
367
- oci8_lob_t *lob = DATA_PTR(self);
503
+ oci8_lob_t *lob = TO_LOB(self);
368
504
  boolean is_initialized;
369
505
 
370
506
  chker2(OCILobLocatorIsInit(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_initialized),
@@ -381,7 +517,7 @@ static VALUE oci8_lob_available_p(VALUE self)
381
517
  */
382
518
  static VALUE oci8_lob_get_size(VALUE self)
383
519
  {
384
- return UB4_TO_NUM(oci8_lob_get_length(DATA_PTR(self)));
520
+ return UB4_TO_NUM(oci8_lob_get_length(TO_LOB(self)));
385
521
  }
386
522
 
387
523
  /*
@@ -393,7 +529,7 @@ static VALUE oci8_lob_get_size(VALUE self)
393
529
  */
394
530
  static VALUE oci8_lob_get_pos(VALUE self)
395
531
  {
396
- oci8_lob_t *lob = DATA_PTR(self);
532
+ oci8_lob_t *lob = TO_LOB(self);
397
533
  return UB4_TO_NUM(lob->pos);
398
534
  }
399
535
 
@@ -404,7 +540,7 @@ static VALUE oci8_lob_get_pos(VALUE self)
404
540
  */
405
541
  static VALUE oci8_lob_eof_p(VALUE self)
406
542
  {
407
- oci8_lob_t *lob = DATA_PTR(self);
543
+ oci8_lob_t *lob = TO_LOB(self);
408
544
  if (oci8_lob_get_length(lob) < lob->pos)
409
545
  return Qfalse;
410
546
  else
@@ -427,7 +563,7 @@ static VALUE oci8_lob_eof_p(VALUE self)
427
563
  */
428
564
  static VALUE oci8_lob_seek(int argc, VALUE *argv, VALUE self)
429
565
  {
430
- oci8_lob_t *lob = DATA_PTR(self);
566
+ oci8_lob_t *lob = TO_LOB(self);
431
567
  VALUE position, whence;
432
568
 
433
569
  rb_scan_args(argc, argv, "11", &position, &whence);
@@ -456,7 +592,7 @@ static VALUE oci8_lob_seek(int argc, VALUE *argv, VALUE self)
456
592
  */
457
593
  static VALUE oci8_lob_rewind(VALUE self)
458
594
  {
459
- oci8_lob_t *lob = DATA_PTR(self);
595
+ oci8_lob_t *lob = TO_LOB(self);
460
596
  lob->pos = 0;
461
597
  return self;
462
598
  }
@@ -465,14 +601,14 @@ static VALUE oci8_lob_rewind(VALUE self)
465
601
  * call-seq:
466
602
  * truncate(length)
467
603
  *
468
- * Changes the lob size to the given <i>length</i>.
469
- *
470
- * @param [Integer] length
604
+ * @param [Integer] length length in characters if +self+ is a {CLOB} or a {NCLOB}.
605
+ * length in bytes if +self+ is a {BLOB} or a {BFILE}.
471
606
  * @return [self]
607
+ * @see #size=
472
608
  */
473
609
  static VALUE oci8_lob_truncate(VALUE self, VALUE len)
474
610
  {
475
- oci8_lob_t *lob = DATA_PTR(self);
611
+ oci8_lob_t *lob = TO_LOB(self);
476
612
  oci8_svcctx_t *svcctx = check_svcctx(lob);
477
613
 
478
614
  lob_open(lob);
@@ -482,13 +618,13 @@ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
482
618
  }
483
619
 
484
620
  /*
485
- * call-seq:
486
- * size = length
621
+ * @overload size=(length)
487
622
  *
488
623
  * Changes the lob size to the given <i>length</i>.
489
624
  *
490
- * @param [Integer] length
491
- * @return [Integer]
625
+ * @param [Integer] length length in characters if +self+ is a {CLOB} or a {NCLOB}.
626
+ * length in bytes if +self+ is a {BLOB} or a {BFILE}.
627
+ * @see #truncate
492
628
  */
493
629
  static VALUE oci8_lob_set_size(VALUE self, VALUE len)
494
630
  {
@@ -497,29 +633,37 @@ static VALUE oci8_lob_set_size(VALUE self, VALUE len)
497
633
  }
498
634
 
499
635
  /*
500
- * call-seq:
501
- * read(length = nil)
636
+ * @overload read
502
637
  *
503
- * Reads <i>length</i> characters for CLOB and NCLOB or <i>length</i>
504
- * bytes for BLOB and BILF from the current position.
505
- * If <i>length</i> is <code>nil</code>, it reads data until EOF.
638
+ *
639
+ *
640
+ * @param [Integer] length number of characters if +self+ is a {CLOB} or a {NCLOB}.
641
+ * number of bytes if +self+ is a {BLOB} or a {BFILE}.
642
+ * @return [String or nil] data read. <code>nil</code> means it
643
+ * met EOF at beginning. It returns an empty string '' as a special exception
644
+ * when <i>length</i> is <code>nil</code> and the lob is empty.
506
645
  *
507
- * It returns a string or <code>nil</code>. <code>nil</code> means it
508
- * met EOF at beginning. As a special exception, when <i>length</i> is
509
- * <code>nil</code> and the lob length is zero, it returns an empty string ''.
646
+ * @overload read(length)
510
647
  *
511
- * @param [Integer] length
512
- * @return [String or nil]
648
+ * Reads <i>length</i> characters for {CLOB} and {NCLOB} or <i>length</i>
649
+ * bytes for {BLOB} and {BFILE} from the current position.
650
+ * If <i>length</i> is <code>nil</code>, it reads data until EOF.
651
+ *
652
+ * @param [Integer] length number of characters if +self+ is a {CLOB} or a {NCLOB}.
653
+ * number of bytes if +self+ is a {BLOB} or a {BFILE}.
654
+ * @return [String or nil] data read. <code>nil</code> means it
655
+ * met EOF at beginning. It returns an empty string '' as a special exception
656
+ * when <i>length</i> is <code>nil</code> and the lob is empty.
513
657
  */
514
658
  static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
515
659
  {
516
- oci8_lob_t *lob = DATA_PTR(self);
660
+ oci8_lob_t *lob = TO_LOB(self);
517
661
  oci8_svcctx_t *svcctx = check_svcctx(lob);
518
662
  ub4 length;
519
663
  ub4 nchar;
664
+ long nbyte;
520
665
  ub4 amt;
521
666
  sword rv;
522
- char buf[8192];
523
667
  size_t buf_size_in_char;
524
668
  VALUE size;
525
669
  VALUE v = rb_ary_new();
@@ -539,9 +683,13 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
539
683
  if (nchar > length)
540
684
  nchar = length;
541
685
  }
686
+ nbyte = oci8_nls_ratio * (long)nchar;
542
687
  amt = nchar;
543
- buf_size_in_char = sizeof(buf) / lob->char_width;
688
+ buf_size_in_char = nbyte / lob->char_width;
544
689
  do {
690
+ VALUE strbuf = rb_str_buf_new(nbyte);
691
+ char *buf = RSTRING_PTR(strbuf);
692
+
545
693
  if (lob->state == S_BFILE_CLOSE) {
546
694
  rv = OCILobFileOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_FILE_READONLY);
547
695
  if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22290) {
@@ -564,8 +712,8 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
564
712
  lob->state = S_BFILE_OPEN;
565
713
  }
566
714
  /* initialize buf in zeros everytime to check a nul characters. */
567
- memset(buf, 0, sizeof(buf));
568
- 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);
715
+ memset(buf, 0, nbyte);
716
+ rv = OCILobRead_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, buf, nbyte, NULL, NULL, 0, lob->csfrm);
569
717
  svcctx->suppress_free_temp_lobs = 0;
570
718
  switch (rv) {
571
719
  case OCI_SUCCESS:
@@ -594,7 +742,7 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
594
742
  * amt is increaded until a nul character to know the actually
595
743
  * read size.
596
744
  */
597
- while (amt < sizeof(buf) && buf[amt] != '\0') {
745
+ while (amt < nbyte && buf[amt] != '\0') {
598
746
  amt++;
599
747
  }
600
748
 
@@ -604,17 +752,23 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
604
752
  if (amt > buf_size_in_char)
605
753
  rb_raise(eOCIException, "Too large buffer fetched or you set too large size of a character.");
606
754
  amt *= lob->char_width;
607
- rb_ary_push(v, rb_str_new(buf, amt));
755
+ rb_str_set_len(strbuf, amt);
756
+ rb_ary_push(v, strbuf);
608
757
  } while (rv == OCI_NEED_DATA);
609
758
  lob->pos += nchar;
610
759
  if (nchar == length) {
611
760
  lob_close(lob);
612
761
  bfile_close(lob);
613
762
  }
614
- if (RARRAY_LEN(v) == 0) {
763
+ switch (RARRAY_LEN(v)) {
764
+ case 0:
615
765
  return Qnil;
766
+ case 1:
767
+ v = RARRAY_PTR(v)[0];
768
+ break;
769
+ default:
770
+ v = rb_ary_join(v, Qnil);
616
771
  }
617
- v = rb_ary_join(v, Qnil);
618
772
  OBJ_TAINT(v);
619
773
  if (lob->lobtype == OCI_TEMP_CLOB) {
620
774
  /* set encoding */
@@ -627,17 +781,17 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
627
781
  }
628
782
 
629
783
  /*
630
- * call-seq:
631
- * write(data)
784
+ * @overload write(data)
632
785
  *
633
- * Writes <i>data</i>.
786
+ * Writes +data+ to LOB.
634
787
  *
635
788
  * @param [String] data
636
- * @return [Integer]
789
+ * @return [Integer] number of characters written if +self+ is a {CLOB} or a {NCLOB}.
790
+ * number of bytes written if +self+ is a {BLOB} or a {BFILE}.
637
791
  */
638
792
  static VALUE oci8_lob_write(VALUE self, VALUE data)
639
793
  {
640
- oci8_lob_t *lob = DATA_PTR(self);
794
+ oci8_lob_t *lob = TO_LOB(self);
641
795
  oci8_svcctx_t *svcctx = check_svcctx(lob);
642
796
  ub4 amt;
643
797
 
@@ -666,7 +820,7 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
666
820
  */
667
821
  static VALUE oci8_lob_get_sync(VALUE self)
668
822
  {
669
- oci8_lob_t *lob = DATA_PTR(self);
823
+ oci8_lob_t *lob = TO_LOB(self);
670
824
  return (lob->state == S_NO_OPEN_CLOSE) ? Qtrue : Qfalse;
671
825
  }
672
826
 
@@ -676,7 +830,7 @@ static VALUE oci8_lob_get_sync(VALUE self)
676
830
  */
677
831
  static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
678
832
  {
679
- oci8_lob_t *lob = DATA_PTR(self);
833
+ oci8_lob_t *lob = TO_LOB(self);
680
834
  if (RTEST(b)) {
681
835
  lob_close(lob);
682
836
  lob->state = S_NO_OPEN_CLOSE;
@@ -693,7 +847,7 @@ static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
693
847
  */
694
848
  static VALUE oci8_lob_flush(VALUE self)
695
849
  {
696
- oci8_lob_t *lob = DATA_PTR(self);
850
+ oci8_lob_t *lob = TO_LOB(self);
697
851
  lob_close(lob);
698
852
  return self;
699
853
  }
@@ -701,12 +855,12 @@ static VALUE oci8_lob_flush(VALUE self)
701
855
  /*
702
856
  * Returns the chunk size of a LOB.
703
857
  *
704
- * @see http://docs.oracle.com/cd/E16338_01/appdev.112/e10646/oci17msc002.htm#i493090
858
+ * @see http://docs.oracle.com/database/121/ARPLS/d_lob.htm#ARPLS66706 DBMS_LOB.GETCHUNKSIZE
705
859
  * @return [Integer]
706
860
  */
707
861
  static VALUE oci8_lob_get_chunk_size(VALUE self)
708
862
  {
709
- oci8_lob_t *lob = DATA_PTR(self);
863
+ oci8_lob_t *lob = TO_LOB(self);
710
864
  oci8_svcctx_t *svcctx = check_svcctx(lob);
711
865
  ub4 len;
712
866
 
@@ -717,7 +871,7 @@ static VALUE oci8_lob_get_chunk_size(VALUE self)
717
871
 
718
872
  static VALUE oci8_lob_clone(VALUE self)
719
873
  {
720
- oci8_lob_t *lob = DATA_PTR(self);
874
+ oci8_lob_t *lob = TO_LOB(self);
721
875
  oci8_lob_t *newlob;
722
876
  VALUE newobj = lob->svcctx ? lob->svcctx->base.self : Qnil;
723
877
  boolean is_temporary;
@@ -749,7 +903,7 @@ static void oci8_bfile_get_name(VALUE self, VALUE *dir_alias_p, VALUE *filename_
749
903
  need_get = 1;
750
904
  }
751
905
  if (need_get) {
752
- oci8_lob_t *lob = DATA_PTR(self);
906
+ oci8_lob_t *lob = TO_LOB(self);
753
907
  char d_buf[31];
754
908
  ub2 d_length = sizeof(d_buf);
755
909
  char f_buf[256];
@@ -774,7 +928,7 @@ static void oci8_bfile_get_name(VALUE self, VALUE *dir_alias_p, VALUE *filename_
774
928
 
775
929
  static void oci8_bfile_set_name(VALUE self, VALUE dir_alias, VALUE filename)
776
930
  {
777
- oci8_lob_t *lob = DATA_PTR(self);
931
+ oci8_lob_t *lob = TO_LOB(self);
778
932
 
779
933
  bfile_close(lob);
780
934
  if (RSTRING_LEN(dir_alias) > UB2MAXVAL) {
@@ -790,21 +944,20 @@ static void oci8_bfile_set_name(VALUE self, VALUE dir_alias, VALUE filename)
790
944
  }
791
945
 
792
946
  /*
793
- * call-seq:
794
- * initialize(conn, dir_alias = nil, filename = nil)
947
+ * @overload initialize(conn, directory = nil, filename = nil)
795
948
  *
796
949
  * Creates a BFILE object.
797
- * This is correspond to {http://docs.oracle.com/cd/E11882_01/server.112/e17118/functions019.htm#sthref953 BFILENAME}.
950
+ * This is correspond to {BFILENAME}[https://docs.oracle.com/database/121/SQLRF/functions020.htm].
798
951
  *
799
952
  * @param [OCI8] conn
800
- * @param [String] dir_alias a directory object created by
801
- * {http://docs.oracle.com/cd/E11882_01/server.112/e17118/statements_5007.htm "CREATE DIRECTORY"}.
953
+ * @param [String] directory a directory object created by
954
+ * {"CREATE DIRECTORY"}[http://docs.oracle.com/database/121/SQLRF/statements_5008.htm].
802
955
  * @param [String] filename
803
956
  * @return [OCI8::BFILE]
804
957
  */
805
958
  static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
806
959
  {
807
- oci8_lob_t *lob = DATA_PTR(self);
960
+ oci8_lob_t *lob = TO_LOB(self);
808
961
  VALUE svc;
809
962
  VALUE dir_alias;
810
963
  VALUE filename;
@@ -828,12 +981,14 @@ static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
828
981
  OCI8SafeStringValue(filename);
829
982
  oci8_bfile_set_name(self, dir_alias, filename);
830
983
  }
831
- oci8_link_to_parent((oci8_base_t*)lob, (oci8_base_t*)DATA_PTR(svc));
984
+ oci8_link_to_parent(&lob->base, &svcctx->base);
832
985
  lob->svcctx = svcctx;
833
986
  return Qnil;
834
987
  }
835
988
 
836
989
  /*
990
+ * @overload dir_alias
991
+ *
837
992
  * Returns the directory object name.
838
993
  *
839
994
  * @return [String]
@@ -847,6 +1002,8 @@ static VALUE oci8_bfile_get_dir_alias(VALUE self)
847
1002
  }
848
1003
 
849
1004
  /*
1005
+ * @overload filename
1006
+ *
850
1007
  * Returns the file name.
851
1008
  *
852
1009
  * @return [String]
@@ -860,12 +1017,11 @@ static VALUE oci8_bfile_get_filename(VALUE self)
860
1017
  }
861
1018
 
862
1019
  /*
863
- * call-seq:
864
- * dir_alias = name
1020
+ * @overload dir_alias=(dir_alias)
865
1021
  *
866
1022
  * Changes the directory object name.
867
1023
  *
868
- * @param [String] name
1024
+ * @param [String] dir_alias
869
1025
  */
870
1026
  static VALUE oci8_bfile_set_dir_alias(VALUE self, VALUE dir_alias)
871
1027
  {
@@ -879,12 +1035,11 @@ static VALUE oci8_bfile_set_dir_alias(VALUE self, VALUE dir_alias)
879
1035
  }
880
1036
 
881
1037
  /*
882
- * call-seq:
883
- * filename = name
1038
+ * @overload filename=(filename)
884
1039
  *
885
1040
  * Changes the file name.
886
1041
  *
887
- * @param [String] name
1042
+ * @param [String] filename
888
1043
  */
889
1044
  static VALUE oci8_bfile_set_filename(VALUE self, VALUE filename)
890
1045
  {
@@ -898,13 +1053,13 @@ static VALUE oci8_bfile_set_filename(VALUE self, VALUE filename)
898
1053
  }
899
1054
 
900
1055
  /*
901
- * Returns <code>true</code> when the BFILE exists on the server's operating system.
1056
+ * @overload exists?
902
1057
  *
903
- * @return [true or false]
1058
+ * Returns <code>true</code> when the BFILE exists on the server's operating system.
904
1059
  */
905
1060
  static VALUE oci8_bfile_exists_p(VALUE self)
906
1061
  {
907
- oci8_lob_t *lob = DATA_PTR(self);
1062
+ oci8_lob_t *lob = TO_LOB(self);
908
1063
  oci8_svcctx_t *svcctx = check_svcctx(lob);
909
1064
  boolean flag;
910
1065
 
@@ -914,38 +1069,10 @@ static VALUE oci8_bfile_exists_p(VALUE self)
914
1069
  }
915
1070
 
916
1071
  /*
917
- * Document-method: OCI8::BFILE#truncate
918
- *
919
- * call-seq:
920
- * truncate(length)
921
- *
922
- * Raises <code>RuntimeError</code>.
923
- *
924
- * @raise [RuntimeError] cannot modify a read-only BFILE object
925
- */
926
-
927
- /*
928
- * Document-method: OCI8::BFILE#size=
929
- *
930
- * call-seq:
931
- * size = length
932
- *
933
- * Raises <code>RuntimeError</code>.
934
- *
935
- * @raise [RuntimeError] cannot modify a read-only BFILE object
936
- */
937
-
938
- /*
939
- * Document-method: OCI8::BFILE#write
940
- *
941
- * call-seq:
942
- * write(data)
943
- *
944
- * Raises <code>RuntimeError</code>.
1072
+ * Raises <code>RuntimeError</code> always.
945
1073
  *
946
1074
  * @raise [RuntimeError] cannot modify a read-only BFILE object
947
1075
  */
948
-
949
1076
  static VALUE oci8_bfile_error(VALUE self, VALUE dummy)
950
1077
  {
951
1078
  rb_raise(rb_eRuntimeError, "cannot modify a read-only BFILE object");
@@ -956,9 +1083,9 @@ static VALUE oci8_bfile_error(VALUE self, VALUE dummy)
956
1083
  */
957
1084
 
958
1085
  typedef struct {
959
- oci8_bind_vtable_t bind;
1086
+ oci8_bind_data_type_t bind;
960
1087
  VALUE *klass;
961
- } oci8_bind_lob_vtable_t;
1088
+ } oci8_bind_lob_data_type_t;
962
1089
 
963
1090
  static VALUE bind_lob_get(oci8_bind_t *obind, void *data, void *null_struct)
964
1091
  {
@@ -969,13 +1096,11 @@ static VALUE bind_lob_get(oci8_bind_t *obind, void *data, void *null_struct)
969
1096
  static void bind_lob_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
970
1097
  {
971
1098
  oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
972
- const oci8_bind_lob_vtable_t *vptr = (const oci8_bind_lob_vtable_t *)obind->base.vptr;
973
- oci8_base_t *h;
974
- if (!rb_obj_is_kind_of(val, *vptr->klass))
975
- rb_raise(rb_eArgError, "Invalid argument: %s (expect %s)", rb_class2name(CLASS_OF(val)), rb_class2name(*vptr->klass));
976
- h = DATA_PTR(val);
1099
+ const oci8_handle_data_type_t *bind_data_type = obind->base.data_type;
1100
+ const oci8_handle_data_type_t *lob_data_type = bind_data_type->rb_data_type.data;
1101
+ oci8_base_t *h = oci8_check_typeddata(val, lob_data_type, 1);
977
1102
  oho->hp = h->hp.ptr;
978
- oho->obj = val;
1103
+ RB_OBJ_WRITE(obind->base.self, &oho->obj, val);
979
1104
  }
980
1105
 
981
1106
  static void bind_lob_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
@@ -986,13 +1111,14 @@ static void bind_lob_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length
986
1111
 
987
1112
  static void bind_lob_init_elem(oci8_bind_t *obind, VALUE svc)
988
1113
  {
989
- const oci8_bind_lob_vtable_t *vptr = (const oci8_bind_lob_vtable_t *)obind->base.vptr;
1114
+ const oci8_bind_lob_data_type_t *data_type = (const oci8_bind_lob_data_type_t *)obind->base.data_type;
990
1115
  oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
991
1116
  oci8_base_t *h;
992
1117
  ub4 idx = 0;
993
1118
 
994
1119
  do {
995
- oho[idx].obj = rb_class_new_instance(1, &svc, *vptr->klass);
1120
+ oho[idx].obj = rb_class_new_instance(1, &svc, *data_type->klass);
1121
+ RB_OBJ_WRITTEN(obind->base.self, Qundef, oho[idx].obj);
996
1122
  h = DATA_PTR(oho[idx].obj);
997
1123
  oho[idx].hp = h->hp.ptr;
998
1124
  } while (++idx < obind->maxar_sz);
@@ -1006,10 +1132,21 @@ static void bind_lob_post_bind_hook_for_nclob(oci8_bind_t *obind)
1006
1132
  &obind->base);
1007
1133
  }
1008
1134
 
1009
- static const oci8_bind_lob_vtable_t bind_clob_vtable = {
1135
+ static const oci8_bind_lob_data_type_t bind_clob_data_type = {
1010
1136
  {
1011
1137
  {
1012
- oci8_bind_hp_obj_mark,
1138
+ {
1139
+ "OCI8::BindType::CLOB",
1140
+ {
1141
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1142
+ oci8_handle_cleanup,
1143
+ oci8_handle_size,
1144
+ },
1145
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_clob_data_type,
1146
+ #ifdef RUBY_TYPED_WB_PROTECTED
1147
+ RUBY_TYPED_WB_PROTECTED,
1148
+ #endif
1149
+ },
1013
1150
  oci8_bind_free,
1014
1151
  sizeof(oci8_bind_t)
1015
1152
  },
@@ -1023,10 +1160,26 @@ static const oci8_bind_lob_vtable_t bind_clob_vtable = {
1023
1160
  &cOCI8CLOB
1024
1161
  };
1025
1162
 
1026
- static const oci8_bind_lob_vtable_t bind_nclob_vtable = {
1163
+ static VALUE bind_clob_alloc(VALUE klass)
1164
+ {
1165
+ return oci8_allocate_typeddata(klass, &bind_clob_data_type.bind.base);
1166
+ }
1167
+
1168
+ static const oci8_bind_lob_data_type_t bind_nclob_data_type = {
1027
1169
  {
1028
1170
  {
1029
- oci8_bind_hp_obj_mark,
1171
+ {
1172
+ "OCI8::BindType::NCLOB",
1173
+ {
1174
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1175
+ oci8_handle_cleanup,
1176
+ oci8_handle_size,
1177
+ },
1178
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_nclob_data_type,
1179
+ #ifdef RUBY_TYPED_WB_PROTECTED
1180
+ RUBY_TYPED_WB_PROTECTED,
1181
+ #endif
1182
+ },
1030
1183
  oci8_bind_free,
1031
1184
  sizeof(oci8_bind_t)
1032
1185
  },
@@ -1041,10 +1194,26 @@ static const oci8_bind_lob_vtable_t bind_nclob_vtable = {
1041
1194
  &cOCI8NCLOB
1042
1195
  };
1043
1196
 
1044
- static const oci8_bind_lob_vtable_t bind_blob_vtable = {
1197
+ static VALUE bind_nclob_alloc(VALUE klass)
1198
+ {
1199
+ return oci8_allocate_typeddata(klass, &bind_nclob_data_type.bind.base);
1200
+ }
1201
+
1202
+ static const oci8_bind_lob_data_type_t bind_blob_data_type = {
1045
1203
  {
1046
1204
  {
1047
- oci8_bind_hp_obj_mark,
1205
+ {
1206
+ "OCI8::BindType::BLOB",
1207
+ {
1208
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1209
+ oci8_handle_cleanup,
1210
+ oci8_handle_size,
1211
+ },
1212
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_blob_data_type,
1213
+ #ifdef RUBY_TYPED_WB_PROTECTED
1214
+ RUBY_TYPED_WB_PROTECTED,
1215
+ #endif
1216
+ },
1048
1217
  oci8_bind_free,
1049
1218
  sizeof(oci8_bind_t)
1050
1219
  },
@@ -1058,10 +1227,26 @@ static const oci8_bind_lob_vtable_t bind_blob_vtable = {
1058
1227
  &cOCI8BLOB
1059
1228
  };
1060
1229
 
1061
- static const oci8_bind_lob_vtable_t bind_bfile_vtable = {
1230
+ static VALUE bind_blob_alloc(VALUE klass)
1231
+ {
1232
+ return oci8_allocate_typeddata(klass, &bind_blob_data_type.bind.base);
1233
+ }
1234
+
1235
+ static const oci8_bind_lob_data_type_t bind_bfile_data_type = {
1062
1236
  {
1063
1237
  {
1064
- oci8_bind_hp_obj_mark,
1238
+ {
1239
+ "OCI8::BindType::BFILE",
1240
+ {
1241
+ (RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
1242
+ oci8_handle_cleanup,
1243
+ oci8_handle_size,
1244
+ },
1245
+ &oci8_bind_data_type.rb_data_type, (void*)&oci8_bfile_data_type,
1246
+ #ifdef RUBY_TYPED_WB_PROTECTED
1247
+ RUBY_TYPED_WB_PROTECTED,
1248
+ #endif
1249
+ },
1065
1250
  oci8_bind_free,
1066
1251
  sizeof(oci8_bind_t)
1067
1252
  },
@@ -1075,6 +1260,11 @@ static const oci8_bind_lob_vtable_t bind_bfile_vtable = {
1075
1260
  &cOCI8BFILE
1076
1261
  };
1077
1262
 
1263
+ static VALUE bind_bfile_alloc(VALUE klass)
1264
+ {
1265
+ return oci8_allocate_typeddata(klass, &bind_bfile_data_type.bind.base);
1266
+ }
1267
+
1078
1268
  void Init_oci8_lob(VALUE cOCI8)
1079
1269
  {
1080
1270
  id_plus = rb_intern("+");
@@ -1085,16 +1275,21 @@ void Init_oci8_lob(VALUE cOCI8)
1085
1275
  seek_end = rb_eval_string("::IO::SEEK_END");
1086
1276
 
1087
1277
  #if 0
1278
+ /* for yard */
1088
1279
  cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
1089
1280
  cOCI8 = rb_define_class("OCI8", cOCIHandle);
1090
1281
  cOCI8LOB = rb_define_class_under(cOCI8, "LOB", cOCIHandle);
1091
- #endif
1092
-
1093
- cOCI8LOB = oci8_define_class_under(cOCI8, "LOB", &oci8_lob_vtable);
1094
1282
  cOCI8CLOB = rb_define_class_under(cOCI8, "CLOB", cOCI8LOB);
1095
1283
  cOCI8NCLOB = rb_define_class_under(cOCI8, "NCLOB", cOCI8LOB);
1096
1284
  cOCI8BLOB = rb_define_class_under(cOCI8, "BLOB", cOCI8LOB);
1097
1285
  cOCI8BFILE = rb_define_class_under(cOCI8, "BFILE", cOCI8LOB);
1286
+ #endif
1287
+
1288
+ cOCI8LOB = oci8_define_class_under(cOCI8, "LOB", &oci8_lob_data_type, oci8_lob_alloc);
1289
+ cOCI8CLOB = oci8_define_class_under(cOCI8, "CLOB", &oci8_clob_data_type, oci8_clob_alloc);
1290
+ cOCI8NCLOB = oci8_define_class_under(cOCI8, "NCLOB", &oci8_nclob_data_type, oci8_nclob_alloc);
1291
+ cOCI8BLOB = oci8_define_class_under(cOCI8, "BLOB", &oci8_blob_data_type, oci8_blob_alloc);
1292
+ cOCI8BFILE = oci8_define_class_under(cOCI8, "BFILE", &oci8_bfile_data_type, oci8_bfile_alloc);
1098
1293
 
1099
1294
  rb_define_method(cOCI8CLOB, "initialize", oci8_clob_initialize, -1);
1100
1295
  rb_define_method(cOCI8NCLOB, "initialize", oci8_nclob_initialize, -1);
@@ -1127,8 +1322,8 @@ void Init_oci8_lob(VALUE cOCI8)
1127
1322
  rb_define_method(cOCI8BFILE, "size=", oci8_bfile_error, 1);
1128
1323
  rb_define_method(cOCI8BFILE, "write", oci8_bfile_error, 1);
1129
1324
 
1130
- oci8_define_bind_class("CLOB", &bind_clob_vtable.bind);
1131
- oci8_define_bind_class("NCLOB", &bind_nclob_vtable.bind);
1132
- oci8_define_bind_class("BLOB", &bind_blob_vtable.bind);
1133
- oci8_define_bind_class("BFILE", &bind_bfile_vtable.bind);
1325
+ oci8_define_bind_class("CLOB", &bind_clob_data_type.bind, bind_clob_alloc);
1326
+ oci8_define_bind_class("NCLOB", &bind_nclob_data_type.bind, bind_nclob_alloc);
1327
+ oci8_define_bind_class("BLOB", &bind_blob_data_type.bind, bind_blob_alloc);
1328
+ oci8_define_bind_class("BFILE", &bind_bfile_data_type.bind, bind_bfile_alloc);
1134
1329
  }