ruby-oci8 1.0.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/ChangeLog +1254 -390
  2. data/Makefile +10 -13
  3. data/README +56 -385
  4. data/VERSION +1 -1
  5. data/dist-files +26 -27
  6. data/ext/oci8/.document +1 -0
  7. data/ext/oci8/MANIFEST +0 -4
  8. data/ext/oci8/apiwrap.c.tmpl +172 -0
  9. data/ext/oci8/apiwrap.h.tmpl +61 -0
  10. data/ext/oci8/apiwrap.rb +91 -0
  11. data/ext/oci8/apiwrap.yml +1243 -0
  12. data/ext/oci8/attr.c +124 -384
  13. data/ext/oci8/bind.c +472 -164
  14. data/ext/oci8/encoding.c +196 -0
  15. data/ext/oci8/env.c +84 -253
  16. data/ext/oci8/error.c +196 -127
  17. data/ext/oci8/extconf.rb +82 -59
  18. data/ext/oci8/lob.c +710 -370
  19. data/ext/oci8/metadata.c +359 -0
  20. data/ext/oci8/object.c +622 -0
  21. data/ext/oci8/oci8.c +577 -161
  22. data/ext/oci8/oci8.h +354 -258
  23. data/ext/oci8/oci8lib.c +493 -0
  24. data/ext/oci8/ocidatetime.c +473 -0
  25. data/ext/oci8/ocinumber.c +1123 -24
  26. data/ext/oci8/oraconf.rb +72 -106
  27. data/ext/oci8/oradate.c +511 -321
  28. data/ext/oci8/stmt.c +752 -572
  29. data/ext/oci8/win32.c +131 -0
  30. data/ext/oci8/xmldb.c +383 -0
  31. data/lib/.document +2 -0
  32. data/lib/dbd/OCI8.rb +2 -17
  33. data/lib/oci8.rb.in +41 -1622
  34. data/lib/oci8/.document +5 -0
  35. data/lib/oci8/compat.rb +108 -0
  36. data/lib/oci8/datetime.rb +489 -0
  37. data/lib/oci8/encoding-init.rb +40 -0
  38. data/lib/oci8/encoding.yml +537 -0
  39. data/lib/oci8/metadata.rb +2077 -0
  40. data/lib/oci8/object.rb +548 -0
  41. data/lib/oci8/oci8.rb +773 -0
  42. data/lib/oci8/oracle_version.rb +144 -0
  43. data/metaconfig +3 -3
  44. data/ruby-oci8.gemspec +5 -5
  45. data/setup.rb +4 -4
  46. data/test/config.rb +64 -84
  47. data/test/test_all.rb +14 -21
  48. data/test/test_array_dml.rb +317 -0
  49. data/test/test_bind_raw.rb +18 -25
  50. data/test/test_bind_time.rb +78 -91
  51. data/test/test_break.rb +37 -35
  52. data/test/test_clob.rb +33 -89
  53. data/test/test_connstr.rb +5 -4
  54. data/test/test_datetime.rb +469 -0
  55. data/test/test_dbi.rb +99 -60
  56. data/test/test_dbi_clob.rb +3 -8
  57. data/test/test_metadata.rb +65 -51
  58. data/test/test_oci8.rb +151 -55
  59. data/test/test_oracle_version.rb +70 -0
  60. data/test/test_oradate.rb +76 -83
  61. data/test/test_oranumber.rb +405 -71
  62. data/test/test_rowid.rb +6 -11
  63. metadata +31 -32
  64. data/NEWS +0 -420
  65. data/ext/oci8/const.c +0 -165
  66. data/ext/oci8/define.c +0 -53
  67. data/ext/oci8/describe.c +0 -81
  68. data/ext/oci8/descriptor.c +0 -39
  69. data/ext/oci8/handle.c +0 -273
  70. data/ext/oci8/oranumber.c +0 -445
  71. data/ext/oci8/param.c +0 -37
  72. data/ext/oci8/server.c +0 -182
  73. data/ext/oci8/session.c +0 -99
  74. data/ext/oci8/svcctx.c +0 -238
  75. data/ruby-oci8.spec +0 -62
  76. data/support/README +0 -4
  77. data/support/runit/assert.rb +0 -281
  78. data/support/runit/cui/testrunner.rb +0 -101
  79. data/support/runit/error.rb +0 -4
  80. data/support/runit/method_mappable.rb +0 -20
  81. data/support/runit/robserver.rb +0 -25
  82. data/support/runit/setuppable.rb +0 -15
  83. data/support/runit/teardownable.rb +0 -16
  84. data/support/runit/testcase.rb +0 -113
  85. data/support/runit/testfailure.rb +0 -25
  86. data/support/runit/testresult.rb +0 -121
  87. data/support/runit/testsuite.rb +0 -43
  88. data/support/runit/version.rb +0 -3
  89. data/test/test_describe.rb +0 -137
@@ -1,10 +1,17 @@
1
1
  # High-level API
2
2
  require 'oci8'
