ruby-oci8 2.0.4 → 2.0.5

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.
@@ -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