ruby-oci8 2.0.6 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/ChangeLog +366 -19
  2. data/Makefile +2 -8
  3. data/NEWS +111 -0
  4. data/README +4 -85
  5. data/VERSION +1 -1
  6. data/dist-files +9 -2
  7. data/ext/oci8/.document +1 -0
  8. data/ext/oci8/apiwrap.c.tmpl +12 -2
  9. data/ext/oci8/apiwrap.yml +37 -21
  10. data/ext/oci8/attr.c +23 -74
  11. data/ext/oci8/bind.c +93 -225
  12. data/ext/oci8/connection_pool.c +201 -0
  13. data/ext/oci8/encoding.c +117 -24
  14. data/ext/oci8/env.c +5 -10
  15. data/ext/oci8/error.c +171 -189
  16. data/ext/oci8/extconf.rb +6 -2
  17. data/ext/oci8/lob.c +81 -79
  18. data/ext/oci8/metadata.c +42 -177
  19. data/ext/oci8/object.c +55 -28
  20. data/ext/oci8/oci8.c +426 -294
  21. data/ext/oci8/oci8.h +84 -51
  22. data/ext/oci8/oci8lib.c +75 -53
  23. data/ext/oci8/ocidatetime.c +67 -88
  24. data/ext/oci8/ocihandle.c +78 -37
  25. data/ext/oci8/ocinumber.c +166 -109
  26. data/ext/oci8/oraconf.rb +68 -157
  27. data/ext/oci8/oradate.c +2 -7
  28. data/ext/oci8/stmt.c +40 -183
  29. data/ext/oci8/thread_util.c +85 -0
  30. data/ext/oci8/thread_util.h +30 -0
  31. data/lib/oci8.rb.in +19 -13
  32. data/lib/oci8/.document +2 -0
  33. data/lib/oci8/bindtype.rb +62 -45
  34. data/lib/oci8/connection_pool.rb +118 -0
  35. data/lib/oci8/datetime.rb +304 -320
  36. data/lib/oci8/encoding-init.rb +62 -30
  37. data/lib/oci8/encoding.yml +3 -3
  38. data/lib/oci8/metadata.rb +552 -497
  39. data/lib/oci8/object.rb +9 -9
  40. data/lib/oci8/oci8.rb +161 -2
  41. data/lib/oci8/ocihandle.rb +427 -0
  42. data/lib/oci8/properties.rb +31 -1
  43. data/ruby-oci8.gemspec +10 -3
  44. data/test/README +41 -3
  45. data/test/config.rb +16 -0
  46. data/test/test_all.rb +3 -0
  47. data/test/test_bind_string.rb +106 -0
  48. data/test/test_break.rb +33 -7
  49. data/test/test_clob.rb +13 -10
  50. data/test/test_connection_pool.rb +125 -0
  51. data/test/test_connstr.rb +2 -2
  52. data/test/test_datetime.rb +26 -66
  53. data/test/test_encoding.rb +7 -3
  54. data/test/test_error.rb +88 -0
  55. data/test/test_metadata.rb +1356 -204
  56. data/test/test_oci8.rb +27 -8
  57. data/test/test_oranumber.rb +41 -0
  58. metadata +34 -9
  59. data/ext/oci8/xmldb.c +0 -383
@@ -1,11 +1,13 @@
1
1
  # properties.rb -- implements OCI8.properties
2
2
  #
3
- # Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
3
+ # Copyright (C) 2010-2011 KUBO Takehiro <kubo@jiubao.org>
4
4
 
5
5
  class OCI8
6
6
 
7
7
  @@properties = {
8
+ :length_semantics => :byte,
8
9
  :bind_string_as_nchar => false,
10
+ :float_conversion_type => :ruby,
9
11
  }
10
12
 
11
13
  def @@properties.[](name)
@@ -16,8 +18,15 @@ class OCI8
16
18
  def @@properties.[]=(name, val)
17
19
  raise IndexError, "No such property name: #{name}" unless @@properties.has_key?(name)
18
20
  case name
21
+ when :length_semantic
22
+ if val != :byte and val != :char
23
+ raise ArgumentError, "Invalid property value #{val} for :length_semantics."
24
+ end
19
25
  when :bind_string_as_nchar
20
26
  val = val ? true : false
27
+ when :float_conversion_type
28
+ # handled by native code in oci8lib_xx.so.
29
+ OCI8.__set_property(name, val)
21
30
  end
22
31
  super(name, val)
23
32
  end
