ruby-oci8 2.0.4 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +158 -1
- data/Makefile +1 -3
- data/NEWS +70 -0
- data/VERSION +1 -1
- data/dist-files +1 -0
- data/ext/oci8/apiwrap.yml +284 -138
- data/ext/oci8/attr.c +1 -1
- data/ext/oci8/bind.c +36 -9
- data/ext/oci8/env.c +59 -33
- data/ext/oci8/error.c +4 -0
- data/ext/oci8/extconf.rb +15 -1
- data/ext/oci8/lob.c +44 -0
- data/ext/oci8/metadata.c +1 -1
- data/ext/oci8/object.c +55 -0
- data/ext/oci8/oci8.c +9 -14
- data/ext/oci8/oci8.h +39 -25
- data/ext/oci8/oci8lib.c +38 -3
- data/ext/oci8/ocidatetime.c +69 -80
- data/ext/oci8/ocihandle.c +9 -1
- data/ext/oci8/ocinumber.c +40 -18
- data/ext/oci8/oraconf.rb +126 -126
- data/ext/oci8/oradate.c +2 -2
- data/ext/oci8/oranumber_util.c +38 -1
- data/ext/oci8/stmt.c +28 -22
- data/ext/oci8/win32.c +9 -3
- data/lib/oci8.rb.in +13 -2
- data/lib/oci8/.document +1 -0
- data/lib/oci8/bindtype.rb +16 -3
- data/lib/oci8/datetime.rb +14 -6
- data/lib/oci8/encoding-init.rb +6 -1
- data/lib/oci8/encoding.yml +2 -2
- data/lib/oci8/object.rb +28 -9
- data/lib/oci8/oci8.rb +22 -6
- data/lib/oci8/properties.rb +50 -0
- data/test/test_break.rb +6 -7
- data/test/test_oranumber.rb +96 -5
- metadata +7 -4
data/lib/oci8/encoding-init.rb
CHANGED
@@ -5,7 +5,8 @@
|
|
5
5
|
# try to get NLS_LANG.
|
6
6
|
nls_lang = ENV['NLS_LANG']
|
7
7
|
|
8
|
-
if
|
8
|
+
# if NLS_LANG is not set, get it from the Windows registry.
|
9
|
+
if nls_lang.nil? and defined? OCI8::Win32Util
|
9
10
|
dll_path = OCI8::Win32Util.dll_path.upcase
|
10
11
|
if dll_path =~ %r{\\BIN\\OCI.DLL}
|
11
12
|
oracle_home = $`
|
@@ -33,6 +34,10 @@ if nls_lang
|
|
33
34
|
if enc.nil?
|
34
35
|
raise "Ruby encoding name is not found in encoding.yml for NLS_LANG #{nls_lang}."
|
35
36
|
end
|
37
|
+
if enc.is_a? Array
|
38
|
+
# Use the first available encoding in the array.
|
39
|
+
enc = enc.find do |e| Encoding.find(e) rescue false; end
|
40
|
+
end
|
36
41
|
else
|
37
42
|
warn "Warning: NLS_LANG is not set. fallback to US-ASCII."
|
38
43
|
enc = 'US-ASCII'
|
data/lib/oci8/encoding.yml
CHANGED
@@ -40,7 +40,7 @@ ZHS16GBK: GBK
|
|
40
40
|
# MS Windows Code Page 950 with Hong Kong Supplementary Character
|
41
41
|
# Set HKSCS-2001 (character set conversion to and from Unicode is
|
42
42
|
# based on Unicode 3.0)
|
43
|
-
ZHT16HKSCS: Big5
|
43
|
+
ZHT16HKSCS: [Big5-HKSCS, Big5]
|
44
44
|
|
45
45
|
# MS Windows Code Page 950 Traditional Chinese
|
46
46
|
ZHT16MSWIN950: Big5
|
@@ -166,7 +166,7 @@ ZHT16DBT: nil # FIXME
|
|
166
166
|
# MS Windows Code Page 950 with Hong Kong Supplementary Character
|
167
167
|
# Set HKSCS-2001 (character set conversion to and from Unicode is
|
168
168
|
# based on Unicode 3.1)
|
169
|
-
ZHT16HKSCS31: Big5
|
169
|
+
ZHT16HKSCS31: [Big5-HKSCS, Big5]
|
170
170
|
|
171
171
|
# SOPS 32-bit Traditional Chinese
|
172
172
|
ZHT32SOPS: nil # FIXME
|
data/lib/oci8/object.rb
CHANGED
@@ -394,7 +394,7 @@ EOS
|
|
394
394
|
@class_methods[type_method.name.downcase.intern] = result_type
|
395
395
|
end
|
396
396
|
else
|
397
|
-
warn "unsupported return type (#{schema_name}.#{name}.#{type_method.name})" if $VERBOSE
|
397
|
+
warn "unsupported return type (#{metadata.schema_name}.#{metadata.name}.#{type_method.name})" if $VERBOSE
|
398
398
|
end
|
399
399
|
end
|
400
400
|
end
|
@@ -457,6 +457,16 @@ EOS
|
|
457
457
|
#[ATTR_NAMED_COLLECTION, [datatype, typeinfo], SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
458
458
|
tdo = con.get_tdo_by_metadata(metadata.type_metadata)
|
459
459
|
[ATTR_NAMED_COLLECTION, tdo, tdo.val_size, tdo.ind_size, tdo.alignment]
|
460
|
+
when :clob
|
461
|
+
if metadata.charset_form != :nchar
|
462
|
+
[ATTR_CLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
463
|
+
else
|
464
|
+
[ATTR_NCLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
465
|
+
end
|
466
|
+
when :blob
|
467
|
+
[ATTR_BLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
468
|
+
when :bfile
|
469
|
+
[ATTR_BFILE, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
460
470
|
else
|
461
471
|
raise "unsupported typecode #{metadata.typecode}"
|
462
472
|
end
|
@@ -487,6 +497,7 @@ EOS
|
|
487
497
|
|
488
498
|
class NamedType
|
489
499
|
def to_value
|
500
|
+
return nil if self.null?
|
490
501
|
obj = tdo.ruby_class.new
|
491
502
|
obj.instance_variable_set(:@attributes, self.attributes)
|
492
503
|
obj
|
@@ -503,20 +514,28 @@ EOS
|
|
503
514
|
end
|
504
515
|
|
505
516
|
def attributes=(obj)
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
517
|
+
if obj.nil?
|
518
|
+
self.null = true
|
519
|
+
else
|
520
|
+
obj = obj.instance_variable_get(:@attributes) unless obj.is_a? Hash
|
521
|
+
tdo.attributes.each do |attr|
|
522
|
+
attr_val = obj[attr.name]
|
523
|
+
attr_val = attr.set_proc.call(attr_val) if attr.set_proc
|
524
|
+
set_attribute(attr.datatype, attr.typeinfo, attr.val_offset, attr.ind_offset, attr_val)
|
525
|
+
end
|
526
|
+
self.null = false
|
511
527
|
end
|
512
528
|
end
|
513
529
|
end
|
514
530
|
|
515
531
|
class NamedCollection
|
516
532
|
def to_value
|
517
|
-
|
518
|
-
|
519
|
-
|
533
|
+
attr = self.attributes
|
534
|
+
if attr
|
535
|
+
obj = tdo.ruby_class.new
|
536
|
+
obj.instance_variable_set(:@attributes, attr)
|
537
|
+
obj
|
538
|
+
end
|
520
539
|
end
|
521
540
|
|
522
541
|
def attributes
|
data/lib/oci8/oci8.rb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#
|
9
9
|
|
10
10
|
require 'date'
|
11
|
+
require 'yaml'
|
11
12
|
|
12
13
|
# A connection to a Oracle database server.
|
13
14
|
#
|
@@ -543,13 +544,28 @@ class OraDate
|
|
543
544
|
end
|
544
545
|
|
545
546
|
class OraNumber
|
546
|
-
def yaml_initialize(type, val) # :nodoc:
|
547
|
-
initialize(val)
|
548
|
-
end
|
549
547
|
|
550
|
-
|
551
|
-
|
552
|
-
|
548
|
+
if defined? Psych and YAML == Psych
|
549
|
+
|
550
|
+
yaml_tag '!ruby/object:OraNumber'
|
551
|
+
def encode_with coder # :nodoc:
|
552
|
+
coder.scalar = self.to_s
|
553
|
+
end
|
554
|
+
|
555
|
+
def init_with coder # :nodoc:
|
556
|
+
initialize(coder.scalar)
|
557
|
+
end
|
558
|
+
|
559
|
+
else
|
560
|
+
|
561
|
+
def yaml_initialize(type, val) # :nodoc:
|
562
|
+
initialize(val)
|
563
|
+
end
|
564
|
+
|
565
|
+
def to_yaml(opts = {}) # :nodoc:
|
566
|
+
YAML.quick_emit(object_id, opts) do |out|
|
567
|
+
out.scalar(taguri, self.to_s, :plain)
|
568
|
+
end
|
553
569
|
end
|
554
570
|
end
|
555
571
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# properties.rb -- implements OCI8.properties
|
2
|
+
#
|
3
|
+
# Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
|
4
|
+
|
5
|
+
class OCI8
|
6
|
+
|
7
|
+
@@properties = {
|
8
|
+
:bind_string_as_nchar => false,
|
9
|
+
}
|
10
|
+
|
11
|
+
def @@properties.[](name)
|
12
|
+
raise IndexError, "No such property name: #{name}" unless @@properties.has_key?(name)
|
13
|
+
super(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def @@properties.[]=(name, val)
|
17
|
+
raise IndexError, "No such property name: #{name}" unless @@properties.has_key?(name)
|
18
|
+
case name
|
19
|
+
when :bind_string_as_nchar
|
20
|
+
val = val ? true : false
|
21
|
+
end
|
22
|
+
super(name, val)
|
23
|
+
end
|
24
|
+
|
25
|
+
# call-seq:
|
26
|
+
# OCI8.properties -> a customized Hash
|
27
|
+
#
|
28
|
+
# (new in 2.0.5)
|
29
|
+
#
|
30
|
+
# Returns a Hash which ruby-oci8 global settings.
|
31
|
+
# The hash's setter and getter methods are customized to check
|
32
|
+
# property names and values.
|
33
|
+
#
|
34
|
+
# # get properties
|
35
|
+
# OCI8.properties[:bind_string_as_nchar] # => false
|
36
|
+
# OCI8.properties[:invalid_property_name] # raises an IndexError
|
37
|
+
#
|
38
|
+
# # set properties
|
39
|
+
# OCI8.properties[:bind_string_as_nchar] = true
|
40
|
+
# OCI8.properties[:invalid_property_name] = true # raises an IndexError
|
41
|
+
#
|
42
|
+
# Supported properties are listed below:
|
43
|
+
#
|
44
|
+
# [:bind_string_as_nchar]
|
45
|
+
# +true+ when string bind variables are bound as NCHAR,
|
46
|
+
# otherwise +false+. The default value is +false+.
|
47
|
+
def self.properties
|
48
|
+
@@properties
|
49
|
+
end
|
50
|
+
end
|
data/test/test_break.rb
CHANGED
@@ -23,23 +23,22 @@ class TestBreak < Test::Unit::TestCase
|
|
23
23
|
|
24
24
|
TIME_IN_PLSQL = 5
|
25
25
|
TIME_TO_BREAK = 2
|
26
|
-
MARGIN = 0.1
|
27
26
|
|
28
27
|
def do_test_ocibreak(conn, expect)
|
29
28
|
$start_time = Time.now
|
30
29
|
|
31
30
|
th = Thread.start do
|
32
31
|
begin
|
33
|
-
|
34
|
-
|
32
|
+
conn.exec("BEGIN DBMS_LOCK.SLEEP(#{TIME_IN_PLSQL}); END;")
|
33
|
+
assert_equal(expect[PLSQL_DONE], (Time.now - $start_time).round, 'PLSQL_DONE')
|
35
34
|
rescue OCIBreak
|
36
|
-
|
35
|
+
assert_equal(expect[OCIBREAK], (Time.now - $start_time).round, 'OCIBREAK')
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
40
|
-
sleep(0.
|
41
|
-
sleep(TIME_TO_BREAK)
|
42
|
-
assert_equal(expect[SEND_BREAK], (Time.now - $start_time
|
39
|
+
sleep(0.3) # Wait until DBMS_LOCK.SLEEP is running.
|
40
|
+
sleep(TIME_TO_BREAK - 0.3)
|
41
|
+
assert_equal(expect[SEND_BREAK], (Time.now - $start_time).round, 'SEND_BREAK')
|
43
42
|
conn.break()
|
44
43
|
th.join
|
45
44
|
end
|
data/test/test_oranumber.rb
CHANGED
@@ -125,6 +125,33 @@ class TestOraNumber < Test::Unit::TestCase
|
|
125
125
|
val = $1+'.'+$2 if /(-?)0\.(.*)/ =~ val
|
126
126
|
assert_equal(val, cursor[:out])
|
127
127
|
end
|
128
|
+
# Infinity and -Infinity
|
129
|
+
['~', '-~'].each do |val|
|
130
|
+
cursor[:in] = OraNumber.new(val)
|
131
|
+
cursor.exec
|
132
|
+
assert_equal(val, cursor[:out])
|
133
|
+
end
|
134
|
+
if OCI8::oracle_client_version >= OCI8::ORAVER_10_1
|
135
|
+
cursor = conn.parse(<<EOS)
|
136
|
+
BEGIN
|
137
|
+
IF (:in_oranum = CAST(:in_binary_double AS NUMBER)) THEN
|
138
|
+
:result := 'match';
|
139
|
+
ELSE
|
140
|
+
:result := 'unmatch';
|
141
|
+
END IF;
|
142
|
+
END;
|
143
|
+
EOS
|
144
|
+
cursor.bind_param(:in_oranum, nil, OraNumber)
|
145
|
+
cursor.bind_param(:in_binary_double, nil, :binary_double)
|
146
|
+
cursor.bind_param(:result, nil, String, 7)
|
147
|
+
[['~', 1.0/0.0], ['-~', -1.0/0.0]].each do |val|
|
148
|
+
cursor[:in_oranum] = OraNumber.new(val[0])
|
149
|
+
cursor[:in_binary_double] = val[1]
|
150
|
+
cursor.exec
|
151
|
+
assert_equal(cursor[:result], 'match')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
128
155
|
ensure
|
129
156
|
conn.logoff
|
130
157
|
end
|
@@ -142,13 +169,39 @@ class TestOraNumber < Test::Unit::TestCase
|
|
142
169
|
cursor.exec
|
143
170
|
assert_equal(OraNumber.new(val), cursor[:out])
|
144
171
|
end
|
172
|
+
# Infinity and -Infinity
|
173
|
+
if OCI8::oracle_client_version >= OCI8::ORAVER_10_1
|
174
|
+
cursor = conn.parse("BEGIN :out := CAST(:in AS NUMBER); END;")
|
175
|
+
cursor.bind_param(:out, OraNumber)
|
176
|
+
cursor.bind_param(:in, nil, :binary_double)
|
177
|
+
[['~', 1.0/0.0], ['-~', -1.0/0.0]].each do |val|
|
178
|
+
cursor[:in] = val[1]
|
179
|
+
cursor.exec
|
180
|
+
assert_equal(OraNumber.new(val[0]), cursor[:out])
|
181
|
+
end
|
182
|
+
end
|
183
|
+
ensure
|
184
|
+
conn.logoff
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_bind_basic_number_type
|
189
|
+
conn = get_oci8_connection
|
190
|
+
bind_type = OCI8::BindType::Mapping[:number]
|
191
|
+
begin
|
192
|
+
OCI8::BindType::Mapping[:number] = OCI8::BindType::BasicNumberType
|
193
|
+
assert_kind_of(NilClass, conn.select_one('select CAST(NULL AS NUMBER) from dual')[0])
|
194
|
+
assert_kind_of(Integer, conn.select_one('select 0.0 from dual')[0])
|
195
|
+
assert_kind_of(Integer, conn.select_one('select 10.0 from dual')[0])
|
196
|
+
assert_kind_of(Float, conn.select_one('select 10.1 from dual')[0])
|
145
197
|
ensure
|
146
198
|
conn.logoff
|
199
|
+
OCI8::BindType::Mapping[:number] = bind_type
|
147
200
|
end
|
148
201
|
end
|
149
202
|
|
150
203
|
def test_dup
|
151
|
-
LARGE_RANGE_VALUES.each do |x|
|
204
|
+
(LARGE_RANGE_VALUES + ['~', '-~']).each do |x|
|
152
205
|
n = OraNumber.new(x)
|
153
206
|
assert_equal(n, n.dup)
|
154
207
|
assert_equal(n, n.clone)
|
@@ -156,14 +209,14 @@ class TestOraNumber < Test::Unit::TestCase
|
|
156
209
|
end
|
157
210
|
|
158
211
|
def test_marshal
|
159
|
-
LARGE_RANGE_VALUES.each do |x|
|
212
|
+
(LARGE_RANGE_VALUES + ['~', '-~']).each do |x|
|
160
213
|
n = OraNumber.new(x)
|
161
214
|
assert_equal(n, Marshal.load(Marshal.dump(n)))
|
162
215
|
end
|
163
216
|
end
|
164
217
|
|
165
218
|
def test_yaml
|
166
|
-
LARGE_RANGE_VALUES.each do |x|
|
219
|
+
(LARGE_RANGE_VALUES + ['~', '-~']).each do |x|
|
167
220
|
n = OraNumber.new(x)
|
168
221
|
assert_equal(n, YAML.load(YAML.dump(n)))
|
169
222
|
end
|
@@ -200,11 +253,28 @@ class TestOraNumber < Test::Unit::TestCase
|
|
200
253
|
|
201
254
|
# OCI8::Math.atan2(y, x) -> ocinumber
|
202
255
|
def test_math_atan2
|
256
|
+
# Prior to ruby 1.9.2:
|
257
|
+
# Following method calls' return values depend on the underneath C library
|
258
|
+
# implementation.
|
259
|
+
#
|
260
|
+
# Math::atan2(+0.0, +0.0)
|
261
|
+
# Math::atan2(-0.0, +0.0)
|
262
|
+
# Math::atan2(+0.0, -0.0)
|
263
|
+
# Math::atan2(-0.0, -0.0)
|
264
|
+
#
|
265
|
+
# They are +0.0, -0.0, +PI and -PI respectively as far as I checked them on
|
266
|
+
# Windows and Linux.
|
267
|
+
#
|
268
|
+
# After ruby 1.9.2:
|
269
|
+
# They all raise a Math::DomainError exception.
|
270
|
+
#
|
271
|
+
# In contrast to Math::atan2, OCI8::Math::atan2(0, 0) allways returns 0 because
|
272
|
+
# OraNumber doesn't have the difference between +0 and -0.
|
203
273
|
compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
|
204
|
-
Proc.new {|x, y| Math::atan2(x, y.to_f)},
|
274
|
+
Proc.new {|x, y| (x.to_f == 0 && y.to_f == 0) ? 0 : Math::atan2(x, y.to_f)},
|
205
275
|
Proc.new {|x, y| OCI8::Math::atan2(x, y.to_f)})
|
206
276
|
compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
|
207
|
-
Proc.new {|x, y| Math::atan2(y.to_f, x)},
|
277
|
+
Proc.new {|x, y| (x.to_f == 0 && y.to_f == 0) ? 0 : Math::atan2(y.to_f, x)},
|
208
278
|
Proc.new {|x, y| OCI8::Math::atan2(y.to_f, x)})
|
209
279
|
end
|
210
280
|
|
@@ -652,4 +722,25 @@ class TestOraNumber < Test::Unit::TestCase
|
|
652
722
|
assert_equal(ary[1], OraNumber.new(ary[0]).to_s)
|
653
723
|
end
|
654
724
|
end
|
725
|
+
|
726
|
+
def test_dump
|
727
|
+
conn = get_oci8_connection
|
728
|
+
begin
|
729
|
+
cursor = conn.parse("select dump(to_number(:1)) from dual")
|
730
|
+
cursor.bind_param(1, nil, String, 40)
|
731
|
+
LARGE_RANGE_VALUES.each do |val|
|
732
|
+
cursor[1] = val
|
733
|
+
cursor.exec
|
734
|
+
assert_equal(cursor.fetch[0], OraNumber.new(val).dump)
|
735
|
+
end
|
736
|
+
ensure
|
737
|
+
conn.logoff
|
738
|
+
end
|
739
|
+
LARGE_RANGE_VALUES
|
740
|
+
end
|
741
|
+
|
742
|
+
def test_has_decimal_part
|
743
|
+
assert_equal(false, OraNumber(10.0).has_decimal_part?)
|
744
|
+
assert_equal(true, OraNumber(10.1).has_decimal_part?)
|
745
|
+
end
|
655
746
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 2
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 2.0.
|
8
|
+
- 5
|
9
|
+
version: 2.0.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- KUBO Takehiro
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-06-12 00:00:00 +09:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- lib/oci8/object.rb
|
87
87
|
- lib/oci8/oci8.rb
|
88
88
|
- lib/oci8/oracle_version.rb
|
89
|
+
- lib/oci8/properties.rb
|
89
90
|
- test/README
|
90
91
|
- test/config.rb
|
91
92
|
- test/test_all.rb
|
@@ -117,6 +118,7 @@ rdoc_options:
|
|
117
118
|
require_paths:
|
118
119
|
- lib
|
119
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
120
122
|
requirements:
|
121
123
|
- - ">="
|
122
124
|
- !ruby/object:Gem::Version
|
@@ -126,6 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
128
|
- 0
|
127
129
|
version: 1.8.0
|
128
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
129
132
|
requirements:
|
130
133
|
- - ">="
|
131
134
|
- !ruby/object:Gem::Version
|
@@ -135,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
138
|
requirements: []
|
136
139
|
|
137
140
|
rubyforge_project: ruby-oci8
|
138
|
-
rubygems_version: 1.3.
|
141
|
+
rubygems_version: 1.3.7
|
139
142
|
signing_key:
|
140
143
|
specification_version: 3
|
141
144
|
summary: Ruby interface for Oracle using OCI8 API
|