ruby-oci8 2.1.7 → 2.1.8

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