@@ -41,9 +50,30 @@ class OCI8
41
50
  #
42
51
  # Supported properties are listed below:
43
52
  #
53
+ # [:length_semantics]
54
+ # (new in 2.1.0)
55
+ #
56
+ # +:char+ when Oracle character length is counted by the number of characters.
57
+ # +:byte+ when it is counted by the number of bytes.
58
+ # The default setting is +:byte+ because +:char+ causes unexpected behaviour on
59
+ # Oracle 9i.
60
+ #
44
61
  # [:bind_string_as_nchar]
45
62
  # +true+ when string bind variables are bound as NCHAR,
46
63
  # otherwise +false+. The default value is +false+.
64
+ #
65
+ # [:float_conversion_type]
66
+ # (new in 2.1.0)
67
+ #
68
+ # +:ruby+ when Oracle decimal numbers are converted to ruby Float values
69
+ # same as Float#to_s does. (default)
70
+ # +:oracle:+ when they are done by Oracle OCI functions.
71
+ #
72
+ # From ruby 1.9.2, a float value converted from Oracle number 15.7 by
73
+ # the Oracle function OCINumberToReal() makes a string representation
74
+ # 15.700000000000001 by Float#to_s.
75
+ # See: http://rubyforge.org/forum/forum.php?thread_id=50030&forum_id=1078
76
+ #
47
77
  def self.properties
48
78
  @@properties
49
79
  end
@@ -8,10 +8,17 @@
8
8
  #
9
9
  require 'fileutils'
10
10
 
11
- if ARGV.size > 3
12
- gem_platform = ARGV[3]
11
+ build_args = if (defined? Gem::Command and Gem::Command.respond_to? :build_args)
12
+ Gem::Command.build_args
13
+ else
14
+ # for old rubygems
15
+ ARGV.include?("--") ? ARGV[(ARGV.index("--") + 1)...ARGV.size] : []
16
+ end
17
+
18
+ if build_args.size > 0
19
+ gem_platform = build_args[0]
13
20
  else
14
- gem_platform = Gem::Platform::RUBY
21
+ gem_platform = Gem::Platform::RUBY
15
22
  end
16
23
 
17
24
  spec = Gem::Specification.new do |s|
@@ -1,4 +1,42 @@
1
- This directory includes test cases using RubyUnit.
1
+ Before runing unit test:
2
2
 
3
- If RubyUnit is installed in your site, it is used to run test cases.
4
- If not installed, support files in this package are used.
3
+ 1. connect to Oracle as system:
4
+
5
+ $ sqlplus system/<password_of_system>
6
+
7
+ 2. create user ruby:
8
+
9
+ SQL> CREATE USER ruby IDENTIFIED BY oci8;
10
+
11
+ or
12
+
13
+ SQL> CREATE USER ruby IDENTIFIED BY oci8
14
+ 2 DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp;
15
+
16
+ 3. grant the privilege to connect and execute.
17
+
18
+ SQL> GRANT connect, resource, create view TO ruby;
19
+
20
+ 4. connect to Oracle as sys
21
+
22
+ $ sqlplus 'sys/<password_of_sys> as sysdba'
23
+
24
+ 5. grant privileges
25
+
26
+ SQL> GRANT EXECUTE ON dbms_lock TO ruby;
27
+ SQL> GRANT CREATE VIEW TO ruby;
28
+
29
+ 6. connect as ruby user.
30
+
31
+ $ sqlplus ruby/oci8
32
+
33
+ 7. Create object types
34
+
35
+ SQL> @test/setup_test_object.sql
36
+
37
+ 8. change $dbname if the database
38
+
39
+ Then you can run:
40
+ $ make check
41
+ or
42
+ $ nmake check (If your compiler is MS Visual C++.)
@@ -5,6 +5,9 @@ $dbuser = "ruby"
5
5
  $dbpass = "oci8"
6
6
  $dbname = nil
7
7
 
8
+ # for test_bind_string_as_nchar in test_encoding.rb
9
+ ENV['ORA_NCHAR_LITERAL_REPLACE'] = 'TRUE' if OCI8.client_charset_name.include? 'UTF8'
10
+
8
11
  # test_clob.rb
9
12
 
10
13
  nls_lang = ENV['NLS_LANG']
@@ -103,6 +106,19 @@ module Test
103
106
  end
104
107
  end
105
108
  end # drop_table
