ruby-oci8 2.0.6 → 2.1.0
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/ChangeLog +366 -19
- data/Makefile +2 -8
- data/NEWS +111 -0
- data/README +4 -85
- data/VERSION +1 -1
- data/dist-files +9 -2
- data/ext/oci8/.document +1 -0
- data/ext/oci8/apiwrap.c.tmpl +12 -2
- data/ext/oci8/apiwrap.yml +37 -21
- data/ext/oci8/attr.c +23 -74
- data/ext/oci8/bind.c +93 -225
- data/ext/oci8/connection_pool.c +201 -0
- data/ext/oci8/encoding.c +117 -24
- data/ext/oci8/env.c +5 -10
- data/ext/oci8/error.c +171 -189
- data/ext/oci8/extconf.rb +6 -2
- data/ext/oci8/lob.c +81 -79
- data/ext/oci8/metadata.c +42 -177
- data/ext/oci8/object.c +55 -28
- data/ext/oci8/oci8.c +426 -294
- data/ext/oci8/oci8.h +84 -51
- data/ext/oci8/oci8lib.c +75 -53
- data/ext/oci8/ocidatetime.c +67 -88
- data/ext/oci8/ocihandle.c +78 -37
- data/ext/oci8/ocinumber.c +166 -109
- data/ext/oci8/oraconf.rb +68 -157
- data/ext/oci8/oradate.c +2 -7
- data/ext/oci8/stmt.c +40 -183
- data/ext/oci8/thread_util.c +85 -0
- data/ext/oci8/thread_util.h +30 -0
- data/lib/oci8.rb.in +19 -13
- data/lib/oci8/.document +2 -0
- data/lib/oci8/bindtype.rb +62 -45
- data/lib/oci8/connection_pool.rb +118 -0
- data/lib/oci8/datetime.rb +304 -320
- data/lib/oci8/encoding-init.rb +62 -30
- data/lib/oci8/encoding.yml +3 -3
- data/lib/oci8/metadata.rb +552 -497
- data/lib/oci8/object.rb +9 -9
- data/lib/oci8/oci8.rb +161 -2
- data/lib/oci8/ocihandle.rb +427 -0
- data/lib/oci8/properties.rb +31 -1
- data/ruby-oci8.gemspec +10 -3
- data/test/README +41 -3
- data/test/config.rb +16 -0
- data/test/test_all.rb +3 -0
- data/test/test_bind_string.rb +106 -0
- data/test/test_break.rb +33 -7
- data/test/test_clob.rb +13 -10
- data/test/test_connection_pool.rb +125 -0
- data/test/test_connstr.rb +2 -2
- data/test/test_datetime.rb +26 -66
- data/test/test_encoding.rb +7 -3
- data/test/test_error.rb +88 -0
- data/test/test_metadata.rb +1356 -204
- data/test/test_oci8.rb +27 -8
- data/test/test_oranumber.rb +41 -0
- metadata +34 -9
- data/ext/oci8/xmldb.c +0 -383
@@ -0,0 +1,85 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* thread_util.c - part of ruby-oci8
|
4
|
+
*
|
5
|
+
* Copyright (C) 2011 KUBO Takehiro <kubo@jiubao.org>
|
6
|
+
*/
|
7
|
+
#include "oci8.h"
|
8
|
+
#include <errno.h>
|
9
|
+
|
10
|
+
#ifdef USE_THREAD_LOCAL_ERRHP
|
11
|
+
|
12
|
+
#ifndef WIN32
|
13
|
+
#include <pthread.h>
|
14
|
+
static pthread_attr_t detached_thread_attr;
|
15
|
+
#endif
|
16
|
+
|
17
|
+
typedef struct {
|
18
|
+
rb_blocking_function_t *func;
|
19
|
+
void *arg;
|
20
|
+
} adapter_arg_t;
|
21
|
+
|
22
|
+
void Init_oci8_thread_util(void)
|
23
|
+
{
|
24
|
+
#ifndef WIN32
|
25
|
+
pthread_attr_init(&detached_thread_attr);
|
26
|
+
pthread_attr_setdetachstate(&detached_thread_attr, PTHREAD_CREATE_DETACHED);
|
27
|
+
#endif
|
28
|
+
}
|
29
|
+
|
30
|
+
#ifdef WIN32
|
31
|
+
|
32
|
+
static void __cdecl adapter(void *arg)
|
33
|
+
{
|
34
|
+
adapter_arg_t *aa = (adapter_arg_t *)arg;
|
35
|
+
aa->func(aa->arg);
|
36
|
+
free(aa);
|
37
|
+
}
|
38
|
+
|
39
|
+
int oci8_run_native_thread(rb_blocking_function_t func, void *arg)
|
40
|
+
{
|
41
|
+
adapter_arg_t *aa = malloc(sizeof(adapter_arg_t));
|
42
|
+
if (aa == NULL) {
|
43
|
+
return ENOMEM;
|
44
|
+
}
|
45
|
+
|
46
|
+
aa->func = func;
|
47
|
+
aa->arg = arg;
|
48
|
+
if (_beginthread(adapter, 0, aa) == (uintptr_t)-1L) {
|
49
|
+
int err = errno;
|
50
|
+
free(aa);
|
51
|
+
return err;
|
52
|
+
}
|
53
|
+
return 0;
|
54
|
+
}
|
55
|
+
|
56
|
+
#else /* WIN32 */
|
57
|
+
|
58
|
+
static void *adapter(void *arg)
|
59
|
+
{
|
60
|
+
adapter_arg_t *aa = (adapter_arg_t *)arg;
|
61
|
+
aa->func(aa->arg);
|
62
|
+
free(aa);
|
63
|
+
return NULL;
|
64
|
+
}
|
65
|
+
|
66
|
+
int oci8_run_native_thread(rb_blocking_function_t func, void *arg)
|
67
|
+
{
|
68
|
+
pthread_t thread;
|
69
|
+
adapter_arg_t *aa = malloc(sizeof(adapter_arg_t));
|
70
|
+
int rv;
|
71
|
+
if (aa == NULL) {
|
72
|
+
return ENOMEM;
|
73
|
+
}
|
74
|
+
|
75
|
+
aa->func = func;
|
76
|
+
aa->arg = arg;
|
77
|
+
rv = pthread_create(&thread, &detached_thread_attr, adapter, aa);
|
78
|
+
if (rv != 0) {
|
79
|
+
free(aa);
|
80
|
+
}
|
81
|
+
return rv;
|
82
|
+
}
|
83
|
+
#endif /* WIN32 */
|
84
|
+
|
85
|
+
#endif /* USE_THREAD_LOCAL_ERRHP */
|
@@ -0,0 +1,30 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* thread_util.h - part of ruby-oci8
|
4
|
+
*
|
5
|
+
* Copyright (C) 2011 KUBO Takehiro <kubo@jiubao.org>
|
6
|
+
*/
|
7
|
+
#ifdef USE_THREAD_LOCAL_ERRHP
|
8
|
+
|
9
|
+
/*
|
10
|
+
* Prepare to execute thread-related functions.
|
11
|
+
*/
|
12
|
+
void Init_oci8_thread_util(void);
|
13
|
+
|
14
|
+
/*
|
15
|
+
* Run the func in a new native thread.
|
16
|
+
* Don't call any ruby functions in the func.
|
17
|
+
* The return value is errno.
|
18
|
+
*/
|
19
|
+
int oci8_run_native_thread(rb_blocking_function_t func, void *arg);
|
20
|
+
|
21
|
+
#else
|
22
|
+
|
23
|
+
/*
|
24
|
+
* For ruby 1.8 configured without --enable-pthread on Unix.
|
25
|
+
*/
|
26
|
+
|
27
|
+
#define Init_oci8_thread_util() do {} while (0)
|
28
|
+
#define oci8_run_native_thread(func, arg) ((func)(arg), 0)
|
29
|
+
|
30
|
+
#endif
|
data/lib/oci8.rb.in
CHANGED
@@ -6,16 +6,21 @@
|
|
6
6
|
# ruby -r oci8 -e 'OCI8.new("scott", "tiger", nil).exec("select * from emp") do |r| puts r.join(","); end'
|
7
7
|
# # select all data from emp and print them as CVS format.
|
8
8
|
|
9
|
+
ENV['ORA_SDTZ'] = ENV['TZ'] unless ENV['ORA_SDTZ']
|
10
|
+
|
9
11
|
if RUBY_PLATFORM =~ /cygwin/
|
10
12
|
# Cygwin manages environment variables by itself.
|
11
13
|
# They don't synchroize with Win32's ones.
|
12
14
|
# This set some Oracle's environment variables to win32's enviroment.
|
13
15
|
require 'Win32API'
|
14
16
|
win32setenv = Win32API.new('Kernel32.dll', 'SetEnvironmentVariableA', 'PP', 'I')
|
15
|
-
['NLS_LANG', '
|
17
|
+
['NLS_LANG', 'TNS_ADMIN', 'LOCAL'].each do |name|
|
16
18
|
val = ENV[name]
|
17
19
|
win32setenv.call(name, val && val.dup)
|
18
20
|
end
|
21
|
+
ENV.each do |name, val|
|
22
|
+
win32setenv.call(name, val && val.dup) if name =~ /^ORA/
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
so_basename = 'oci8lib_'
|
@@ -28,7 +33,7 @@ end
|
|
28
33
|
# 191 - ruby 1.9.1 and 1.9.2
|
29
34
|
# 19x - ruby 1.9.x future version which will break the API compatibility
|
30
35
|
case RUBY_VERSION
|
31
|
-
when /^1\.9/
|
36
|
+
when /^1\.9/, /^2\.0/
|
32
37
|
so_basename += '191'
|
33
38
|
when /^1\.8/
|
34
39
|
so_basename += '18'
|
@@ -37,14 +42,13 @@ else
|
|
37
42
|
end
|
38
43
|
require so_basename
|
39
44
|
|
40
|
-
if OCI8
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
load 'oci8/encoding-init.rb'
|
45
|
-
end
|
45
|
+
if OCI8::VERSION != '@@OCI8_MODULE_VERSION@@'
|
46
|
+
require 'rbconfig'
|
47
|
+
so_name = so_basename + "." + Config::CONFIG['DLEXT']
|
48
|
+
raise "VERSION MISMATCH! #{so_name} version is #{OCI8::VERSION}, but oci8.rb version is @@OCI8_MODULE_VERSION@@."
|
46
49
|
end
|
47
50
|
|
51
|
+
require 'oci8/encoding-init.rb'
|
48
52
|
require 'oci8/oracle_version.rb'
|
49
53
|
|
50
54
|
class OCI8
|
@@ -77,17 +81,19 @@ class OCI8
|
|
77
81
|
def self.oracle_client_version
|
78
82
|
@@oracle_client_version
|
79
83
|
end
|
84
|
+
|
85
|
+
# defined for backward compatibility.
|
86
|
+
CLIENT_VERSION = @@oracle_client_version.major.to_s +
|
87
|
+
@@oracle_client_version.minor.to_s +
|
88
|
+
@@oracle_client_version.update.to_s
|
80
89
|
end
|
81
90
|
|
91
|
+
require 'oci8/ocihandle.rb'
|
82
92
|
require 'oci8/datetime.rb'
|
83
93
|
require 'oci8/oci8.rb'
|
84
94
|
require 'oci8/bindtype.rb'
|
85
95
|
require 'oci8/metadata.rb'
|
86
96
|
require 'oci8/compat.rb'
|
87
97
|
require 'oci8/object.rb'
|
98
|
+
require 'oci8/connection_pool.rb'
|
88
99
|
require 'oci8/properties.rb'
|
89
|
-
|
90
|
-
class OCI8
|
91
|
-
VERSION = '@@OCI8_MODULE_VERSION@@'
|
92
|
-
CLIENT_VERSION = '@@OCI8_CLIENT_VERSION@@'
|
93
|
-
end
|
data/lib/oci8/.document
CHANGED
data/lib/oci8/bindtype.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#--
|
2
2
|
# bindtype.rb -- OCI8::BindType
|
3
3
|
#
|
4
|
-
# Copyright (C) 2009-
|
4
|
+
# Copyright (C) 2009-2011 KUBO Takehiro <kubo@jiubao.org>
|
5
5
|
#++
|
6
6
|
|
7
7
|
class OCI8
|
@@ -105,45 +105,56 @@ class OCI8
|
|
105
105
|
def self.create(con, val, param, max_array_size)
|
106
106
|
case param
|
107
107
|
when Hash
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
108
|
+
param[:length_semantics] = OCI8::properties[:length_semantics] unless param.has_key? :length_semantics
|
109
|
+
unless param[:length]
|
110
|
+
if val.respond_to? :to_str
|
111
|
+
val = val.to_str
|
112
|
+
if param[:length_semantics] == :char
|
113
|
+
# character semantics
|
114
|
+
param[:length] = val.size
|
115
|
+
else
|
116
|
+
# byte semantics
|
117
|
+
if OCI8.respond_to? :encoding and OCI8.encoding != val.encoding
|
118
|
+
# If the string encoding is different with NLS_LANG character set,
|
119
|
+
# convert it to get the length.
|
120
|
+
val = val.encode(OCI8.encoding)
|
121
|
+
end
|
122
|
+
if val.respond_to? :bytesize
|
123
|
+
# ruby 1.8.7 or upper
|
124
|
+
param[:length] = val.bytesize
|
125
|
+
else
|
126
|
+
# ruby 1.8.6 or lower
|
127
|
+
param[:length] = val.size
|
128
|
+
end
|
129
|
+
end
|
120
130
|
else
|
121
|
-
|
122
|
-
length = val.size
|
131
|
+
param[:length] = @@minimum_bind_length
|
123
132
|
end
|
124
133
|
end
|
125
134
|
# use the default value when :nchar is not set explicitly.
|
126
|
-
nchar = OCI8.properties[:bind_string_as_nchar] unless param.has_key?(:nchar)
|
135
|
+
param[:nchar] = OCI8.properties[:bind_string_as_nchar] unless param.has_key?(:nchar)
|
127
136
|
when OCI8::Metadata::Base
|
128
137
|
case param.data_type
|
129
138
|
when :char, :varchar2
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
139
|
+
length_semantics = OCI8.properties[:length_semantics]
|
140
|
+
if length_semantics == :char
|
141
|
+
length = param.char_size
|
142
|
+
else
|
143
|
+
length = param.data_size * OCI8.nls_ratio
|
144
|
+
end
|
145
|
+
param = {
|
146
|
+
:length => length,
|
147
|
+
:length_semantics => length_semantics,
|
148
|
+
:nchar => (param.charset_form == :nchar),
|
149
|
+
}
|
136
150
|
when :raw
|
137
151
|
# HEX needs twice space.
|
138
|
-
|
152
|
+
param = {:length => param.data_size * 2}
|
153
|
+
else
|
154
|
+
param = {:length => @@minimum_bind_length}
|
139
155
|
end
|
140
156
|
end
|
141
|
-
|
142
|
-
if nchar
|
143
|
-
OCI8::BindType::NCHAR.new(con, val, length, max_array_size)
|
144
|
-
else
|
145
|
-
OCI8::BindType::CHAR.new(con, val, length, max_array_size)
|
146
|
-
end
|
157
|
+
self.new(con, val, param, max_array_size)
|
147
158
|
end
|
148
159
|
end
|
149
160
|
|
@@ -151,28 +162,36 @@ class OCI8
|
|
151
162
|
def self.create(con, val, param, max_array_size)
|
152
163
|
case param
|
153
164
|
when Hash
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
165
|
+
unless param[:length]
|
166
|
+
if val.respond_to? :to_str
|
167
|
+
val = val.to_str
|
168
|
+
if val.respond_to? :bytesize
|
169
|
+
param[:length] = val.bytesize
|
170
|
+
else
|
171
|
+
param[:length] = val.size
|
172
|
+
end
|
173
|
+
else
|
174
|
+
param[:length] = 400
|
175
|
+
end
|
159
176
|
end
|
160
177
|
when OCI8::Metadata::Base
|
161
|
-
|
178
|
+
param = {:length => param.data_size}
|
162
179
|
end
|
163
|
-
self.new(con, val,
|
180
|
+
self.new(con, val, param, max_array_size)
|
164
181
|
end
|
165
182
|
end
|
166
183
|
|
167
184
|
class Long < OCI8::BindType::String
|
168
185
|
def self.create(con, val, param, max_array_size)
|
169
|
-
|
186
|
+
param = {:length => con.long_read_len, :char_semantics => true}
|
187
|
+
super(con, val, param, max_array_size)
|
170
188
|
end
|
171
189
|
end
|
172
190
|
|
173
191
|
class LongRaw < OCI8::BindType::RAW
|
174
192
|
def self.create(con, val, param, max_array_size)
|
175
|
-
|
193
|
+
param = {:length => con.long_read_len, :char_semantics => false}
|
194
|
+
self.new(con, val, param, max_array_size)
|
176
195
|
end
|
177
196
|
end
|
178
197
|
|
@@ -260,13 +279,11 @@ OCI8::BindType::Mapping[:bfile] = OCI8::BindType::BFILE
|
|
260
279
|
# DATE SQLT_DAT 7 0 0
|
261
280
|
OCI8::BindType::Mapping[:date] = OCI8::BindType::Time
|
262
281
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
OCI8::BindType::Mapping[:interval_ds] = OCI8::BindType::IntervalDS
|
269
|
-
end
|
282
|
+
OCI8::BindType::Mapping[:timestamp] = OCI8::BindType::Time
|
283
|
+
OCI8::BindType::Mapping[:timestamp_tz] = OCI8::BindType::Time
|
284
|
+
OCI8::BindType::Mapping[:timestamp_ltz] = OCI8::BindType::Time
|
285
|
+
OCI8::BindType::Mapping[:interval_ym] = OCI8::BindType::IntervalYM
|
286
|
+
OCI8::BindType::Mapping[:interval_ds] = OCI8::BindType::IntervalDS
|
270
287
|
|
271
288
|
# datatype type size prec scale
|
272
289
|
# -------------------------------------------------
|
@@ -0,0 +1,118 @@
|
|
1
|
+
#--
|
2
|
+
# connection_pool.rb -- OCI8::ConnectionPool
|
3
|
+
#
|
4
|
+
# Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
|
5
|
+
#++
|
6
|
+
|
7
|
+
class OCI8
|
8
|
+
|
9
|
+
# Connection pooling is the use of a group (the pool) of reusable
|
10
|
+
# physical connections by several sessions to balance loads.
|
11
|
+
# See: {Oracle Call Interface Manual}[http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/oci09adv.htm#sthref1479]
|
12
|
+
#
|
13
|
+
# This is equivalent to Oracle JDBC Driver {OCI Connection Pooling}[http://docs.oracle.com/cd/E11882_01/java.112/e16548/ociconpl.htm#JJDBC28789].
|
14
|
+
#
|
15
|
+
# Usage:
|
16
|
+
# # Create a connection pool.
|
17
|
+
# # username and password are required to establish an implicit primary session.
|
18
|
+
# cpool = OCI8::ConnectionPool.new(1, 5, 2, username, password, database)
|
19
|
+
#
|
20
|
+
# # Get a session from the pool.
|
21
|
+
# # Pass the connection pool to the third argument.
|
22
|
+
# conn1 = OCI8.new(username, password, cpool)
|
23
|
+
#
|
24
|
+
# # Get another session.
|
25
|
+
# conn2 = OCI8.new(username, password, cpool)
|
26
|
+
#
|
27
|
+
class ConnectionPool
|
28
|
+
|
29
|
+
# call-seq:
|
30
|
+
# timeout -> integer
|
31
|
+
#
|
32
|
+
# Connections idle for more than this time value (in seconds) are
|
33
|
+
# terminated, to maintain an optimum number of open
|
34
|
+
# connections. If it is zero, the connections are never timed out.
|
35
|
+
# The default value is zero.
|
36
|
+
#
|
37
|
+
# <b>Note:</b> Shrinkage of the pool only occurs when there is a network
|
38
|
+
# round trip. If there are no operations, then the connections
|
39
|
+
# stay alive.
|
40
|
+
def timeout
|
41
|
+
attr_get_ub4(OCI_ATTR_CONN_TIMEOUT)
|
42
|
+
end
|
43
|
+
|
44
|
+
# call-seq:
|
45
|
+
# timeout = integer
|
46
|
+
#
|
47
|
+
# Changes the timeout in seconds to terminate idle connections.
|
48
|
+
def timeout=(val)
|
49
|
+
attr_set_ub4(OCI_ATTR_CONN_TIMEOUT, val)
|
50
|
+
end
|
51
|
+
|
52
|
+
# call-seq:
|
53
|
+
# nowait? -> true or false
|
54
|
+
#
|
55
|
+
# If true, an error is thrown when all the connections in the pool
|
56
|
+
# are busy and the number of connections has already reached the
|
57
|
+
# maximum. Otherwise the call waits till it gets a connection.
|
58
|
+
# The default value is false.
|
59
|
+
def nowait?
|
60
|
+
attr_get_ub1(OCI_ATTR_CONN_NOWAIT) != 0
|
61
|
+
end
|
62
|
+
|
63
|
+
# call-seq:
|
64
|
+
# nowait = true or false
|
65
|
+
#
|
66
|
+
# Changes the behavior when all the connections in the pool
|
67
|
+
# are busy and the number of connections has already reached the
|
68
|
+
# maximum.
|
69
|
+
def nowait=(val)
|
70
|
+
attr_set_ub1(OCI_ATTR_CONN_NOWAIT, val ? 1 : 0)
|
71
|
+
end
|
72
|
+
|
73
|
+
# call-seq:
|
74
|
+
# busy_count -> integer
|
75
|
+
#
|
76
|
+
# Returns the number of busy physical connections.
|
77
|
+
def busy_count
|
78
|
+
attr_get_ub4(OCI_ATTR_CONN_BUSY_COUNT)
|
79
|
+
end
|
80
|
+
|
81
|
+
# call-seq:
|
82
|
+
# open_count -> integer
|
83
|
+
#
|
84
|
+
# Returns the number of open physical connections.
|
85
|
+
def open_count
|
86
|
+
attr_get_ub4(OCI_ATTR_CONN_OPEN_COUNT)
|
87
|
+
end
|
88
|
+
|
89
|
+
# call-seq:
|
90
|
+
# min -> integer
|
91
|
+
#
|
92
|
+
# Returns the number of minimum physical connections.
|
93
|
+
def min
|
94
|
+
attr_get_ub4(OCI_ATTR_CONN_MIN)
|
95
|
+
end
|
96
|
+
|
97
|
+
# call-seq:
|
98
|
+
# max -> integer
|
99
|
+
#
|
100
|
+
# Returns the number of maximum physical connections.
|
101
|
+
def max
|
102
|
+
attr_get_ub4(OCI_ATTR_CONN_MAX)
|
103
|
+
end
|
104
|
+
|
105
|
+
# call-seq:
|
106
|
+
# incr -> integer
|
107
|
+
#
|
108
|
+
# Returns the connection increment parameter.
|
109
|
+
def incr
|
110
|
+
attr_get_ub4(OCI_ATTR_CONN_INCR)
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
def destroy
|
115
|
+
free
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|