3
- require 'runit/testcase'
4
- require 'runit/cui/testrunner'
3
+ require 'test/unit'
5
4
  require File.dirname(__FILE__) + '/config'
6
5
 
7
- class TestBreak < RUNIT::TestCase
6
+ class TestBreak < Test::Unit::TestCase
7
+
8
+ def setup
9
+ @conn = get_oci8_connection
10
+ end
11
+
12
+ def teardown
13
+ @conn.logoff
14
+ end
8
15
 
9
16
  def report(str)
10
17
  printf "%d: %s\n", (Time.now - $start_time), str
@@ -14,8 +21,8 @@ class TestBreak < RUNIT::TestCase
14
21
  OCIBREAK = 2
15
22
  SEND_BREAK = 3
16
23
 
17
- TIME_IN_PLSQL = 3
18
- TIME_TO_BREAK = 1
24
+ TIME_IN_PLSQL = 5
25
+ TIME_TO_BREAK = 2
19
26
  MARGIN = 0.1
20
27
 
21
28
  def do_test_ocibreak(conn, expect)
@@ -24,58 +31,53 @@ class TestBreak < RUNIT::TestCase
24
31
  th = Thread.start do
25
32
  begin
26
33
  conn.exec("BEGIN DBMS_LOCK.SLEEP(#{TIME_IN_PLSQL}); END;")
27
- assert_equal(expect[PLSQL_DONE], (Time.now - $start_time + MARGIN).to_i)
34
+ assert_equal(expect[PLSQL_DONE], (Time.now - $start_time + MARGIN).to_i, 'PLSQL_DONE')
28
35
  rescue OCIBreak
29
- assert_equal(expect[OCIBREAK], (Time.now - $start_time + MARGIN).to_i)
36
+ assert_equal(expect[OCIBREAK], (Time.now - $start_time + MARGIN).to_i, 'OCIBREAK')
30
37
  end
31
38
  end
32
39
 
40
+ sleep(0.01) # make a time to run DBMS_LOCK.SLEEP
33
41
  sleep(TIME_TO_BREAK)
34
- assert_equal(expect[SEND_BREAK], (Time.now - $start_time + MARGIN).to_i)
42
+ assert_equal(expect[SEND_BREAK], (Time.now - $start_time + MARGIN).to_i, 'SEND_BREAK')
35
43
  conn.break()
36
44
  th.join
37
45
  end
38
46
 
39
- def test_set_blocking_mode
40
- conn = get_oci_connection()
41
- conn.non_blocking = true
42
- assert_equal(true, conn.non_blocking?)
43
- conn.non_blocking = false
44
- assert_equal(false, conn.non_blocking?)
45
- conn.non_blocking = true
46
- assert_equal(true, conn.non_blocking?)
47
- conn.logoff()
48
- end
49
-
50
47
  def test_blocking_mode
51
- conn = get_oci_connection()
52
- conn.non_blocking = false
48
+ @conn.non_blocking = false
49
+ assert_equal(false, @conn.non_blocking?)
53
50
  expect = []
54
51
  expect[PLSQL_DONE] = TIME_IN_PLSQL
55
52
  expect[OCIBREAK] = "Invalid status"
56
53
  expect[SEND_BREAK] = TIME_IN_PLSQL + TIME_TO_BREAK
57
- do_test_ocibreak(conn, expect)
58
- conn.logoff()
54
+ do_test_ocibreak(@conn, expect)
59
55
  end
60
56
 
61
57
  def test_non_blocking_mode
62
- conn = get_oci_connection()
63
- conn.non_blocking = true
58
+ is_windows_server = false
59
+ @conn.exec('select banner from v$version') do |row|
60
+ is_windows_server = true if row[0].include? 'Windows'
61
+ end
62
+
63
+ @conn.non_blocking = true
64
+ assert_equal(true, @conn.non_blocking?)
64
65
  expect = []
65
- expect[PLSQL_DONE] = "Invalid status"
66
- if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/
67
- # raise after sleeping #{TIME_IN_PLSQL} seconds.
68
- expect[OCIBREAK] = TIME_IN_PLSQL
66
+ if is_windows_server
67
+ if $oracle_server_version >= OCI8::ORAVER_9_0
68
+ # raise after sleeping #{TIME_IN_PLSQL} seconds.
69
+ expect[PLSQL_DONE] = "Invalid status"
70
+ expect[OCIBREAK] = TIME_IN_PLSQL
71
+ else
72
+ expect[PLSQL_DONE] = TIME_IN_PLSQL
73
+ expect[OCIBREAK] = "Invalid status"
74
+ end
69
75
  else
70
76
  # raise immediately by OCI8#break.
77
+ expect[PLSQL_DONE] = "Invalid status"
71
78
  expect[OCIBREAK] = TIME_TO_BREAK
72
79
  end
73
80
  expect[SEND_BREAK] = TIME_TO_BREAK
74
- do_test_ocibreak(conn, expect)
75
- conn.logoff()
81
+ do_test_ocibreak(@conn, expect)
76
82
  end