109
+
110
+ def drop_type(type_name)
111
+ begin
112
+ @conn.exec("DROP TYPE BODY #{type_name}")
113
+ rescue OCIError
114
+ raise if $!.code != 4043
115
+ end
116
+ begin
117
+ @conn.exec("DROP TYPE #{type_name}")
118
+ rescue OCIError
119
+ raise if $!.code != 4043
120
+ end
121
+ end # drop_type
106
122
  end
107
123
  end
108
124
  end
@@ -6,6 +6,7 @@ require "#{srcdir}/config"
6
6
 
7
7
  require "#{srcdir}/test_oradate"
8
8
  require "#{srcdir}/test_oranumber"
9
+ require "#{srcdir}/test_bind_string"
9
10
  require "#{srcdir}/test_bind_time"
10
11
  require "#{srcdir}/test_bind_raw"
11
12
  if $test_clob
@@ -21,6 +22,8 @@ require "#{srcdir}/test_array_dml"
21
22
  require "#{srcdir}/test_rowid"
22
23
  require "#{srcdir}/test_appinfo"
23
24
  require "#{srcdir}/test_oracle_version"
25
+ require "#{srcdir}/test_error"
26
+ require "#{srcdir}/test_connection_pool"
24
27
 
25
28
  if OCI8.respond_to? :encoding
26
29
  require "#{srcdir}/test_encoding"
@@ -0,0 +1,106 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'oci8'
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/config'
5
+
6
+ class TestBindString < Test::Unit::TestCase
7
+ def setup
8
+ @conn = get_oci8_connection
9
+ end
10
+
11
+ def teardown
12
+ @conn.logoff
13
+ end
14
+
15
+ if OCI8.client_charset_name.include? 'UTF8'
16
+
17
+ def test_bind_string_as_nchar
18
+ if ['AL32UTF8', 'UTF8', 'ZHS32GB18030'].include? @conn.database_charset_name
19
+ warn "Skip test_bind_string_as_nchar. It needs Oracle server whose database chracter set is incompatible with unicode."
20
+ else
21
+ drop_table('test_table')
22
+ @conn.exec("CREATE TABLE test_table (ID NUMBER(5), V VARCHAR2(10), NV1 NVARCHAR2(10), NV2 NVARCHAR2(10))")
23
+
24
+ orig_prop = OCI8.properties[:bind_string_as_nchar]
25
+ begin
26
+ utf8_string = "a¡あ"
27
+
28
+ OCI8.properties[:bind_string_as_nchar] = false
29
+ @conn.exec("INSERT INTO test_table VALUES (1, N'#{utf8_string}', N'#{utf8_string}', :1)", utf8_string)
30
+ v, nv1, nv2 = @conn.select_one('select V, NV1, NV2 from test_table where ID = 1')
31
+ assert_not_equal(utf8_string, v) # Some UTF-8 chracters should be garbled.
32
+ assert_equal(utf8_string, nv1) # No garbled characters
33
+ assert_equal(v, nv2) # Garbled as VARCHAR2 column.
34
+
35
+ OCI8.properties[:bind_string_as_nchar] = true
36
+ @conn.exec("INSERT INTO test_table VALUES (2, N'#{utf8_string}', N'#{utf8_string}', :1)", utf8_string)
37
+ v, nv1, nv2 = @conn.select_one('select V, NV1, NV2 from test_table where ID = 2')
38
+ assert_not_equal(utf8_string, v) # Some UTF-8 chracters should be garbled.
39
+ assert_equal(utf8_string, nv1) # No garbled characters
40
+ assert_equal(nv1, nv2) # Same as NVARCHAR2.
41
+
42
+ @conn.commit
43
+ ensure
44
+ OCI8.properties[:bind_string_as_nchar] = orig_prop
45
+ end
46
+ end
47
+ end
48
+
49
+ def test_length_semantics # This test needs to be revised.
50
+ orig_prop = OCI8.properties[:length_semantics]
51
+ begin
52
+ utf8_string = "a¡あ"
53
+
54
+ OCI8.properties[:length_semantics] = :byte
55
+ assert_equal(:byte, OCI8.properties[:length_semantics])
56
+ cursor = @conn.parse <<EOS
57
+ DECLARE
58
+ TMP VARCHAR2(6);
59
+ BEGIN
60
+ TMP := :in;
61
+ :out := TMP;
62
+ END;
63
+ EOS
64
+ cursor.bind_param(:in, utf8_string)
65
+ cursor.bind_param(:out, nil, String, 5)
66
+ begin
67
+ cursor.exec
68
+ rescue OCIError
69
+ assert_equal(6502, $!.code)
70
+ end
71
+ cursor.bind_param(:out, nil, String, 6)
72
+ cursor.exec
73
+ assert_equal(utf8_string, cursor[:out])
74
+
75
+ OCI8.properties[:length_semantics] = :char
76
+ assert_equal(:char, OCI8.properties[:length_semantics])
77
+ cursor = @conn.parse <<EOS
78
+ DECLARE
79
+ TMP VARCHAR2(6);
80
+ BEGIN
81
+ TMP := :in;
82
+ :out := TMP;
83
+ END;
84
+ EOS
85
+ cursor.bind_param(:in, utf8_string, String, 3)
86
+ cursor.bind_param(:out, nil, String, 2)
87
+ begin
88
+ cursor.exec
89
+ rescue OCIError
90
+ assert_equal(6502, $!.code)
91
+ end
92
+ cursor.bind_param(:out, nil, String, 3)
93
+ cursor.exec
94
+ assert_equal(utf8_string, cursor[:out])
95
+ ensure
96
+ OCI8.properties[:length_semantics] = orig_prop
97
+ end
98
+ end
99
+
100
+ else
101
+
102
+ def test_dummy
103
+ # to suppress "No tests were specified."
104
+ end
105
+ end
106
+ end
@@ -1,6 +1,7 @@
1
1
  # High-level API
