ruby-oci8 2.0.6-x86-mingw32 → 2.1.0-x86-mingw32
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/lib/oci8.rb +19 -13
- 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/lib/oci8lib_18.so +0 -0
- data/lib/oci8lib_191.so +0 -0
- 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 +10 -5
data/lib/oci8/properties.rb
CHANGED
@@ -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
|
data/lib/oci8lib_18.so
CHANGED
Binary file
|
data/lib/oci8lib_191.so
CHANGED
Binary file
|
data/ruby-oci8.gemspec
CHANGED
@@ -8,10 +8,17 @@
|
|
8
8
|
#
|
9
9
|
require 'fileutils'
|
10
10
|
|
11
|
-
if
|
12
|
-
|
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
|
-
|
21
|
+
gem_platform = Gem::Platform::RUBY
|
15
22
|
end
|
16
23
|
|
17
24
|
spec = Gem::Specification.new do |s|
|
data/test/README
CHANGED
@@ -1,4 +1,42 @@
|
|
1
|
-
|
1
|
+
Before runing unit test:
|
2
2
|
|
3
|
-
|
4
|
-
|
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++.)
|
data/test/config.rb
CHANGED
@@ -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
|
data/test/test_all.rb
CHANGED
@@ -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
|
data/test/test_break.rb
CHANGED
@@ -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
|
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
|
data/test/test_clob.rb
CHANGED
@@ -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
|
15
|
-
@conn.exec("INSERT INTO
|
16
|
-
cursor = @conn.exec("SELECT content FROM
|
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
|
29
|
-
@conn.exec("INSERT INTO
|
30
|
-
cursor = @conn.exec("SELECT content FROM
|
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
|
46
|
-
@conn.exec("INSERT INTO
|
47
|
-
cursor = @conn.exec("SELECT content FROM
|
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
|
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
|