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