77
83
  end
78
-
79
- if $0 == __FILE__
80
- RUNIT::CUI::TestRunner.run(TestBreak.suite())
81
- end
@@ -1,122 +1,66 @@
1
1
  # Low-level API
2
2
  require 'oci8'
3
- require 'runit/testcase'
4
- require 'runit/cui/testrunner'
3
+ require 'test/unit'
5
4
  require File.dirname(__FILE__) + '/config'
6
5
 
7
- class TestCLob < RUNIT::TestCase
6
+ class TestCLob < Test::Unit::TestCase
8
7
 
9
8
  def setup
10
- @env, @svc, @stmt = setup_lowapi()
9
+ @conn = get_oci8_connection
11
10
  end
12
11
 
13
12
  def test_insert
14
13
  filename = File.basename($lobfile)
15
- @stmt.prepare("DELETE FROM test_clob WHERE filename = :1")
16
- @stmt.bindByPos(1, String, filename.size).set(filename)
17
- @stmt.execute(@svc)
18
-
19
- @stmt.prepare("INSERT INTO test_clob(filename, content) VALUES (:1, EMPTY_CLOB())")
20
- @stmt.bindByPos(1, String, filename.size).set(filename)
21
- @stmt.execute(@svc)
22
-
23
- lob = @env.alloc(OCILobLocator)
24
- @stmt.prepare("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE")
25
- @stmt.bindByPos(1, String, filename.size).set(filename)
26
- @stmt.defineByPos(1, OCI_TYPECODE_CLOB, lob)
27
- @stmt.execute(@svc, 1)
28
- offset = 1 # count by charactor, not byte.
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)
17
+ lob = cursor.fetch[0]
29
18
  open($lobfile) do |f|
30
19
  while f.gets()
31
- num_of_chars = lob.write(@svc, offset, $_)
32
- offset += num_of_chars
20
+ lob.write($_)
33
21
  end
34
22
  end
35
- lob.free()
23
+ lob.close
36
24
  end
37
25
 
38
- def test_insert_with_open_close
26
+ def test_insert_with_flush
39
27
  filename = File.basename($lobfile)
40
- @stmt.prepare("DELETE FROM test_clob WHERE filename = :1")
41
- @stmt.bindByPos(1, String, filename.size).set(filename)
42
- @stmt.execute(@svc)
43
-
44
- @stmt.prepare("INSERT INTO test_clob(filename, content) VALUES (:1, EMPTY_CLOB())")
45
- @stmt.bindByPos(1, String, filename.size).set(filename)
46
- @stmt.execute(@svc)
47
-
48
- lob = @env.alloc(OCILobLocator)
49
- @stmt.prepare("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE")
50
- @stmt.bindByPos(1, String, filename.size).set(filename)
51
- @stmt.defineByPos(1, OCI_TYPECODE_CLOB, lob)
52
- @stmt.execute(@svc, 1)
53
- lob.open(@svc)
54
- begin
55
- offset = 1 # count by charactor, not byte.
56
- open($lobfile) do |f|
57
- while f.gets()
58
- offset += lob.write(@svc, offset, $_)
59
- end
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)
31
+ lob = cursor.fetch[0]
32
+ lob.sync = false
33
+ open($lobfile) do |f|
34
+ while f.gets()
35
+ lob.write($_)
60
36
  end
61
- ensure
62
- lob.close(@svc)
63
37
  end
64
- lob.free()
65
- end
66
-
67
- def test_insert_symbol
68
- filename = 'test_symbol'
69
- value = :foo_bar
70
- @stmt.prepare("DELETE FROM test_clob WHERE filename = :1")
71
- @stmt.bindByPos(1, String, filename.size).set(filename)
72
- @stmt.execute(@svc)
73
-
74
- @stmt.prepare("INSERT INTO test_clob(filename, content) VALUES (:1, EMPTY_CLOB())")
75
- @stmt.bindByPos(1, String, filename.size).set(filename)
76
- @stmt.execute(@svc)
77
-
78
- lob = @env.alloc(OCILobLocator)
79
- @stmt.prepare("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE")
80
- @stmt.bindByPos(1, String, filename.size).set(filename)
81
- @stmt.defineByPos(1, OCI_TYPECODE_CLOB, lob)
82
- @stmt.execute(@svc, 1)
83
- lob.write(@svc, 1, value)
84
- assert_equal(value.to_s, lob.read(@svc, 1, 30))
85
- lob.free()
38
+ lob.flush
39
+ lob.close
86
40
  end
87
41
 
88
42
  def test_read
89
- filename = File.basename($lobfile)
90
43
  test_insert() # first insert data.
91
- lob = @env.alloc(OCILobLocator)
92
- @stmt.prepare("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE")
93
- @stmt.bindByPos(1, String, filename.size).set(filename)
94
- @stmt.defineByPos(1, OCI_TYPECODE_CLOB, lob)
95
- @stmt.execute(@svc, 1)
44
+ filename = File.basename($lobfile)
45
+ cursor = @conn.exec("SELECT content FROM test_clob WHERE filename = :1 FOR UPDATE", filename)
46
+ lob = cursor.fetch[0]
96
47
 