2
2
  require 'oci8'
3
3
  require 'test/unit'
4
+ require 'timeout'
4
5
  require File.dirname(__FILE__) + '/config'
5
6
 
6
7
  class TestBreak < Test::Unit::TestCase
@@ -16,7 +17,18 @@ class TestBreak < Test::Unit::TestCase
16
17
  def report(str)
17
18
  printf "%d: %s\n", (Time.now - $start_time), str
18
19
  end
19
-
20
+
21
+ @@server_is_runing_on_windows = nil
22
+ def server_is_runing_on_windows?
23
+ if @@server_is_runing_on_windows.nil?
24
+ @@server_is_runing_on_windows = false
25
+ @conn.exec('select banner from v$version') do |row|
26
+ @@server_is_runing_on_windows = true if row[0].include? 'Windows'
27
+ end
28
+ end
29
+ @@server_is_runing_on_windows
30
+ end
31
+
20
32
  PLSQL_DONE = 1
21
33
  OCIBREAK = 2
22
34
  SEND_BREAK = 3
@@ -33,6 +45,7 @@ class TestBreak < Test::Unit::TestCase
33
45
  assert_equal(expect[PLSQL_DONE], (Time.now - $start_time).round, 'PLSQL_DONE')
34
46
  rescue OCIBreak
35
47
  assert_equal(expect[OCIBREAK], (Time.now - $start_time).round, 'OCIBREAK')
48
+ assert_equal('Canceled by user request.', $!.to_s)
36
49
  end
37
50
  end
38
51
 
@@ -54,15 +67,10 @@ class TestBreak < Test::Unit::TestCase
54
67
  end
55
68
 
56
69
  def test_non_blocking_mode
57
- is_windows_server = false
58
- @conn.exec('select banner from v$version') do |row|
59
- is_windows_server = true if row[0].include? 'Windows'
60
- end
61
-
62
70
  @conn.non_blocking = true
63
71
  assert_equal(true, @conn.non_blocking?)
64
72
  expect = []
65
- if is_windows_server
73
+ if server_is_runing_on_windows?
66
74
  if $oracle_server_version >= OCI8::ORAVER_9_0
67
75
  # raise after sleeping #{TIME_IN_PLSQL} seconds.
68
76
  expect[PLSQL_DONE] = "Invalid status"
@@ -79,4 +87,22 @@ class TestBreak < Test::Unit::TestCase
79
87
  expect[SEND_BREAK] = TIME_TO_BREAK
80
88
  do_test_ocibreak(@conn, expect)
81
89
  end
90
+
91
+ def test_timeout
92
+ @conn.non_blocking = true
93
+ start_time = Time.now
94
+ assert_raise(Timeout::Error) do
95
+ Timeout.timeout(1) do
96
+ @conn.exec("BEGIN DBMS_LOCK.SLEEP(5); END;")
97
+ end
98
+ end
99
+ if server_is_runing_on_windows?
100
+ end_time = start_time + 5
101
+ else
102
+ end_time = start_time + 1
103
+ end
104
+ assert_in_delta(Time.now, end_time, 1)
105
+ @conn.exec("BEGIN NULL; END;")
106
+ assert_in_delta(Time.now, end_time, 1)
107
+ end
82
108
  end
