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.
@@ -5,7 +5,8 @@
5
5
  # try to get NLS_LANG.
6
6
  nls_lang = ENV['NLS_LANG']
7
7
 
8
- if defined? OCI8::Win32Util
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'
@@ -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 # Does the Big5 include HKSCS?
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 # Does the Big5 include HKSCS?
169
+ ZHT16HKSCS31: [Big5-HKSCS, Big5]
170
170
 
171
171
  # SOPS 32-bit Traditional Chinese
172
172
  ZHT32SOPS: nil # FIXME
@@ -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
- obj = obj.instance_variable_get(:@attributes) unless obj.is_a? Hash
507
- tdo.attributes.each do |attr|
508
- attr_val = obj[attr.name]
509
- attr_val = attr.set_proc.call(attr_val) if attr.set_proc
510
- set_attribute(attr.datatype, attr.typeinfo, attr.val_offset, attr.ind_offset, attr_val)
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
- obj = tdo.ruby_class.new
518
- obj.instance_variable_set(:@attributes, self.attributes)
519
- obj
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
@@ -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
- def to_yaml(opts = {}) # :nodoc:
551
- YAML.quick_emit(object_id, opts) do |out|
552
- out.scalar(taguri, self.to_s, :plain)
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
@@ -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
- conn.exec("BEGIN DBMS_LOCK.SLEEP(#{TIME_IN_PLSQL}); END;")
34
- assert_equal(expect[PLSQL_DONE], (Time.now - $start_time + MARGIN).to_i, 'PLSQL_DONE')
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
- assert_equal(expect[OCIBREAK], (Time.now - $start_time + MARGIN).to_i, 'OCIBREAK')
35
+ assert_equal(expect[OCIBREAK], (Time.now - $start_time).round, 'OCIBREAK')
37
36
  end
38
37
  end
39
38
 
40
- sleep(0.01) # make a time to run DBMS_LOCK.SLEEP
41
- sleep(TIME_TO_BREAK)
42
- assert_equal(expect[SEND_BREAK], (Time.now - $start_time + MARGIN).to_i, 'SEND_BREAK')
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
@@ -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
- - 4
9
- version: 2.0.4
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: 2010-02-28 00:00:00 +09:00
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.6
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