97
48
  open($lobfile) do |f|
98
- offset = 1
99
- while buf = lob.read(@svc, offset, $lobreadnum)
100
- fbuf = f.read(buf.size)
101
- assert_equal(fbuf, buf)
102
- offset += $lobreadnum
103
- # offset += buf.size will not work fine,
104
- # Though buf.size counts in byte,
105
- # offset and $lobreadnum count in character.
49
+ while buf = lob.read($lobreadnum)
50
+ fbuf = f.read(buf.size)
51
+ assert_equal(fbuf, buf)
52
+ # offset += buf.size will not work fine,
53
+ # Though buf.size counts in byte,
54
+ # offset and $lobreadnum count in character.
106
55
  end
107
56
  assert_equal(nil, buf)
108
- assert_equal(true, f.eof?)
57
+ assert(f.eof?)
58
+ assert(lob.eof?)
109
59
  end
110
- lob.free()
60
+ lob.close
111
61
  end
112
62
 
113
63
  def teardown
114
- @stmt.free()
115
- @svc.logoff()
116
- @env.free()
64
+ @conn.logoff
117
65
  end
118
66
  end
119
-
120
- if $0 == __FILE__
121
- RUNIT::CUI::TestRunner.run(TestCLob.suite())
122
- end
@@ -1,9 +1,8 @@
1
1
  require 'oci8'
2
- require 'runit/testcase'
3
- require 'runit/cui/testrunner'
2
+ require 'test/unit'
4
3
  require File.dirname(__FILE__) + '/config'
5
4
 
6
- class TestConnStr < RUNIT::TestCase
5
+ class TestConnStr < Test::Unit::TestCase
7
6
  TEST_CASES =