@@ -7,13 +7,15 @@ class TestCLob < Test::Unit::TestCase
7
7
 
8
8
  def setup
9
9
  @conn = get_oci8_connection
10
+ drop_table('test_table')
11
+ @conn.exec('CREATE TABLE test_table (filename VARCHAR2(40), content CLOB)')
10
12
  end
11
13
 
12
14
  def test_insert
13
15
  filename = File.basename($lobfile)
14
- @conn.exec("DELETE FROM test_clob WHERE filename = :1", filename)
15
- @conn.exec("INSERT INTO test_clob(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
16
- cursor = @conn.exec("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE", filename)
16
+ @conn.exec("DELETE FROM test_table WHERE filename = :1", filename)
17
+ @conn.exec("INSERT INTO test_table(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
18
+ cursor = @conn.exec("SELECT content FROM test_table WHERE filename = :1 FOR UPDATE", filename)
17
19
  lob = cursor.fetch[0]
18
20
  open($lobfile) do |f|
19
21
  while f.gets()
@@ -25,9 +27,9 @@ class TestCLob < Test::Unit::TestCase
25
27
 
26
28
  def test_insert_with_flush
27
29
  filename = File.basename($lobfile)
28
- @conn.exec("DELETE FROM test_clob WHERE filename = :1", filename)
29
- @conn.exec("INSERT INTO test_clob(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
30
- cursor = @conn.exec("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE", filename)
30
+ @conn.exec("DELETE FROM test_table WHERE filename = :1", filename)
31
+ @conn.exec("INSERT INTO test_table(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
32
+ cursor = @conn.exec("SELECT content FROM test_table WHERE filename = :1 FOR UPDATE", filename)
31
33
  lob = cursor.fetch[0]
32
34
  lob.sync = false
33
35
  open($lobfile) do |f|
@@ -42,9 +44,9 @@ class TestCLob < Test::Unit::TestCase
42
44
  def test_insert_symbol
43
45
  filename = 'test_symbol'
44
46
  value = :foo_bar
45
- @conn.exec("DELETE FROM test_clob WHERE filename = :1", filename)
46
- @conn.exec("INSERT INTO test_clob(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
47
- cursor = @conn.exec("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE", filename)
47
+ @conn.exec("DELETE FROM test_table WHERE filename = :1", filename)
48
+ @conn.exec("INSERT INTO test_table(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
49
+ cursor = @conn.exec("SELECT content FROM test_table WHERE filename = :1 FOR UPDATE", filename)
48
50
  lob = cursor.fetch[0]
49
51
  lob.write(value)
50
52
  lob.rewind
@@ -55,7 +57,7 @@ class TestCLob < Test::Unit::TestCase
55
57
  def test_read
56
58
  test_insert() # first insert data.
57
59
  filename = File.basename($lobfile)
58
- cursor = @conn.exec("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE", filename)
60
+ cursor = @conn.exec("SELECT content FROM test_table WHERE filename = :1 FOR UPDATE", filename)
59
61
  lob = cursor.fetch[0]
60
62
 
61
63
  open($lobfile) do |f|
@@ -74,6 +76,7 @@ class TestCLob < Test::Unit::TestCase
74
76
  end
75
77
 
76
78
  def teardown
79
+ drop_table('test_table')
77
80
  @conn.logoff
78
81
  end
79
82
  end
@@ -0,0 +1,125 @@
1
+ require 'oci8'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/config'
4
+
5
+ class TestConnectionPool < Test::Unit::TestCase
6
+
7
+ def create_pool(min, max, incr)
8
+ OCI8::ConnectionPool.new(min, max, incr, $dbuser, $dbpass, $dbname)
9
+ rescue OCIError
10
+ raise if $!.code != 12516 && $!.code != 12520
11
+ sleep(5)
12
+ OCI8::ConnectionPool.new(min, max, incr, $dbuser, $dbpass, $dbname)
13
+ end
14
+
15
+ def test_connect
16
+ pool = create_pool(1, 5, 3)
17
+ assert_equal(1, pool.min)
18
+ assert_equal(5, pool.max)
19
+ assert_equal(3, pool.incr)
20
+ end
21
+
22
+ def test_reinitialize
23
+ pool = create_pool(1, 5, 3)
24
+ pool.reinitialize(2, 6, 4)
25
+ assert_equal(2, pool.min)
26
+ assert_equal(6, pool.max)
27
+ assert_equal(4, pool.incr)
28
+ end
29
+
30
+ def test_busy_and_open_count
31
+ check_busy_and_open_count(1, 5, 3)
32
+ check_busy_and_open_count(2, 4, 1)
33
+ end
34
+
35
+ def check_busy_and_open_count(min_cnt, max_cnt, incr_cnt)
36
+ msg = "create_pool(#{min_cnt}, #{max_cnt}, #{incr_cnt})"
37
+ # Create a connection pool.
38
+ pool = create_pool(min_cnt, max_cnt, incr_cnt)
39
+ assert_equal(min_cnt, pool.open_count, msg)
40
+ assert_equal(0, pool.busy_count, msg)
41
+
42
+ non_blocking = true
43
+
44
+ # Create connections from the pool.
45
+ conns = []
46
+ max_cnt.times do |cnt|
47
+ conn = OCI8.new($dbuser, $dbpass, pool)
48
+ if cnt == 0
49
+ unless conn.non_blocking?
50
+ non_blocking = false
51
+ assert_raise(RuntimeError) do
52
+ # This should raise "Could not set non-blocking mode to a connection allocated from OCI8::ConnectionPool."
53
+ conn.non_blocking = true
54
+ end
55
+ end
56
+ end
57
+ conns << conn
58
+ end
59
+ assert_equal(min_cnt, pool.open_count, msg)
60
+ assert_equal(0, pool.busy_count, msg)
61
+
62
+ # Execute blocking SQL statements sequentially.
63
+ max_cnt.times do |n|
64
+ thread = Thread.start do
65
+ conns[n].exec "BEGIN DBMS_LOCK.SLEEP(1); END;"
66
+ end
67
+ sleep(0.5)
68
+ assert_equal(min_cnt, pool.open_count, msg)
69
+ assert_equal(non_blocking ? 1 : 0, pool.busy_count, msg)
70
+ thread.join
71
+ end
72
+ assert_equal(min_cnt, pool.open_count, msg)
73
+ assert_equal(0, pool.busy_count, msg)
74
+
75
+ # Execute blocking SQL statements parallel to increment open_count.
76
+ threads = []
77
+ (min_cnt + 1).times do |n|
78
+ threads << Thread.start do
79
+ conns[n].exec "BEGIN DBMS_LOCK.SLEEP(2); END;"
80
+ end
81
+ end
82
+ sleep(0.5)
83
+ assert_equal(non_blocking ? (min_cnt + incr_cnt) : min_cnt, pool.open_count, msg)
84
+ assert_equal(non_blocking ? (min_cnt + 1) : 0, pool.busy_count, msg)
85
+
86
+ # Execute blocking SQL statements parallel up to maximum.
87
+ (min_cnt + 1).upto(max_cnt - 1) do |n|
88
+ threads << Thread.start do
89
+ conns[n].exec "BEGIN DBMS_LOCK.SLEEP(1); END;"
90
+ end
91
+ end
92
+ sleep(0.5)
93
+ assert_equal(non_blocking ? max_cnt : min_cnt, pool.open_count, msg)
94
+ assert_equal(non_blocking ? max_cnt : 0, pool.busy_count, msg)
95
+
96
+ #
97
+ threads.each do |thr|
98
+ thr.join
99
+ end
100
+ assert_equal(non_blocking ? max_cnt : min_cnt, pool.open_count, msg)
101
+ assert_equal(0, pool.busy_count, msg)
102
+
103
+ # Set timeout
104
+ pool.timeout = 1
105
+ sleep(1.5)
106
+ assert_equal(non_blocking ? max_cnt : min_cnt, pool.open_count, msg) # open_count doesn't shrink.
107
+ assert_equal(0, pool.busy_count, msg)
108
+ conns[0].ping # make a network roundtrip.
109
+ sleep(0.5)
110
+ # open_count shrinks.
111
+ # The decrement count depends on Oracle version.
112
+ assert_operator(pool.open_count, :<, max_cnt, msg)
113
+ assert_equal(0, pool.busy_count, msg)
114
+
115
+ # Close all conections.
116
+ conns.each do | conn |
117
+ conn.logoff
118
+ end
119
+ assert_equal(min_cnt, pool.open_count, msg)
120
+ assert_equal(0, pool.busy_count, msg)
121
+ end
122
+
123
+ def test_nowait
124
+ end
125
+ end