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.
- data/ChangeLog +136 -0
- data/NEWS +61 -0
- data/README.md +2 -2
- data/VERSION +1 -1
- data/dist-files +5 -0
- data/docs/install-instant-client.md +2 -0
- data/ext/oci8/attr.c +0 -9
- data/ext/oci8/bind.c +86 -28
- data/ext/oci8/connection_pool.c +32 -17
- data/ext/oci8/extconf.rb +21 -0
- data/ext/oci8/hook_funcs.c +215 -0
- data/ext/oci8/lob.c +363 -168
- data/ext/oci8/metadata.c +43 -26
- data/ext/oci8/object.c +115 -36
- data/ext/oci8/oci8.c +392 -269
- data/ext/oci8/oci8.h +88 -33
- data/ext/oci8/oci8lib.c +59 -28
- data/ext/oci8/ocidatetime.c +100 -36
- data/ext/oci8/ocihandle.c +288 -286
- data/ext/oci8/ocinumber.c +172 -112
- data/ext/oci8/oradate.c +129 -87
- data/ext/oci8/plthook.h +56 -0
- data/ext/oci8/plthook_elf.c +537 -0
- data/ext/oci8/plthook_osx.c +474 -0
- data/ext/oci8/plthook_win32.c +376 -0
- data/ext/oci8/stmt.c +112 -75
- data/lib/oci8/cursor.rb +1 -1
- data/lib/oci8/oci8.rb +71 -0
- data/lib/oci8/properties.rb +18 -3
- metadata +10 -16
data/ext/oci8/connection_pool.c
CHANGED
@@ -2,13 +2,15 @@
|
|
2
2
|
/*
|
3
3
|
* connection_pool.c - part of ruby-oci8
|
4
4
|
*
|
5
|
-
* Copyright (C) 2010
|
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
|
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
|
-
|
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 =
|
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
|
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 =
|
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 =
|
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", &
|
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);
|
data/ext/oci8/extconf.rb
CHANGED
@@ -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
|
+
}
|
data/ext/oci8/lob.c
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
/*
|
3
3
|
* lob.c - part of ruby-oci8
|
4
4
|
*
|
5
|
-
* Copyright (C) 2002-
|
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 =
|
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 =
|
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
|
-
*
|
223
|
-
*
|
224
|
-
*
|
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 =
|
369
|
+
oci8_lob_t *lob = TO_LOB(self);
|
235
370
|
lob_close(lob);
|
236
|
-
oci8_base_free(
|
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 =
|
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(
|
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 =
|
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 =
|
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(
|
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 =
|
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 =
|
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 =
|
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 =
|
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
|
-
*
|
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 =
|
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
|
-
*
|
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
|
-
*
|
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
|
-
*
|
501
|
-
* read(length = nil)
|
636
|
+
* @overload read
|
502
637
|
*
|
503
|
-
*
|
504
|
-
*
|
505
|
-
*
|
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
|
-
*
|
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
|
-
*
|
512
|
-
*
|
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 =
|
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 =
|
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,
|
568
|
-
rv = OCILobRead_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, buf,
|
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 <
|
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
|
-
|
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
|
-
|
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
|
-
*
|
631
|
-
* write(data)
|
784
|
+
* @overload write(data)
|
632
785
|
*
|
633
|
-
* Writes
|
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 =
|
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 =
|
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 =
|
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 =
|
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/
|
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 =
|
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 =
|
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 =
|
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 =
|
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
|
-
*
|
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 {
|
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]
|
801
|
-
* {http://docs.oracle.com/
|
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 =
|
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(
|
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
|
-
*
|
864
|
-
* dir_alias = name
|
1020
|
+
* @overload dir_alias=(dir_alias)
|
865
1021
|
*
|
866
1022
|
* Changes the directory object name.
|
867
1023
|
*
|
868
|
-
* @param [String]
|
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
|
-
*
|
883
|
-
* filename = name
|
1038
|
+
* @overload filename=(filename)
|
884
1039
|
*
|
885
1040
|
* Changes the file name.
|
886
1041
|
*
|
887
|
-
* @param [String]
|
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
|
-
*
|
1056
|
+
* @overload exists?
|
902
1057
|
*
|
903
|
-
*
|
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 =
|
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
|
-
*
|
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
|
-
|
1086
|
+
oci8_bind_data_type_t bind;
|
960
1087
|
VALUE *klass;
|
961
|
-
}
|
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
|
973
|
-
|
974
|
-
|
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
|
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
|
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, *
|
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
|
1135
|
+
static const oci8_bind_lob_data_type_t bind_clob_data_type = {
|
1010
1136
|
{
|
1011
1137
|
{
|
1012
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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", &
|
1131
|
-
oci8_define_bind_class("NCLOB", &
|
1132
|
-
oci8_define_bind_class("BLOB", &
|
1133
|
-
oci8_define_bind_class("BFILE", &
|
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
|
}
|