8
7
  [
9
8
  # success cases:
@@ -69,7 +68,7 @@ class TestConnStr < RUNIT::TestCase
69
68
  result = obj.instance_eval { parse_connect_string(test_case[0]) }
70
69
  assert_equal(test_case[1], result, test_case[0])
71
70
  when Class
72
- assert_exception(test_case[1], test_case[0]) do
71
+ assert_raises(test_case[1]) do
73
72
  result = obj.instance_eval { parse_connect_string(test_case[0]) }
74
73
  end
75
74
  else
@@ -78,3 +77,5 @@ class TestConnStr < RUNIT::TestCase
78
77
  end
79
78
  end
80
79
  end
80
+
81
+ Test::Unit::AutoRunner.run() if $0 == __FILE__
@@ -0,0 +1,469 @@
1
+ require 'oci8'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/config'
4
+ require 'scanf'
5
+
6
+ class TestDateTime < Test::Unit::TestCase
7
+
8
+ def timezone_string(tzh, tzm)
9
+ if tzh >= 0
10
+ format("+%02d:%02d", tzh, tzm)
11
+ else
12
+ format("-%02d:%02d", -tzh, -tzm)
13
+ end
14
+ end
15
+
16
+ def setup
17
+ @conn = get_oci8_connection
18
+ @local_timezone = timezone_string(*((::Time.now.utc_offset / 60).divmod 60))
19
+ end
20
+
21
+ def teardown
22
+ @conn.logoff
23
+ end
24
+
25
+ def test_date_select
26
+ ['2005-12-31 23:59:59',
27
+ '2006-01-01 00:00:00'].each do |date|
28
+ @conn.exec(<<-EOS) do |row|
29
+ SELECT TO_DATE('#{date}', 'YYYY-MM-DD HH24:MI:SS') FROM dual
30
+ EOS
31
+ assert_equal(Time.local(*date.scanf("%d-%d-%d %d:%d:%d.%06d")), row[0])
32
+ end
33
+ end
34
+ end
35
+
36
+ def test_date_out_bind
37
+ cursor = @conn.parse(<<-EOS)
38
+ BEGIN
39
+ :out := TO_DATE(:in, 'YYYY-MM-DD HH24:MI:SS');
40
+ END;
41
+ EOS
42
+ cursor.bind_param(:out, nil, DateTime)
43
+ cursor.bind_param(:in, nil, String, 36)
44
+ ['2005-12-31 23:59:59',
45
+ '2006-01-01 00:00:00'].each do |date|
46
+ cursor[:in] = date
47
+ cursor.exec
48
+ assert_equal(DateTime.parse(date + @local_timezone), cursor[:out])
49
+ end
50
+ cursor.close
51
+ end
52
+
53
+ def test_date_in_bind
54
+ cursor = @conn.parse(<<-EOS)
55
+ DECLARE
56
+ dt date;
57
+ BEGIN
58
+ dt := :in;
59
+ :out := TO_CHAR(dt, 'YYYY-MM-DD HH24:MI:SS');
60
+ END;
61
+ EOS
62
+ cursor.bind_param(:out, nil, String, 33)
63
+ cursor.bind_param(:in, nil, DateTime)
64
+ ['2005-12-31 23:59:59',
65
+ '2006-01-01 00:00:00'].each do |date|
66
+ cursor[:in] = DateTime.parse(date + @local_timezone)
67
+ cursor.exec
68
+ assert_equal(date, cursor[:out])
69
+ end
70
+ cursor.close
71
+ end
72
+
73
+ def test_timestamp_select
74
+ return if $oracle_version < OCI8::ORAVER_9_0
75
+
76
+ ['2005-12-31 23:59:59.999999000',
77
+ '2006-01-01 00:00:00.000000000'].each do |date|
78
+ @conn.exec(<<-EOS) do |row|
79
+ SELECT TO_TIMESTAMP('#{date}', 'YYYY-MM-DD HH24:MI:SS.FF') FROM dual
80
+ EOS
81
+ assert_equal(Time.local(*date.scanf("%d-%d-%d %d:%d:%d.%06d")), row[0])
82
+ end
83
+ end
84
+ end
85
+
86
+ def test_timestamp_out_bind
87
+ return if $oracle_version < OCI8::ORAVER_9_0
88
+
89
+ cursor = @conn.parse(<<-EOS)
90
+ BEGIN
91
+ :out := TO_TIMESTAMP(:in, 'YYYY-MM-DD HH24:MI:SS.FF');
92
+ END;
93
+ EOS
94
+ cursor.bind_param(:out, nil, DateTime)
95
+ cursor.bind_param(:in, nil, String, 36)
96
+ ['2005-12-31 23:59:59.999999000',
97
+ '2006-01-01 00:00:00.000000000'].each do |date|
98
+ cursor[:in] = date
99
+ cursor.exec
100
+ assert_equal(DateTime.parse(date + @local_timezone), cursor[:out])
101
+ end
102
+ cursor.close
103
+ end
104
+
105
+ def test_timestamp_in_bind
106
+ return if $oracle_version < OCI8::ORAVER_9_0
107
+
108
+ cursor = @conn.parse(<<-EOS)
109
+ BEGIN
110
+ :out := TO_CHAR(:in, 'YYYY-MM-DD HH24:MI:SS.FF');
111
+ END;
112
+ EOS
113
+ cursor.bind_param(:out, nil, String, 33)
114
+ cursor.bind_param(:in, nil, DateTime)
115
+ ['2005-12-31 23:59:59.999999000',
116
+ '2006-01-01 00:00:00.000000000'].each do |date|
117
+ cursor[:in] = DateTime.parse(date + @local_timezone)
118
+ cursor.exec
119
+ assert_equal(date, cursor[:out])
120
+ end
121
+ cursor.close
122
+ end
123
+
124
+ def test_timestamp_tz_select
125
+ return if $oracle_version < OCI8::ORAVER_9_0
126
+
127
+ ['2005-12-31 23:59:59.999999000 +08:30',
128
+ '2006-01-01 00:00:00.000000000 -08:30'].each do |date|
129
+ @conn.exec(<<-EOS) do |row|
130
+ SELECT TO_TIMESTAMP_TZ('#{date}', 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM') FROM dual
131
+ EOS
132
+ assert_equal(DateTime.parse(date), row[0])
133
+ end
134
+ end
135
+ end
136
+
137
+ def test_timestamp_tz_out_bind
138
+ return if $oracle_version < OCI8::ORAVER_9_0
139
+
140
+ cursor = @conn.parse(<<-EOS)
141
+ BEGIN
142
+ :out := TO_TIMESTAMP_TZ(:in, 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM');
143
+ END;
144
+ EOS
145
+ cursor.bind_param(:out, nil, DateTime)
146
+ cursor.bind_param(:in, nil, String, 36)
147
+ ['2005-12-31 23:59:59.999999000 +08:30',
148
+ '2006-01-01 00:00:00.000000000 -08:30'].each do |date|
149
+ cursor[:in] = date
150
+ cursor.exec
151
+ assert_equal(DateTime.parse(date), cursor[:out])
152
+ end
153
+ cursor.close
154
+ end
155
+
156
+ def test_timestamp_tz_in_bind
157
+ return if $oracle_version < OCI8::ORAVER_9_0
158
+
159
+ cursor = @conn.parse(<<-EOS)
160
+ BEGIN
161
+ :out := TO_CHAR(:in, 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM');
162
+ END;
163
+ EOS
164
+ cursor.bind_param(:out, nil, String, 36)
165
+ cursor.bind_param(:in, nil, DateTime)
166
+ ['2005-12-31 23:59:59.999999000 +08:30',
167
+ '2006-01-01 00:00:00.000000000 -08:30'].each do |date|
168
+ cursor[:in] = DateTime.parse(date)
169
+ cursor.exec
170
+ assert_equal(date, cursor[:out])
171
+ end
172
+ cursor.close
173
+ end
174
+
175
+ def test_datetype_duck_typing
176
+ cursor = @conn.parse("BEGIN :out := :in; END;")
177
+ cursor.bind_param(:in, nil, DateTime)
178
+ cursor.bind_param(:out, nil, DateTime)
179
+ obj = Object.new
180
+ # test year, month, day
181
+ def obj.year; 2006; end
182
+ def obj.month; 12; end
183
+ def obj.day; 31; end
184
+ cursor[:in] = obj
185
+ cursor.exec
186
+ assert_equal(DateTime.parse('2006-12-31 00:00:00' + @local_timezone), cursor[:out])
187
+ # test hour
188
+ def obj.hour; 23; end
189
+ cursor[:in] = obj
190
+ cursor.exec
191
+ assert_equal(DateTime.parse('2006-12-31 23:00:00' + @local_timezone), cursor[:out])
192
+ # test min
193
+ def obj.min; 59; end
194
+ cursor[:in] = obj
195
+ cursor.exec
196
+ assert_equal(DateTime.parse('2006-12-31 23:59:00' + @local_timezone), cursor[:out])
197
+ # test sec
198
+ def obj.sec; 59; end
199
+ cursor[:in] = obj
200
+ cursor.exec
201
+ assert_equal(DateTime.parse('2006-12-31 23:59:59' + @local_timezone), cursor[:out])
202
+
203
+ # sec_fraction and timezone are available on Oracle 9i or later
204
+ return if $oracle_version < OCI8::ORAVER_9_0
205
+
206
+ # test sec_fraction
207
+ def obj.sec_fraction; DateTime.parse('0001-01-01 00:00:00.000001').sec_fraction * 999999 ; end
208
+ cursor[:in] = obj
209
+ cursor.exec
210
+ assert_equal(DateTime.parse('2006-12-31 23:59:59.999999' + @local_timezone), cursor[:out])
211
+ # test utc_offset (Time)
212
+ def obj.utc_offset; @utc_offset; end
213
+ obj.instance_variable_set(:@utc_offset, 9 * 60 * 60)
214
+ cursor[:in] = obj
215
+ cursor.exec
216
+ assert_equal(DateTime.parse('2006-12-31 23:59:59.999999 +09:00'), cursor[:out])
217
+ obj.instance_variable_set(:@utc_offset, -5 * 60 * 60)
218
+ cursor[:in] = obj
219
+ cursor.exec
220
+ assert_equal(DateTime.parse('2006-12-31 23:59:59.999999 -05:00'), cursor[:out])
221
+ # test offset (DateTime)
222
+ def obj.offset; @offset; end
223
+ obj.instance_variable_set(:@offset, 9.to_r / 24)
224
+ cursor[:in] = obj
225
+ cursor.exec
226
+ assert_equal(DateTime.parse('2006-12-31 23:59:59.999999 +09:00'), cursor[:out])
227
+ obj.instance_variable_set(:@offset, -5.to_r / 24)
228
+ cursor[:in] = obj
229
+ cursor.exec
230
+ assert_equal(DateTime.parse('2006-12-31 23:59:59.999999 -05:00'), cursor[:out])
231
+ end
232
+
233
+ def test_timezone
234
+ if $oracle_version >= OCI8::ORAVER_9_0
235
+ # temporarily change the mapping to test OCI8::BindType::Util.default_timezone.
236
+ OCI8::BindType::Mapping[:date] = OCI8::BindType::TimeViaOCIDate
237
+ end
238
+ begin
239
+ assert_raise(ArgumentError) do
240
+ OCI8::BindType::Util.default_timezone = :invalid_value
241
+ end
242
+
243
+ [:local, :utc].each do |tz|
244
+ OCI8::BindType::Util.default_timezone = tz
245
+ @conn.exec("select sysdate, to_date('2008-01-02', 'yyyy-mm-dd') from dual") do |row|
246
+ row.each do |dt|
247
+ assert_kind_of(Time, dt)
248
+ assert_equal(tz, dt.utc? ? :utc : :local)
249
+ end
250
+ assert_equal(2008, row[1].year)
251
+ assert_equal(1, row[1].month)
252
+ assert_equal(2, row[1].day)
253
+ end
254
+ end
255
+ ensure
256
+ OCI8::BindType::Util.default_timezone = :local
257
+ if $oracle_version >= OCI8::ORAVER_9_0
258
+ OCI8::BindType::Mapping[:date] = OCI8::BindType::Time
259
+ end
260
+ end
261
+
262
+ if $oracle_version >= OCI8::ORAVER_9_0
263
+ ses_tz = nil
264
+ @conn.exec('select sessiontimezone from dual') do |row|
265
+ ses_tz = row[0]
266
+ end
267
+
268
+ begin
269
+ ['+09:00', '+00:00', '-05:00'].each do |tz|
270
+ @conn.exec("alter session set time_zone = '#{tz}'")
271
+ @conn.exec("select current_timestamp, sysdate, to_timestamp('2008-01-02', 'yyyy-mm-dd') from dual") do |row|
272
+ row.each do |dt|
273
+ case dt
274
+ when Time
275
+ assert_equal(tz, timezone_string(*((dt.utc_offset / 60).divmod 60)))
276
+ when DateTime
277
+ assert_equal(tz, dt.zone)
278
+ else
279
+ flunk "unexpedted type #{dt.class}"
280
+ end
281
+ end
282
+ assert_equal(2008, row[2].year)
283
+ assert_equal(1, row[2].month)
284
+ assert_equal(2, row[2].day)
285
+ end
286
+ end
287
+ ensure
288
+ @conn.exec("alter session set time_zone = '#{ses_tz}'")
289
+ end
290
+ else
291
+ end
292
+ end
293
+
294
+ def test_interval_ym_select
295
+ return if $oracle_version < OCI8::ORAVER_9_0
296
+
297
+ [['2006-01-01', '2004-03-01'],
298
+ ['2006-01-01', '2005-03-01'],
299
+ ['2006-01-01', '2006-03-01'],
300
+ ['2006-01-01', '2007-03-01']
301
+ ].each do |date1, date2|
302
+ @conn.exec(<<-EOS) do |row|
303
+ SELECT (TO_TIMESTAMP('#{date1}', 'YYYY-MM-DD')
304
+ - TO_TIMESTAMP('#{date2}', 'YYYY-MM-DD')) YEAR TO MONTH
305
+ FROM dual
306
+ EOS
307
+ assert_equal(DateTime.parse(date1), DateTime.parse(date2) >> row[0])
308
+ end
309
+ end
310
+ end
311
+
312
+ def test_interval_ym_out_bind
313
+ return if $oracle_version < OCI8::ORAVER_9_0
314
+
315
+ cursor = @conn.parse(<<-EOS)
316
+ DECLARE
317
+ ts1 TIMESTAMP;
318
+ ts2 TIMESTAMP;
319
+ BEGIN
320
+ ts1 := TO_TIMESTAMP(:in1, 'YYYY-MM-DD');
321
+ ts2 := TO_TIMESTAMP(:in2, 'YYYY-MM-DD');
322
+ :out := (ts1 - ts2) YEAR TO MONTH;
323
+ END;
324
+ EOS
325
+ cursor.bind_param(:out, nil, :interval_ym)
326
+ cursor.bind_param(:in1, nil, String, 36)
327
+ cursor.bind_param(:in2, nil, String, 36)
328
+ [['2006-01-01', '2004-03-01'],
329
+ ['2006-01-01', '2005-03-01'],
330
+ ['2006-01-01', '2006-03-01'],
331
+ ['2006-01-01', '2007-03-01']
332
+ ].each do |date1, date2|
333
+ cursor[:in1] = date1
334
+ cursor[:in2] = date2
335
+ cursor.exec
336
+ assert_equal(DateTime.parse(date1), DateTime.parse(date2) >> cursor[:out])
337
+ end
338
+ cursor.close
339
+ end
340
+
341
+ def test_interval_ym_in_bind
342
+ return if $oracle_version < OCI8::ORAVER_9_0
343
+
344
+ cursor = @conn.parse(<<-EOS)
345
+ DECLARE
346
+ ts1 TIMESTAMP;
347
+ BEGIN
348
+ ts1 := TO_TIMESTAMP(:in1, 'YYYY-MM-DD');
349
+ :out := TO_CHAR(ts1 + :in2, 'YYYY-MM-DD');
350
+ END;
351
+ EOS
352
+ cursor.bind_param(:out, nil, String, 36)
353
+ cursor.bind_param(:in1, nil, String, 36)
354
+ cursor.bind_param(:in2, nil, :interval_ym)
355
+ [['2006-01-01', -22],
356
+ ['2006-01-01', -10],
357
+ ['2006-01-01', +2],
358
+ ['2006-01-01', +12]
359
+ ].each do |date, interval|
360
+ cursor[:in1] = date
361
+ cursor[:in2] = interval
362
+ cursor.exec
363
+ assert_equal(DateTime.parse(date) >> interval, DateTime.parse(cursor[:out]))
364
+ end
365
+ cursor.close
366
+ end
367
+
368
+ def test_interval_ds_select
369
+ return if $oracle_version < OCI8::ORAVER_9_0
370
+
371
+ [['2006-01-01', '2004-03-01'],
372
+ ['2006-01-01', '2005-03-01'],
373
+ ['2006-01-01', '2006-03-01'],
374
+ ['2006-01-01', '2007-03-01'],
375
+ ['2006-01-01', '2006-01-01 23:00:00'],
376
+ ['2006-01-01', '2006-01-01 00:59:00'],
377
+ ['2006-01-01', '2006-01-01 00:00:59'],
378
+ ['2006-01-01', '2006-01-01 00:00:00.999999'],
379
+ ['2006-01-01', '2006-01-01 23:59:59.999999'],
380
+ ['2006-01-01', '2005-12-31 23:00:00'],
381
+ ['2006-01-01', '2005-12-31 00:59:00'],
382
+ ['2006-01-01', '2005-12-31 00:00:59'],
383
+ ['2006-01-01', '2005-12-31 00:00:00.999999'],
384
+ ['2006-01-01', '2005-12-31 23:59:59.999999']
385
+ ].each do |date1, date2|
386
+ @conn.exec(<<-EOS) do |row|
387
+ SELECT (TO_TIMESTAMP('#{date1}', 'YYYY-MM-DD HH24:MI:SS.FF')
388
+ - TO_TIMESTAMP('#{date2}', 'YYYY-MM-DD HH24:MI:SS.FF')) DAY(3) TO SECOND
389
+ FROM dual
390
+ EOS
391
+ assert_equal(DateTime.parse(date1) - DateTime.parse(date2), row[0])
392
+ end
393
+ end
394
+ end
395
+
396
+ def test_interval_ds_out_bind
397
+ return if $oracle_version < OCI8::ORAVER_9_0
398
+
399
+ cursor = @conn.parse(<<-EOS)
400
+ DECLARE
401
+ ts1 TIMESTAMP;
402
+ ts2 TIMESTAMP;
403
+ BEGIN
404
+ ts1 := TO_TIMESTAMP(:in1, 'YYYY-MM-DD HH24:MI:SS.FF');
405
+ ts2 := TO_TIMESTAMP(:in2, 'YYYY-MM-DD HH24:MI:SS.FF');
406
+ :out := (ts1 - ts2) DAY TO SECOND(9);
407
+ END;
408
+ EOS
409
+ cursor.bind_param(:out, nil, :interval_ds)
410
+ cursor.bind_param(:in1, nil, String, 36)
411
+ cursor.bind_param(:in2, nil, String, 36)
412
+ [['2006-01-01', '2004-03-01'],
413
+ ['2006-01-01', '2005-03-01'],
414
+ ['2006-01-01', '2006-03-01'],
415
+ ['2006-01-01', '2007-03-01'],
416
+ ['2006-01-01', '2006-01-01 23:00:00'],
417
+ ['2006-01-01', '2006-01-01 00:59:00'],
418
+ ['2006-01-01', '2006-01-01 00:00:59'],
419
+ ['2006-01-01', '2006-01-01 00:00:00.999999'],
420
+ ['2006-01-01', '2006-01-01 23:59:59.999999'],
421
+ ['2006-01-01', '2005-12-31 23:00:00'],
422
+ ['2006-01-01', '2005-12-31 00:59:00'],
423
+ ['2006-01-01', '2005-12-31 00:00:59'],
424
+ ['2006-01-01', '2005-12-31 00:00:00.999999'],
425
+ ['2006-01-01', '2005-12-31 23:59:59.999999']
426
+ ].each do |date1, date2|
427
+ cursor[:in1] = date1
428
+ cursor[:in2] = date2
429
+ cursor.exec
430
+ assert_equal(DateTime.parse(date1) - DateTime.parse(date2), cursor[:out])
431
+ end
432
+ cursor.close
433
+ end
434
+
435
+ def test_interval_ds_in_bind
436
+ return if $oracle_version < OCI8::ORAVER_9_0
437
+
438
+ cursor = @conn.parse(<<-EOS)
439
+ DECLARE
440
+ ts1 TIMESTAMP;
441
+ BEGIN
442
+ ts1 := TO_TIMESTAMP(:in1, 'YYYY-MM-DD HH24:MI:SS.FF');
443
+ :out := TO_CHAR(ts1 + :in2, 'YYYY-MM-DD HH24:MI:SS.FF');
444
+ END;
445
+ EOS
446
+ cursor.bind_param(:out, nil, String, 36)
447
+ cursor.bind_param(:in1, nil, String, 36)
448
+ cursor.bind_param(:in2, nil, :interval_ds)
449
+ [['2006-01-01', -22],
450
+ ['2006-01-01', -10],
451
+ ['2006-01-01', +2],
452
+ ['2006-01-01', +12],
453
+ ['2006-01-01', -1.to_r / 24], # one hour
454
+ ['2006-01-01', -1.to_r / (24*60)], # one minute
455
+ ['2006-01-01', -1.to_r / (24*60*60)], # one second
456
+ ['2006-01-01', -999999.to_r / (24*60*60*1000000)], # 0.999999 seconds
457
+ ['2006-01-01', +1.to_r / 24], # one hour
458
+ ['2006-01-01', +1.to_r / (24*60)], # one minute
459
+ ['2006-01-01', +1.to_r / (24*60*60)], # one second
460
+ ['2006-01-01', +999999.to_r / (24*60*60*1000000)] # 0.999999 seconds
461
+ ].each do |date, interval|
462
+ cursor[:in1] = date
463
+ cursor[:in2] = interval
464
+ cursor.exec
465
+ assert_equal(DateTime.parse(date) + interval, DateTime.parse(cursor[:out]))
466
+ end
467
+ cursor.close
468
+ end
469
+ end # TestOCI8