ruby-oci8 2.1.8 → 2.2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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);
|