ruby-oci8 2.1.8 → 2.2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +2 -0
- data/ChangeLog +186 -0
- data/Makefile +2 -2
- data/NEWS +64 -5
- data/README.md +10 -8
- data/dist-files +7 -2
- data/docs/install-instant-client.md +7 -5
- data/docs/install-on-osx.md +132 -0
- data/docs/osx-install-dev-tools.png +0 -0
- data/docs/report-installation-issue.md +1 -4
- data/ext/oci8/apiwrap.c.tmpl +0 -4
- data/ext/oci8/apiwrap.yml +2 -62
- data/ext/oci8/bind.c +1 -3
- data/ext/oci8/encoding.c +56 -168
- data/ext/oci8/env.c +0 -46
- data/ext/oci8/error.c +6 -32
- data/ext/oci8/extconf.rb +33 -39
- data/ext/oci8/lob.c +110 -118
- data/ext/oci8/oci8.c +19 -174
- data/ext/oci8/oci8.h +10 -121
- data/ext/oci8/oci8lib.c +26 -69
- data/ext/oci8/ocidatetime.c +4 -46
- data/ext/oci8/ocinumber.c +7 -30
- data/ext/oci8/oraconf.rb +64 -4
- data/ext/oci8/stmt.c +2 -9
- data/ext/oci8/thread_util.c +0 -4
- data/ext/oci8/thread_util.h +0 -12
- data/ext/oci8/util.c +71 -0
- data/ext/oci8/win32.c +1 -25
- data/lib/{oci8.rb.in → oci8.rb} +11 -3
- data/lib/oci8/bindtype.rb +3 -13
- data/lib/oci8/check_load_error.rb +99 -0
- data/lib/oci8/encoding-init.rb +27 -61
- data/lib/oci8/metadata.rb +27 -57
- data/lib/oci8/oci8.rb +17 -18
- data/lib/oci8/properties.rb +1 -9
- data/lib/oci8/version.rb +3 -0
- data/ruby-oci8.gemspec +15 -5
- data/test/test_oci8.rb +14 -2
- data/test/test_package_type.rb +967 -0
- metadata +28 -11
- data/VERSION +0 -1
data/ext/oci8/env.c
CHANGED
@@ -5,12 +5,7 @@
|
|
5
5
|
* Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
|
6
6
|
*/
|
7
7
|
#include "oci8.h"
|
8
|
-
|
9
|
-
#if defined(HAVE_RUBY_UTIL_H)
|
10
8
|
#include <ruby/util.h>
|
11
|
-
#elif defined(HAVE_UTIL_H)
|
12
|
-
#include <util.h>
|
13
|
-
#endif
|
14
9
|
|
15
10
|
ub4 oci8_env_mode = OCI_OBJECT | OCI_THREADED;
|
16
11
|
|
@@ -27,7 +22,6 @@ OCIEnv *oci8_make_envhp(void)
|
|
27
22
|
return oci8_global_envhp;
|
28
23
|
}
|
29
24
|
|
30
|
-
#ifdef USE_THREAD_LOCAL_ERRHP
|
31
25
|
/*
|
32
26
|
* Setup thread-local oci8_errhp.
|
33
27
|
*/
|
@@ -87,48 +81,10 @@ OCIError *oci8_make_errhp(void)
|
|
87
81
|
oci8_tls_set(oci8_tls_key, (void*)errhp);
|
88
82
|
return errhp;
|
89
83
|
}
|
90
|
-
#else
|
91
|
-
/*
|
92
|
-
* oci8_errhp is global in ruby 1.8 configured without --enable-pthread on Unix.
|
93
|
-
*/
|
94
|
-
OCIError *oci8_global_errhp;
|
95
|
-
|
96
|
-
OCIError *oci8_make_errhp(void)
|
97
|
-
{
|
98
|
-
sword rv;
|
99
|
-
|
100
|
-
rv = OCIHandleAlloc(oci8_envhp, (dvoid *)&oci8_global_errhp, OCI_HTYPE_ERROR, 0, NULL);
|
101
|
-
if (rv != OCI_SUCCESS)
|
102
|
-
oci8_env_raise(oci8_envhp, rv);
|
103
|
-
return oci8_global_errhp;
|
104
|
-
}
|
105
|
-
#endif
|
106
84
|
|
107
85
|
void Init_oci8_env(void)
|
108
86
|
{
|
109
|
-
#ifdef USE_THREAD_LOCAL_ERRHP
|
110
87
|
int error;
|
111
|
-
#endif
|
112
|
-
|
113
|
-
#if !defined(NATIVE_THREAD_WITH_GVL) && !defined(_WIN32)
|
114
|
-
/* workaround code.
|
115
|
-
*
|
116
|
-
* Some instant clients set the environment variables
|
117
|
-
* ORA_NLS_PROFILE33, ORA_NLS10 and ORACLE_HOME if they aren't
|
118
|
-
* set. It causes problems on some platforms.
|
119
|
-
*/
|
120
|
-
if (RTEST(rb_eval_string("RUBY_VERSION == \"1.8.4\""))) {
|
121
|
-
if (getenv("ORA_NLS_PROFILE33") == NULL) {
|
122
|
-
ruby_setenv("ORA_NLS_PROFILE33", "");
|
123
|
-
}
|
124
|
-
if (getenv("ORA_NLS10") == NULL) {
|
125
|
-
ruby_setenv("ORA_NLS10", "");
|
126
|
-
}
|
127
|
-
if (getenv("ORACLE_HOME") == NULL) {
|
128
|
-
ruby_setenv("ORACLE_HOME", ".");
|
129
|
-
}
|
130
|
-
}
|
131
|
-
#endif /* WIN32 */
|
132
88
|
|
133
89
|
/* workaround code.
|
134
90
|
*
|
@@ -156,7 +112,6 @@ void Init_oci8_env(void)
|
|
156
112
|
}
|
157
113
|
}
|
158
114
|
|
159
|
-
#ifdef USE_THREAD_LOCAL_ERRHP
|
160
115
|
#if defined(_WIN32)
|
161
116
|
if (!dllmain_is_called) {
|
162
117
|
/* sanity check */
|
@@ -174,5 +129,4 @@ void Init_oci8_env(void)
|
|
174
129
|
if (error != 0) {
|
175
130
|
rb_raise(rb_eRuntimeError, "Cannot create thread local key (errno = %d)", error);
|
176
131
|
}
|
177
|
-
#endif
|
178
132
|
}
|
data/ext/oci8/error.c
CHANGED
@@ -2,20 +2,10 @@
|
|
2
2
|
/*
|
3
3
|
error.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
|
*/
|
8
|
-
#if defined __linux && !defined(_GNU_SOURCE)
|
9
|
-
#define _GNU_SOURCE 1
|
10
|
-
#endif
|
11
8
|
#include "oci8.h"
|
12
|
-
#ifdef HAVE_DLADDR
|
13
|
-
#include <dlfcn.h>
|
14
|
-
#endif
|
15
|
-
#ifdef __CYGWIN__
|
16
|
-
#undef boolean
|
17
|
-
#include <windows.h>
|
18
|
-
#endif
|
19
9
|
|
20
10
|
#ifndef DLEXT
|
21
11
|
#define DLEXT ".so"
|
@@ -227,22 +217,8 @@ void oci8_do_raise_init_error(const char *file, int line)
|
|
227
217
|
{
|
228
218
|
VALUE msg = rb_usascii_str_new_cstr("OCI Library Initialization Error");
|
229
219
|
VALUE exc;
|
230
|
-
const char *dll_path =
|
231
|
-
|
232
|
-
HMODULE hMod = GetModuleHandleA("OCI.DLL");
|
233
|
-
char buf[MAX_PATH];
|
234
|
-
if (hMod != NULL) {
|
235
|
-
if (GetModuleFileName(hMod, buf, sizeof(buf))) {
|
236
|
-
dll_path = buf;
|
237
|
-
}
|
238
|
-
}
|
239
|
-
#elif defined HAVE_DLADDR
|
240
|
-
void *addr = dlsym(RTLD_DEFAULT, "OCIEnvCreate");
|
241
|
-
Dl_info info;
|
242
|
-
if (addr != NULL && dladdr(addr, &info)) {
|
243
|
-
dll_path = info.dli_fname;
|
244
|
-
}
|
245
|
-
#endif
|
220
|
+
const char *dll_path = oci8_dll_path();
|
221
|
+
|
246
222
|
if (dll_path != NULL) {
|
247
223
|
msg = rb_str_buf_cat_ascii(msg, " - ");
|
248
224
|
msg = rb_enc_str_buf_cat(msg, dll_path, strlen(dll_path), rb_filesystem_encoding());
|
@@ -258,12 +234,10 @@ VALUE oci8_get_error_message(ub4 msgno, const char *default_msg)
|
|
258
234
|
const char *errmsg = NULL;
|
259
235
|
char msgbuf[64];
|
260
236
|
|
261
|
-
if (
|
262
|
-
|
263
|
-
chkerr(OCIMessageOpen(oci8_envhp, oci8_errhp, &msghp, TO_CONST_ORATEXT("rdbms"), TO_CONST_ORATEXT("ora"), OCI_DURATION_PROCESS));
|
264
|
-
}
|
265
|
-
errmsg = TO_CHARPTR(OCIMessageGet(msghp, msgno, NULL, 0));
|
237
|
+
if (msghp == NULL) {
|
238
|
+
chkerr(OCIMessageOpen(oci8_envhp, oci8_errhp, &msghp, TO_CONST_ORATEXT("rdbms"), TO_CONST_ORATEXT("ora"), OCI_DURATION_PROCESS));
|
266
239
|
}
|
240
|
+
errmsg = TO_CHARPTR(OCIMessageGet(msghp, msgno, NULL, 0));
|
267
241
|
if (errmsg == NULL) {
|
268
242
|
if (default_msg != NULL) {
|
269
243
|
errmsg = default_msg;
|
data/ext/oci8/extconf.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
if RUBY_VERSION < "1.9"
|
2
|
+
puts "Ruby-oci8 doesn't work ruby 1.8 since ruby-oci8 2.2.0."
|
3
|
+
exit 1
|
4
|
+
end
|
5
|
+
|
1
6
|
begin
|
2
7
|
require 'mkmf'
|
3
8
|
rescue LoadError
|
@@ -12,24 +17,10 @@ end
|
|
12
17
|
require File.dirname(__FILE__) + '/oraconf'
|
13
18
|
require File.dirname(__FILE__) + '/apiwrap'
|
14
19
|
require File.dirname(__FILE__) + '/../../lib/oci8/oracle_version.rb'
|
15
|
-
|
16
|
-
RUBY_OCI8_VERSION = File.read("#{File.dirname(__FILE__)}/../../VERSION").chomp
|
20
|
+
require File.dirname(__FILE__) + '/../../lib/oci8/version.rb'
|
17
21
|
|
18
22
|
oraconf = OraConf.get()
|
19
23
|
|
20
|
-
def replace_keyword(source, target, replace)
|
21
|
-
puts "creating #{target} from #{source}"
|
22
|
-
open(source, "rb") { |f|
|
23
|
-
buf = f.read
|
24
|
-
replace.each do |key, value|
|
25
|
-
buf.gsub!('@@' + key + '@@', value)
|
26
|
-
end
|
27
|
-
open(target, "wb") {|fw|
|
28
|
-
fw.write buf
|
29
|
-
}
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
24
|
$CFLAGS += oraconf.cflags
|
34
25
|
saved_libs = $libs
|
35
26
|
$libs += oraconf.libs
|
@@ -46,6 +37,8 @@ YAML.load(open(File.dirname(__FILE__) + '/apiwrap.yml')).each do |key, val|
|
|
46
37
|
funcs[ver] ||= []
|
47
38
|
funcs[ver] << key
|
48
39
|
end
|
40
|
+
|
41
|
+
saved_defs = $defs.clone
|
49
42
|
funcs.keys.sort.each do |version|
|
50
43
|
next if version == 0x08000000
|
51
44
|
verstr = format('%d.%d.%d', ((version >> 24) & 0xFF), ((version >> 20) & 0xF), ((version >> 12) & 0xFF))
|
@@ -62,6 +55,7 @@ funcs.keys.sort.each do |version|
|
|
62
55
|
puts "checking for Oracle #{verstr} API - #{result}"
|
63
56
|
break if result == 'fail'
|
64
57
|
end
|
58
|
+
$defs = saved_defs
|
65
59
|
|
66
60
|
have_type('oratext', 'ociap.h')
|
67
61
|
have_type('OCIDateTime*', 'ociap.h')
|
@@ -83,6 +77,25 @@ $defs << "-DORACLE_CLIENT_VERSION=#{format('0x%08x', oci_client_version)}"
|
|
83
77
|
if with_config('runtime-check')
|
84
78
|
$defs << "-DRUNTIME_API_CHECK=1"
|
85
79
|
$libs = saved_libs
|
80
|
+
else
|
81
|
+
oraver = OCI8::OracleVersion.new(oci_client_version)
|
82
|
+
if oraver < OCI8::OracleVersion.new(10)
|
83
|
+
case "#{oraver.major}.#{oraver.minor}"
|
84
|
+
when "8.0"
|
85
|
+
ora_name = "Oracle 8"
|
86
|
+
oci8_ver = "2.0.x"
|
87
|
+
when "8.1"
|
88
|
+
ora_name = "Oracle 8i"
|
89
|
+
oci8_ver = "2.0.x"
|
90
|
+
when "9.1"
|
91
|
+
ora_name = "Oracle 9iR1"
|
92
|
+
oci8_ver = "2.1.x"
|
93
|
+
when "9.2"
|
94
|
+
ora_name = "Oracle 9iR2"
|
95
|
+
oci8_ver = "2.1.x"
|
96
|
+
end
|
97
|
+
raise "Ruby-oci8 #{OCI8::VERSION} doesn't support #{ora_name}. Use ruby-oci8 #{oci8_ver} instead."
|
98
|
+
end
|
86
99
|
end
|
87
100
|
|
88
101
|
$objs = ["oci8lib.o", "env.o", "error.o", "oci8.o", "ocihandle.o",
|
@@ -90,7 +103,7 @@ $objs = ["oci8lib.o", "env.o", "error.o", "oci8.o", "ocihandle.o",
|
|
90
103
|
"stmt.o", "bind.o", "metadata.o", "attr.o",
|
91
104
|
"lob.o", "oradate.o",
|
92
105
|
"ocinumber.o", "ocidatetime.o", "object.o", "apiwrap.o",
|
93
|
-
"encoding.o", "oranumber_util.o", "thread_util.o"]
|
106
|
+
"encoding.o", "oranumber_util.o", "thread_util.o", "util.o"]
|
94
107
|
|
95
108
|
if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/
|
96
109
|
$defs << "-DUSE_WIN32_C"
|
@@ -104,24 +117,13 @@ end
|
|
104
117
|
|
105
118
|
have_func("localtime_r")
|
106
119
|
have_func("dladdr")
|
120
|
+
have_func("dlmodinfo")
|
121
|
+
have_func("dlgetname")
|
107
122
|
|
108
|
-
# ruby 1.8 headers
|
109
|
-
have_header("intern.h")
|
110
|
-
have_header("util.h")
|
111
|
-
# ruby 1.9.1 headers
|
112
|
-
have_header("ruby/util.h")
|
113
|
-
have_type('rb_encoding', ['ruby/ruby.h', 'ruby/encoding.h'])
|
114
123
|
# ruby 2.0.0 headers
|
115
124
|
have_header("ruby/thread.h")
|
116
125
|
|
117
|
-
# $! in C API
|
118
|
-
have_var("ruby_errinfo", "ruby.h") # ruby 1.8
|
119
|
-
have_func("rb_errinfo", "ruby.h") # ruby 1.9
|
120
|
-
|
121
|
-
have_func("rb_str_set_len", "ruby.h")
|
122
|
-
have_func("rb_set_end_proc", "ruby.h")
|
123
126
|
have_func("rb_class_superclass", "ruby.h")
|
124
|
-
have_func("rb_thread_blocking_region", "ruby.h")
|
125
127
|
have_func("rb_thread_call_without_gvl", "ruby/thread.h")
|
126
128
|
have_func("rb_sym2str", "ruby.h")
|
127
129
|
if (defined? RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
@@ -129,15 +131,6 @@ if (defined? RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
|
129
131
|
have_func("rb_enc_str_buf_cat", "ruby.h")
|
130
132
|
end
|
131
133
|
|
132
|
-
# replace files
|
133
|
-
replace = {
|
134
|
-
'OCI8_CLIENT_VERSION' => oraconf.version,
|
135
|
-
'OCI8_MODULE_VERSION' => RUBY_OCI8_VERSION
|
136
|
-
}
|
137
|
-
|
138
|
-
# make ruby script before running create_makefile.
|
139
|
-
replace_keyword(File.dirname(__FILE__) + '/../../lib/oci8.rb.in', '../../lib/oci8.rb', replace)
|
140
|
-
|
141
134
|
ruby_engine = (defined? RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
142
135
|
|
143
136
|
so_basename = 'oci8lib_'
|
@@ -194,6 +187,7 @@ else
|
|
194
187
|
plthook_src = "plthook_elf.c"
|
195
188
|
end
|
196
189
|
if xsystem(cc_command("").gsub(CONFTEST_C, File.dirname(__FILE__) + "/" + plthook_src))
|
190
|
+
File.delete(plthook_src.gsub(/\.c$/, '.' + RbConfig::CONFIG["OBJEXT"]))
|
197
191
|
puts plthook_src
|
198
192
|
$objs << plthook_src.gsub(/\.c$/, '.o')
|
199
193
|
$objs << "hook_funcs.o"
|
@@ -204,7 +198,7 @@ end
|
|
204
198
|
|
205
199
|
$defs << "-DInit_oci8lib=Init_#{so_basename}"
|
206
200
|
$defs << "-Doci8lib=#{so_basename}"
|
207
|
-
$defs << "-DOCI8LIB_VERSION=\\\"#{
|
201
|
+
$defs << "-DOCI8LIB_VERSION=\\\"#{OCI8::VERSION}\\\""
|
208
202
|
$defs << "-DCHAR_IS_NOT_A_SHORTCUT_TO_ID" if ruby_engine != 'ruby'
|
209
203
|
|
210
204
|
create_header()
|
data/ext/oci8/lob.c
CHANGED
@@ -20,6 +20,10 @@ static VALUE seek_end;
|
|
20
20
|
|
21
21
|
#define TO_LOB(obj) ((oci8_lob_t *)oci8_check_typeddata((obj), &oci8_lob_data_type, 1))
|
22
22
|
|
23
|
+
#ifndef MIN
|
24
|
+
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
25
|
+
#endif
|
26
|
+
|
23
27
|
enum state {
|
24
28
|
S_NO_OPEN_CLOSE,
|
25
29
|
S_OPEN,
|
@@ -30,8 +34,7 @@ enum state {
|
|
30
34
|
typedef struct {
|
31
35
|
oci8_base_t base;
|
32
36
|
oci8_svcctx_t *svcctx;
|
33
|
-
|
34
|
-
int char_width;
|
37
|
+
ub8 pos;
|
35
38
|
ub1 csfrm;
|
36
39
|
ub1 lobtype;
|
37
40
|
enum state state;
|
@@ -65,8 +68,6 @@ static void oci8_lob_free(oci8_base_t *base)
|
|
65
68
|
if (svcctx != NULL
|
66
69
|
&& OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS
|
67
70
|
&& is_temporary) {
|
68
|
-
|
69
|
-
#ifdef NATIVE_THREAD_WITH_GVL
|
70
71
|
oci8_temp_lob_t *temp_lob = ALLOC(oci8_temp_lob_t);
|
71
72
|
|
72
73
|
temp_lob->next = svcctx->temp_lobs;
|
@@ -75,10 +76,6 @@ static void oci8_lob_free(oci8_base_t *base)
|
|
75
76
|
lob->base.type = 0;
|
76
77
|
lob->base.closed = 1;
|
77
78
|
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
79
|
}
|
83
80
|
lob->svcctx = NULL;
|
84
81
|
}
|
@@ -259,12 +256,12 @@ void oci8_assign_bfile(oci8_svcctx_t *svcctx, VALUE lob, OCILobLocator **dest)
|
|
259
256
|
oci8_assign_lob(cOCI8BFILE, svcctx, lob, dest);
|
260
257
|
}
|
261
258
|
|
262
|
-
static
|
259
|
+
static ub8 oci8_lob_get_length(oci8_lob_t *lob)
|
263
260
|
{
|
264
261
|
oci8_svcctx_t *svcctx = check_svcctx(lob);
|
265
|
-
|
262
|
+
ub8 len;
|
266
263
|
|
267
|
-
chker2(
|
264
|
+
chker2(OCILobGetLength2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len),
|
268
265
|
&svcctx->base);
|
269
266
|
return len;
|
270
267
|
}
|
@@ -305,6 +302,10 @@ static void bfile_close(oci8_lob_t *lob)
|
|
305
302
|
/*
|
306
303
|
* Document-class: OCI8::LOB
|
307
304
|
*
|
305
|
+
* OCI8::LOB is an I/O object. LOB contents are read from and written
|
306
|
+
* to the Oracle server via an associating connection. When a connection
|
307
|
+
* is closed, associating LOBs are also closed.
|
308
|
+
*
|
308
309
|
* This is the abstract base class of large-object data types; {BFILE}, {BLOB}, {CLOB} and {NCLOB}.
|
309
310
|
*
|
310
311
|
*/
|
@@ -387,7 +388,6 @@ static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm
|
|
387
388
|
oci8_env_raise(oci8_envhp, rv);
|
388
389
|
lob->base.type = OCI_DTYPE_LOB;
|
389
390
|
lob->pos = 0;
|
390
|
-
lob->char_width = 1;
|
391
391
|
lob->csfrm = csfrm;
|
392
392
|
lob->lobtype = lobtype;
|
393
393
|
lob->state = S_NO_OPEN_CLOSE;
|
@@ -473,26 +473,6 @@ static VALUE oci8_blob_initialize(int argc, VALUE *argv, VALUE self)
|
|
473
473
|
return Qnil;
|
474
474
|
}
|
475
475
|
|
476
|
-
/*
|
477
|
-
* call-seq:
|
478
|
-
* __char_width = size
|
479
|
-
*
|
480
|
-
* @private
|
481
|
-
* IMO, nobody need and use this.
|
482
|
-
*/
|
483
|
-
static VALUE oci8_lob_set_char_width(VALUE self, VALUE vsize)
|
484
|
-
{
|
485
|
-
oci8_lob_t *lob = TO_LOB(self);
|
486
|
-
int size;
|
487
|
-
|
488
|
-
size = NUM2INT(vsize); /* 1 */
|
489
|
-
|
490
|
-
if (size <= 0)
|
491
|
-
rb_raise(rb_eArgError, "size must be more than one.");
|
492
|
-
lob->char_width = size;
|
493
|
-
return vsize;
|
494
|
-
}
|
495
|
-
|
496
476
|
/*
|
497
477
|
* Returns +true+ when <i>self</i> is initialized.
|
498
478
|
*
|
@@ -517,7 +497,7 @@ static VALUE oci8_lob_available_p(VALUE self)
|
|
517
497
|
*/
|
518
498
|
static VALUE oci8_lob_get_size(VALUE self)
|
519
499
|
{
|
520
|
-
return
|
500
|
+
return ULL2NUM(oci8_lob_get_length(TO_LOB(self)));
|
521
501
|
}
|
522
502
|
|
523
503
|
/*
|
@@ -530,7 +510,7 @@ static VALUE oci8_lob_get_size(VALUE self)
|
|
530
510
|
static VALUE oci8_lob_get_pos(VALUE self)
|
531
511
|
{
|
532
512
|
oci8_lob_t *lob = TO_LOB(self);
|
533
|
-
return
|
513
|
+
return ULL2NUM(lob->pos);
|
534
514
|
}
|
535
515
|
|
536
516
|
/*
|
@@ -577,11 +557,11 @@ static VALUE oci8_lob_seek(int argc, VALUE *argv, VALUE self)
|
|
577
557
|
}
|
578
558
|
}
|
579
559
|
if (whence == seek_cur) {
|
580
|
-
position = rb_funcall(
|
560
|
+
position = rb_funcall(ULL2NUM(lob->pos), id_plus, 1, position);
|
581
561
|
} else if (whence == seek_end) {
|
582
|
-
position = rb_funcall(
|
562
|
+
position = rb_funcall(ULL2NUM(oci8_lob_get_length(lob)), id_plus, 1, position);
|
583
563
|
}
|
584
|
-
lob->pos =
|
564
|
+
lob->pos = NUM2ULL(position);
|
585
565
|
return self;
|
586
566
|
}
|
587
567
|
|
@@ -612,7 +592,7 @@ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
|
|
612
592
|
oci8_svcctx_t *svcctx = check_svcctx(lob);
|
613
593
|
|
614
594
|
lob_open(lob);
|
615
|
-
chker2(
|
595
|
+
chker2(OCILobTrim2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2ULL(len)),
|
616
596
|
&svcctx->base);
|
617
597
|
return self;
|
618
598
|
}
|
@@ -632,6 +612,32 @@ static VALUE oci8_lob_set_size(VALUE self, VALUE len)
|
|
632
612
|
return len;
|
633
613
|
}
|
634
614
|
|
615
|
+
static void open_bfile(oci8_svcctx_t *svcctx, oci8_lob_t *lob, OCIError *errhp)
|
616
|
+
{
|
617
|
+
while (1) {
|
618
|
+
sword rv = OCILobFileOpen_nb(svcctx, svcctx->base.hp.svc, errhp, lob->base.hp.lob, OCI_FILE_READONLY);
|
619
|
+
if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22290) {
|
620
|
+
/* ORA-22290: operation would exceed the maximum number of opened files or LOBs */
|
621
|
+
/* close all opened BFILE implicitly. */
|
622
|
+
oci8_base_t *base;
|
623
|
+
for (base = &lob->base; base != &lob->base; base = base->next) {
|
624
|
+
if (base->type == OCI_DTYPE_LOB) {
|
625
|
+
oci8_lob_t *tmp = (oci8_lob_t *)base;
|
626
|
+
if (tmp->state == S_BFILE_OPEN) {
|
627
|
+
chker2(OCILobFileClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, tmp->base.hp.lob),
|
628
|
+
&svcctx->base);
|
629
|
+
tmp->state = S_BFILE_CLOSE;
|
630
|
+
}
|
631
|
+
}
|
632
|
+
}
|
633
|
+
} else {
|
634
|
+
chker2(rv, &svcctx->base);
|
635
|
+
lob->state = S_BFILE_OPEN;
|
636
|
+
return;
|
637
|
+
}
|
638
|
+
}
|
639
|
+
}
|
640
|
+
|
635
641
|
/*
|
636
642
|
* @overload read
|
637
643
|
*
|
@@ -659,61 +665,55 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
|
|
659
665
|
{
|
660
666
|
oci8_lob_t *lob = TO_LOB(self);
|
661
667
|
oci8_svcctx_t *svcctx = check_svcctx(lob);
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
668
|
+
ub8 lob_length;
|
669
|
+
ub8 read_len;
|
670
|
+
ub8 pos = lob->pos;
|
671
|
+
long strbufsiz;
|
672
|
+
ub8 byte_amt;
|
673
|
+
ub8 char_amt;
|
666
674
|
sword rv;
|
667
|
-
size_t buf_size_in_char;
|
668
675
|
VALUE size;
|
669
676
|
VALUE v = rb_ary_new();
|
677
|
+
OCIError *errhp = oci8_errhp;
|
678
|
+
ub1 piece = OCI_FIRST_PIECE;
|
670
679
|
|
671
680
|
rb_scan_args(argc, argv, "01", &size);
|
672
|
-
|
673
|
-
if (
|
681
|
+
lob_length = oci8_lob_get_length(lob);
|
682
|
+
if (lob_length == 0 && NIL_P(size)) {
|
674
683
|
return rb_usascii_str_new("", 0);
|
675
684
|
}
|
676
|
-
if (
|
685
|
+
if (lob_length <= pos) /* EOF */
|
677
686
|
return Qnil;
|
678
|
-
length -= lob->pos;
|
679
687
|
if (NIL_P(size)) {
|
680
|
-
|
688
|
+
read_len = lob_length - pos;
|
681
689
|
} else {
|
682
|
-
|
683
|
-
|
684
|
-
|
690
|
+
ub8 sz = NUM2ULL(size);
|
691
|
+
read_len = MIN(sz, lob_length - pos);
|
692
|
+
}
|
693
|
+
if (lob->lobtype == OCI_TEMP_CLOB) {
|
694
|
+
byte_amt = 0;
|
695
|
+
char_amt = read_len;
|
696
|
+
if (oci8_nls_ratio == 1) {
|
697
|
+
strbufsiz = MIN(read_len, ULONG_MAX);
|
698
|
+
} else {
|
699
|
+
strbufsiz = MIN(read_len + read_len / 8, ULONG_MAX);
|
700
|
+
}
|
701
|
+
if (strbufsiz <= 10) {
|
702
|
+
strbufsiz = 10;
|
703
|
+
}
|
704
|
+
} else {
|
705
|
+
byte_amt = read_len;
|
706
|
+
char_amt = 0;
|
707
|
+
strbufsiz = MIN(read_len, ULONG_MAX);
|
708
|
+
}
|
709
|
+
if (lob->state == S_BFILE_CLOSE) {
|
710
|
+
open_bfile(svcctx, lob, errhp);
|
685
711
|
}
|
686
|
-
nbyte = oci8_nls_ratio * (long)nchar;
|
687
|
-
amt = nchar;
|
688
|
-
buf_size_in_char = nbyte / lob->char_width;
|
689
712
|
do {
|
690
|
-
VALUE strbuf = rb_str_buf_new(
|
713
|
+
VALUE strbuf = rb_str_buf_new(strbufsiz);
|
691
714
|
char *buf = RSTRING_PTR(strbuf);
|
692
715
|
|
693
|
-
|
694
|
-
rv = OCILobFileOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_FILE_READONLY);
|
695
|
-
if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22290) {
|
696
|
-
/* ORA-22290: operation would exceed the maximum number of opened files or LOBs */
|
697
|
-
/* close all opened BFILE implicitly. */
|
698
|
-
oci8_base_t *base;
|
699
|
-
for (base = &lob->base; base != &lob->base; base = base->next) {
|
700
|
-
if (base->type == OCI_DTYPE_LOB) {
|
701
|
-
oci8_lob_t *tmp = (oci8_lob_t *)base;
|
702
|
-
if (tmp->state == S_BFILE_OPEN) {
|
703
|
-
tmp->state = S_BFILE_CLOSE;
|
704
|
-
}
|
705
|
-
}
|
706
|
-
}
|
707
|
-
chker2(OCILobFileCloseAll_nb(svcctx, svcctx->base.hp.svc, oci8_errhp),
|
708
|
-
&svcctx->base);
|
709
|
-
continue;
|
710
|
-
}
|
711
|
-
chker2(rv, &svcctx->base);
|
712
|
-
lob->state = S_BFILE_OPEN;
|
713
|
-
}
|
714
|
-
/* initialize buf in zeros everytime to check a nul characters. */
|
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);
|
716
|
+
rv = OCILobRead2_nb(svcctx, svcctx->base.hp.svc, errhp, lob->base.hp.lob, &byte_amt, &char_amt, pos + 1, buf, strbufsiz, piece, NULL, NULL, 0, lob->csfrm);
|
717
717
|
svcctx->suppress_free_temp_lobs = 0;
|
718
718
|
switch (rv) {
|
719
719
|
case OCI_SUCCESS:
|
@@ -723,48 +723,32 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
|
|
723
723
|
* See: https://github.com/kubo/ruby-oci8/issues/20
|
724
724
|
*/
|
725
725
|
svcctx->suppress_free_temp_lobs = 1;
|
726
|
+
piece = OCI_NEXT_PIECE;
|
726
727
|
break;
|
727
|
-
case OCI_ERROR:
|
728
|
-
if (oci8_get_error_code(oci8_errhp) == 22289) {
|
729
|
-
/* ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB */
|
730
|
-
if (lob->state == S_BFILE_CLOSE)
|
731
|
-
continue;
|
732
|
-
}
|
733
|
-
/* FALLTHROUGH */
|
734
728
|
default:
|
735
729
|
chker2(rv, &svcctx->base);
|
736
730
|
}
|
737
|
-
|
738
|
-
/* Workaround when using Oracle 10.2.0.4 or 11.1.0.6 client and
|
739
|
-
* variable-length character set (e.g. AL32UTF8).
|
740
|
-
*
|
741
|
-
* When the above mentioned condition, amt may be shorter. So
|
742
|
-
* amt is increaded until a nul character to know the actually
|
743
|
-
* read size.
|
744
|
-
*/
|
745
|
-
while (amt < nbyte && buf[amt] != '\0') {
|
746
|
-
amt++;
|
747
|
-
}
|
748
|
-
|
749
|
-
if (amt == 0)
|
731
|
+
if (byte_amt == 0)
|
750
732
|
break;
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
733
|
+
if (lob->lobtype == OCI_TEMP_CLOB) {
|
734
|
+
pos += char_amt;
|
735
|
+
} else {
|
736
|
+
pos += byte_amt;
|
737
|
+
}
|
738
|
+
rb_str_set_len(strbuf, byte_amt);
|
756
739
|
rb_ary_push(v, strbuf);
|
757
740
|
} while (rv == OCI_NEED_DATA);
|
758
|
-
|
759
|
-
if (
|
741
|
+
|
742
|
+
if (pos >= lob_length) {
|
760
743
|
lob_close(lob);
|
761
744
|
bfile_close(lob);
|
762
745
|
}
|
746
|
+
lob->pos = pos;
|
763
747
|
switch (RARRAY_LEN(v)) {
|
764
748
|
case 0:
|
765
749
|
return Qnil;
|
766
750
|
case 1:
|
767
|
-
v =
|
751
|
+
v = RARRAY_AREF(v, 0);
|
768
752
|
break;
|
769
753
|
default:
|
770
754
|
v = rb_ary_join(v, Qnil);
|
@@ -793,25 +777,35 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
|
|
793
777
|
{
|
794
778
|
oci8_lob_t *lob = TO_LOB(self);
|
795
779
|
oci8_svcctx_t *svcctx = check_svcctx(lob);
|
796
|
-
|
780
|
+
volatile VALUE str;
|
781
|
+
ub8 byte_amt;
|
782
|
+
ub8 char_amt;
|
797
783
|
|
798
784
|
lob_open(lob);
|
799
785
|
if (TYPE(data) != T_STRING) {
|
800
|
-
|
786
|
+
str = rb_obj_as_string(data);
|
787
|
+
} else {
|
788
|
+
str = data;
|
801
789
|
}
|
802
790
|
if (lob->lobtype == OCI_TEMP_CLOB) {
|
803
|
-
|
791
|
+
str = rb_str_export_to_enc(str, oci8_encoding);
|
804
792
|
}
|
805
|
-
|
806
|
-
|
807
|
-
if (amt == 0) {
|
793
|
+
byte_amt = RSTRING_LEN(str);
|
794
|
+
if (byte_amt == 0) {
|
808
795
|
/* to avoid ORA-24801: illegal parameter value in OCI lob function */
|
809
796
|
return INT2FIX(0);
|
810
797
|
}
|
811
|
-
|
798
|
+
char_amt = 0;
|
799
|
+
chker2(OCILobWrite2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &byte_amt, &char_amt, lob->pos + 1, RSTRING_PTR(str), byte_amt, OCI_ONE_PIECE, NULL, NULL, 0, lob->csfrm),
|
812
800
|
&svcctx->base);
|
813
|
-
|
814
|
-
|
801
|
+
RB_GC_GUARD(str);
|
802
|
+
if (lob->lobtype == OCI_TEMP_CLOB) {
|
803
|
+
lob->pos += char_amt;
|
804
|
+
return UINT2NUM(char_amt);
|
805
|
+
} else {
|
806
|
+
lob->pos += byte_amt;
|
807
|
+
return UINT2NUM(byte_amt);
|
808
|
+
}
|
815
809
|
}
|
816
810
|
|
817
811
|
/*
|
@@ -972,7 +966,6 @@ static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
|
|
972
966
|
}
|
973
967
|
lob->base.type = OCI_DTYPE_LOB;
|
974
968
|
lob->pos = 0;
|
975
|
-
lob->char_width = 1;
|
976
969
|
lob->csfrm = SQLCS_IMPLICIT;
|
977
970
|
lob->lobtype = OCI_TEMP_BLOB;
|
978
971
|
lob->state = S_BFILE_CLOSE;
|
@@ -1294,7 +1287,6 @@ void Init_oci8_lob(VALUE cOCI8)
|
|
1294
1287
|
rb_define_method(cOCI8CLOB, "initialize", oci8_clob_initialize, -1);
|
1295
1288
|
rb_define_method(cOCI8NCLOB, "initialize", oci8_nclob_initialize, -1);
|
1296
1289
|
rb_define_method(cOCI8BLOB, "initialize", oci8_blob_initialize, -1);
|
1297
|
-
rb_define_private_method(cOCI8LOB, "__char_width=", oci8_lob_set_char_width, 1);
|
1298
1290
|
rb_define_method(cOCI8LOB, "available?", oci8_lob_available_p, 0);
|
1299
1291
|
rb_define_method(cOCI8LOB, "size", oci8_lob_get_size, 0);
|
1300
1292
|
rb_define_method(cOCI8LOB, "pos", oci8_lob_get_pos, 0);
|