ruby-oci8-master 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/ChangeLog +2321 -0
  2. data/Makefile +88 -0
  3. data/NEWS +303 -0
  4. data/README +76 -0
  5. data/VERSION +1 -0
  6. data/dist-files +83 -0
  7. data/doc/api.en.html +527 -0
  8. data/doc/api.en.rd +554 -0
  9. data/doc/api.ja.html +525 -0
  10. data/doc/api.ja.rd +557 -0
  11. data/doc/manual.css +35 -0
  12. data/ext/oci8/.document +18 -0
  13. data/ext/oci8/MANIFEST +18 -0
  14. data/ext/oci8/apiwrap.c.tmpl +182 -0
  15. data/ext/oci8/apiwrap.h.tmpl +61 -0
  16. data/ext/oci8/apiwrap.rb +91 -0
  17. data/ext/oci8/apiwrap.yml +1455 -0
  18. data/ext/oci8/attr.c +105 -0
  19. data/ext/oci8/bind.c +366 -0
  20. data/ext/oci8/connection_pool.c +199 -0
  21. data/ext/oci8/encoding.c +289 -0
  22. data/ext/oci8/env.c +178 -0
  23. data/ext/oci8/error.c +378 -0
  24. data/ext/oci8/extconf.rb +179 -0
  25. data/ext/oci8/lob.c +805 -0
  26. data/ext/oci8/metadata.c +232 -0
  27. data/ext/oci8/object.c +727 -0
  28. data/ext/oci8/oci8.c +1156 -0
  29. data/ext/oci8/oci8.h +574 -0
  30. data/ext/oci8/oci8lib.c +527 -0
  31. data/ext/oci8/ocidatetime.c +484 -0
  32. data/ext/oci8/ocihandle.c +751 -0
  33. data/ext/oci8/ocinumber.c +1612 -0
  34. data/ext/oci8/oraconf.rb +1119 -0
  35. data/ext/oci8/oradate.c +611 -0
  36. data/ext/oci8/oranumber_util.c +352 -0
  37. data/ext/oci8/oranumber_util.h +24 -0
  38. data/ext/oci8/post-config.rb +5 -0
  39. data/ext/oci8/stmt.c +673 -0
  40. data/ext/oci8/thread_util.c +85 -0
  41. data/ext/oci8/thread_util.h +30 -0
  42. data/ext/oci8/win32.c +137 -0
  43. data/lib/.document +1 -0
  44. data/lib/dbd/OCI8.rb +591 -0
  45. data/lib/oci8.rb.in +94 -0
  46. data/lib/oci8/.document +8 -0
  47. data/lib/oci8/bindtype.rb +349 -0
  48. data/lib/oci8/compat.rb +113 -0
  49. data/lib/oci8/connection_pool.rb +99 -0
  50. data/lib/oci8/datetime.rb +611 -0
  51. data/lib/oci8/encoding-init.rb +74 -0
  52. data/lib/oci8/encoding.yml +537 -0
  53. data/lib/oci8/metadata.rb +2132 -0
  54. data/lib/oci8/object.rb +581 -0
  55. data/lib/oci8/oci8.rb +721 -0
  56. data/lib/oci8/ocihandle.rb +425 -0
  57. data/lib/oci8/oracle_version.rb +144 -0
  58. data/lib/oci8/properties.rb +73 -0
  59. data/metaconfig +142 -0
  60. data/pre-distclean.rb +7 -0
  61. data/ruby-oci8.gemspec +63 -0
  62. data/setup.rb +1331 -0
  63. data/test/README +4 -0
  64. data/test/config.rb +122 -0
  65. data/test/test_all.rb +51 -0
  66. data/test/test_appinfo.rb +63 -0
  67. data/test/test_array_dml.rb +333 -0
  68. data/test/test_bind_raw.rb +46 -0
  69. data/test/test_bind_time.rb +178 -0
  70. data/test/test_break.rb +96 -0
  71. data/test/test_clob.rb +82 -0
  72. data/test/test_connstr.rb +81 -0
  73. data/test/test_datetime.rb +582 -0
  74. data/test/test_dbi.rb +366 -0
  75. data/test/test_dbi_clob.rb +53 -0
  76. data/test/test_encoding.rb +100 -0
  77. data/test/test_error.rb +88 -0
  78. data/test/test_metadata.rb +1399 -0
  79. data/test/test_oci8.rb +434 -0
  80. data/test/test_oracle_version.rb +70 -0
  81. data/test/test_oradate.rb +256 -0
  82. data/test/test_oranumber.rb +746 -0
  83. data/test/test_rowid.rb +33 -0
  84. metadata +137 -0
@@ -0,0 +1,113 @@
1
+ #
2
+ # add compatible code with old versions.
3
+ #
4
+
5
+ OCI_STMT_SELECT = :select_stmt
6
+ OCI_STMT_UPDATE = :update_stmt
7
+ OCI_STMT_DELETE = :delete_stmt
8
+ OCI_STMT_INSERT = :insert_stmt
9
+ OCI_STMT_CREATE = :create_stmt
10
+ OCI_STMT_DROP = :drop_stmt
11
+ OCI_STMT_ALTER = :alter_stmt
12
+ OCI_STMT_BEGIN = :begin_stmt
13
+ OCI_STMT_DECLARE = :declare_stmt
14
+
15
+ class OCI8
16
+
17
+ STMT_SELECT = :select_stmt
18
+ STMT_UPDATE = :update_stmt
19
+ STMT_DELETE = :delete_stmt
20
+ STMT_INSERT = :insert_stmt
21
+ STMT_CREATE = :create_stmt
22
+ STMT_DROP = :drop_stmt
23
+ STMT_ALTER = :alter_stmt
24
+ STMT_BEGIN = :begin_stmt
25
+ STMT_DECLARE = :declare_stmt
26
+
27
+ RAW = :raw
28
+
29
+ # varchar, varchar2
30
+ SQLT_CHR = :varchar2
31
+ # number, double precision, float, real, numeric, int, integer, smallint
32
+ SQLT_NUM = :number
33
+ # long
34
+ SQLT_LNG = :long
35
+ # date
36
+ SQLT_DAT = :date
37
+ # raw
38
+ SQLT_BIN = :raw
39
+ # long raw
40
+ SQLT_LBI = :long_raw
41
+ # char
42
+ SQLT_AFC = :char
43
+ # binary_float
44
+ SQLT_IBFLOAT = :binary_float
45
+ # binary_double
46
+ SQLT_IBDOUBLE = :binary_double
47
+ # rowid
48
+ SQLT_RDD = :rowid
49
+ # clob
50
+ SQLT_CLOB = :clob
51
+ # blob
52
+ SQLT_BLOB = :blob
53
+ # bfile
54
+ SQLT_BFILE = :bfile
55
+ # ref cursor
56
+ SQLT_RSET = 116
57
+ # timestamp
58
+ SQLT_TIMESTAMP = :timestamp
59
+ # timestamp with time zone
60
+ SQLT_TIMESTAMP_TZ = :timestamp_tz
61
+ # interval year to month
62
+ SQLT_INTERVAL_YM = :interval_ym
63
+ # interval day to second
64
+ SQLT_INTERVAL_DS = :interval_ds
65
+ # timestamp with local time zone
66
+ SQLT_TIMESTAMP_LTZ = :timestamp_ltz
67
+
68
+ # mapping of sql type number to sql type name.
69
+ SQLT_NAMES = {}
70
+ constants.each do |name|
71
+ next if name.to_s.index("SQLT_") != 0
72
+ val = const_get name.intern
73
+ if val.is_a? Fixnum
74
+ SQLT_NAMES[val] = name
75
+ end
76
+ end
77
+
78
+ # add alias compatible with 'Oracle7 Module for Ruby'.
79
+ alias autocommit autocommit?
80
+
81
+ class Cursor
82
+ def self.select_number_as=(val)
83
+ if val == Fixnum
84
+ @@bind_unknown_number = OCI8::BindType::Fixnum
85
+ elsif val == Integer
86
+ @@bind_unknown_number = OCI8::BindType::Integer
87
+ elsif val == Float
88
+ @@bind_unknown_number = OCI8::BindType::Float
89
+ else
90
+ raise ArgumentError, "must be Fixnum, Integer or Float"
91
+ end
92
+ end
93
+
94
+ def self.select_number_as
95
+ case @@bind_unknown_number
96
+ when OCI8::BindType::Fixnum
97
+ return Fixnum
98
+ when OCI8::BindType::Integer
99
+ return Integer
100
+ when OCI8::BindType::Float
101
+ return Float
102
+ end
103
+ end
104
+
105
+ # add alias compatible with 'Oracle7 Module for Ruby'.
106
+ alias getColNames get_col_names
107
+ end
108
+
109
+ module BindType
110
+ # alias to Integer for compatibility with ruby-oci8 1.0.
111
+ Fixnum = Integer
112
+ end
113
+ end
@@ -0,0 +1,99 @@
1
+ #--
2
+ # connection_pool.rb -- OCI8::ConnectionPool
3
+ #
4
+ # Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
5
+ #++
6
+
7
+ class OCI8
8
+ class ConnectionPool
9
+
10
+ # call-seq:
11
+ # timeout -> integer
12
+ #
13
+ # Connections idle for more than this time value (in seconds) are
14
+ # terminated, to maintain an optimum number of open
15
+ # connections. If it is zero, the connections are never timed out.
16
+ # The default value is zero.
17
+ #
18
+ # <b>Note:</b> Shrinkage of the pool only occurs when there is a network
19
+ # round trip. If there are no operations, then the connections
20
+ # stay alive.
21
+ def timeout
22
+ attr_get_ub4(OCI_ATTR_CONN_TIMEOUT)
23
+ end
24
+
25
+ # call-seq:
26
+ # timeout = integer
27
+ #
28
+ # Changes the timeout in seconds to terminate idle connections.
29
+ def timeout=(val)
30
+ attr_set_ub4(OCI_ATTR_CONN_TIMEOUT, val)
31
+ end
32
+
33
+ # call-seq:
34
+ # nowait? -> true or false
35
+ #
36
+ # If true, an error is thrown when all the connections in the pool
37
+ # are busy and the number of connections has already reached the
38
+ # maximum. Otherwise the call waits till it gets a connection.
39
+ # The default value is false.
40
+ def nowait?
41
+ attr_get_ub1(OCI_ATTR_CONN_NOWAIT) != 0
42
+ end
43
+
44
+ # call-seq:
45
+ # nowait = true or false
46
+ #
47
+ # Changes the behavior when all the connections in the pool
48
+ # are busy and the number of connections has already reached the
49
+ # maximum.
50
+ def nowait=(val)
51
+ attr_set_ub1(OCI_ATTR_CONN_NOWAIT, val ? 1 : 0)
52
+ end
53
+
54
+ # call-seq:
55
+ # busy_count -> integer
56
+ #
57
+ # Returns the number of busy connections.
58
+ def busy_count
59
+ attr_get_ub4(OCI_ATTR_CONN_BUSY_COUNT)
60
+ end
61
+
62
+ # call-seq:
63
+ # open_count -> integer
64
+ #
65
+ # Returns the number of open connections.
66
+ def open_count
67
+ attr_get_ub4(OCI_ATTR_CONN_OPEN_COUNT)
68
+ end
69
+
70
+ # call-seq:
71
+ # min -> integer
72
+ #
73
+ # Returns the number of minimum connections.
74
+ def min
75
+ attr_get_ub4(OCI_ATTR_CONN_MIN)
76
+ end
77
+
78
+ # call-seq:
79
+ # max -> integer
80
+ #
81
+ # Returns the number of maximum connections.
82
+ def max
83
+ attr_get_ub4(OCI_ATTR_CONN_MAX)
84
+ end
85
+
86
+ # call-seq:
87
+ # incr -> integer
88
+ #
89
+ # Returns the connection increment parameter.
90
+ def incr
91
+ attr_get_ub4(OCI_ATTR_CONN_INCR)
92
+ end
93
+
94
+ #
95
+ def destroy
96
+ free
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,611 @@
1
+ require 'date'
2
+
3
+ class OCI8
4
+
5
+ module BindType
6
+
7
+ # call-seq:
8
+ # OCI8::BindType.default_timezone -> :local or :utc
9
+ #
10
+ # Returns the default time zone when using Oracle 8.x client.
11
+ # The value is unused when using Oracle 9i or upper client.
12
+ #
13
+ # See also: OCI8::BindType::Time
14
+ def self.default_timezone
15
+ OCI8::BindType::Util.default_timezone
16
+ end
17
+
18
+ # call-seq:
19
+ # OCI8::BindType.default_timezone = :local or :utc
20
+ #
21
+ # Sets the default time zone when using Oracle 8.x client.
22
+ # The value is unused when using Oracle 9i or upper client.
23
+ #
24
+ # See also: OCI8::BindType::Time
25
+ def self.default_timezone=(tz)
26
+ OCI8::BindType::Util.default_timezone = tz
27
+ end
28
+
29
+ module Util # :nodoc:
30
+
31
+ @@datetime_fsec_base = (1 / ::DateTime.parse('0001-01-01 00:00:00.000000001').sec_fraction).to_i
32
+
33
+ @@default_timezone = :local
34
+ begin
35
+ Time.new(2001, 1, 1, 0, 0, 0, '+00:00')
36
+ @@time_new_accepts_timezone = true # after ruby 1.9.2
37
+ rescue ArgumentError
38
+ @@time_new_accepts_timezone = false # prior to ruby 1.9.2
39
+ end
40
+
41
+ begin
42
+ # 2001-01-01 00:00:59.999
43
+ ::DateTime.civil(2001, 1, 1, 0, 0, Rational(59_999, 1000), 0)
44
+ @@datetime_has_fractional_second_bug = false
45
+ rescue ArgumentError
46
+ @@datetime_has_fractional_second_bug = true
47
+ end
48
+
49
+ def self.default_timezone
50
+ @@default_timezone
51
+ end
52
+
53
+ def self.default_timezone=(tz)
54
+ if tz != :local and tz != :utc
55
+ raise ArgumentError, "expected :local or :utc but #{tz}"
56
+ end
57
+ @@default_timezone = tz
58
+ end
59
+
60
+ private
61
+
62
+ def datetime_to_array(val, datatype)
63
+ return nil if val.nil?
64
+
65
+ # year
66
+ year = val.year
67
+ # month
68
+ if val.respond_to? :mon
69
+ month = val.mon
70
+ elsif val.respond_to? :month
71
+ month = val.month
72
+ else
73
+ raise "expect Time, Date or DateTime but #{val.class}"
74
+ end
75
+ # day
76
+ if val.respond_to? :mday
77
+ day = val.mday
78
+ elsif val.respond_to? :day
79
+ day = val.day
80
+ else
81
+ raise "expect Time, Date or DateTime but #{val.class}"
82
+ end
83
+ # hour
84
+ if val.respond_to? :hour
85
+ hour = val.hour
86
+ else
87
+ hour = 0
88
+ end
89
+ # minute
90
+ if val.respond_to? :min
91
+ minute = val.min
92
+ else
93
+ minute = 0
94
+ end
95
+ # second
96
+ if val.respond_to? :sec
97
+ sec = val.sec
98
+ else
99
+ sec = 0
100
+ end
101
+ return [year, month, day, hour, minute, sec] if datatype == :date
102
+
103
+ # fractional second
104
+ if val.respond_to? :sec_fraction
105
+ fsec = (val.sec_fraction * @@datetime_fsec_base).to_i
106
+ elsif val.respond_to? :nsec
107
+ fsec = val.nsec
108
+ elsif val.respond_to? :usec
109
+ fsec = val.usec * 1000
110
+ else
111
+ fsec = 0
112
+ end
113
+ return [year, month, day, hour, minute, sec, fsec, nil, nil] if datatype == :timestamp
114
+
115
+ # time zone
116
+ if val.respond_to? :offset
117
+ # DateTime
118
+ tz_min = (val.offset * 1440).to_i
119
+ elsif val.respond_to? :utc_offset
120
+ # Time
121
+ tz_min = val.utc_offset / 60
122
+ else
123
+ tz_hour = nil
124
+ tz_min = nil
125
+ end
126
+ if tz_min
127
+ if tz_min < 0
128
+ tz_min = - tz_min
129
+ tz_hour = - (tz_min / 60)
130
+ tz_min = (tz_min % 60)
131
+ else
132
+ tz_hour = tz_min / 60
133
+ tz_min = tz_min % 60
134
+ end
135
+ end
136
+ [year, month, day, hour, minute, sec, fsec, tz_hour, tz_min]
137
+ end
138
+
139
+ def array_to_datetime(ary, timezone)
140
+ return nil if ary.nil?
141
+
142
+ year, month, day, hour, minute, sec, nsec, tz_hour, tz_min = ary
143
+ sec += nsec.to_r / 1000000000 if nsec and nsec != 0
144
+ if tz_hour and tz_min
145
+ offset = tz_hour.to_r / 24 + tz_min.to_r / 1440
146
+ else
147
+ if @@default_timezone == :local
148
+ if ::DateTime.respond_to? :local_offset
149
+ offset = ::DateTime.local_offset # Use a method defined by active support.
150
+ else
151
+ # Do as active support does.
152
+ offset = ::Time.local(2007).utc_offset.to_r / 86400
153
+ end
154
+ else
155
+ offset = 0
156
+ end
157
+ end
158
+
159
+ if @@datetime_has_fractional_second_bug and sec >= 59 and nsec != 0
160
+ # convert to a DateTime via a String as a workaround
161
+ if offset >= 0
162
+ sign = ?+
163
+ else
164
+ sign = ?-
165
+ offset = - offset;
166
+ end
167
+ tz_min = (offset * 1440).to_i
168
+ tz_hour, tz_min = tz_min.divmod 60
169
+ time_str = format("%04d-%02d-%02dT%02d:%02d:%02d.%09d%c%02d:%02d",
170
+ year, month, day, hour, minute, sec, nsec, sign, tz_hour, tz_min)
171
+ ::DateTime.parse(time_str)
172
+ else
173
+ ::DateTime.civil(year, month, day, hour, minute, sec, offset)
174
+ end
175
+ end
176
+
177
+ if @@time_new_accepts_timezone
178
+
179
+ # after ruby 1.9.2
180
+ def array_to_time(ary, timezone)
181
+ return nil if ary.nil?
182
+
183
+ year, month, day, hour, minute, sec, nsec, tz_hour, tz_min = ary
184
+ nsec ||= 0
185
+
186
+ if timezone
187
+ usec = (nsec == 0) ? 0 : nsec.to_r / 1000
188
+ ::Time.send(timezone, year, month, day, hour, minute, sec, usec)
189
+ else
190
+ sec += nsec.to_r / 1_000_000_000 if nsec != 0
191
+ utc_offset = tz_hour * 3600 + tz_min * 60
192
+ ::Time.new(year, month, day, hour, minute, sec, utc_offset)
193
+ end
194
+ end
195
+
196
+ else
197
+
198
+ # prior to ruby 1.9.2
199
+ def array_to_time(ary, timezone)
200
+ return nil if ary.nil?
201
+
202
+ year, month, day, hour, minute, sec, nsec, tz_hour, tz_min = ary
203
+ nsec ||= 0
204
+ usec = (nsec == 0) ? 0 : nsec.to_r / 1000
205
+ begin
206
+ if timezone
207
+ return ::Time.send(:timezone, year, month, day, hour, minute, sec, usec)
208
+ else
209
+ if tz_hour == 0 and tz_min == 0
210
+ tm = ::Time.utc(year, month, day, hour, minute, sec, usec)
211
+ # Time.utc(99, ...) returns a time object the year of which is 1999.
212
+ # 'tm.year == year' checks such cases.
213
+ return tm if tm.year == year
214
+ else
215
+ tm = ::Time.local(year, month, day, hour, minute, sec, usec)
216
+ return tm if tm.utc_offset == tz_hour * 3600 + tz_min * 60 and tm.year == year
217
+ end
218
+ end
219
+ rescue StandardError
220
+ end
221
+ array_to_datetime(ary, timezone)
222
+ end
223
+
224
+ end
225
+ end
226
+
227
+ #--
228
+ # OCI8::BindType::DateTime
229
+ #++
230
+ # This is a helper class to select or bind Oracle data types such as
231
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
232
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt>. The retrieved value
233
+ # is a \DateTime.
234
+ #
235
+ # === How to select \DataTime values.
236
+ #
237
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
238
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt> are selected as a \Time
239
+ # by default. You change the behaviour by explicitly calling
240
+ # OCI8::Cursor#define as follows:
241
+ #
242
+ # cursor = conn.parse("SELECT hiredate FROM emp")
243
+ # cursor.define(1, nil, DateTime)
244
+ # cursor.exec()
245
+ #
246
+ # Otherwise, you can change the default mapping for all queries.
247
+ #
248
+ # # Changes the mapping for DATE
249
+ # OCI8::BindType::Mapping[OCI8::SQLT_DAT] = OCI8::BindType::DateTime
250
+ #
251
+ # # Changes the mapping for TIMESTAMP
252
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::DateTime
253
+ #
254
+ # # Changes the mapping for TIMESTAMP WITH TIME ZONE
255
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::DateTime
256
+ #
257
+ # # Changes the mapping for TIMESTAMP WITH LOCAL TIME ZONE
258
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::DateTime
259
+ #
260
+ # === Note for default time zone
261
+ #
262
+ # The retrieved value's time zone is determined by the session time zone
263
+ # if its data type is <tt>DATE</tt>, <tt>TIMESTAMP</tt> or <tt>TIMESTAMP
264
+ # WITH LOCAL TIME ZONE</tt>.
265
+ #
266
+ # The session time zone is same with local machine's by default.
267
+ # It is changed by the following SQL.
268
+ #
269
+ # ALTER SESSION SET TIME_ZONE='-05:00'
270
+ #
271
+ # === Note for Oracle 8.x client
272
+ #
273
+ # Timestamp data types and session time zone are new features in
274
+ # Oracle 9i. This class is available only to fetch or bind <tt>DATE</tt>
275
+ # when using Oracle 8.x client.
276
+ #
277
+ # The retrieved value's time zone is determined not by the session
278
+ # time zone, but by the OCI8::BindType.default_timezone
279
+ # The time zone can be changed as follows:
280
+ #
281
+ # OCI8::BindType.default_timezone = :local
282
+ # # or
283
+ # OCI8::BindType.default_timezone = :utc
284
+ #
285
+ # If you are in the regions where daylight saving time is adopted,
286
+ # you should use OCI8::BindType::Time.
287
+ #
288
+ class DateTime < OCI8::BindType::OCITimestampTZ
289
+ include OCI8::BindType::Util
290
+
291
+ def set(val) # :nodoc:
292
+ super(datetime_to_array(val, :timestamp_tz))
293
+ end
294
+
295
+ def get() # :nodoc:
296
+ array_to_datetime(super(), nil)
297
+ end
298
+ end
299
+
300
+ class LocalDateTime < OCI8::BindType::OCITimestamp
301
+ include OCI8::BindType::Util
302
+
303
+ def set(val) # :nodoc:
304
+ super(datetime_to_array(val, :timestamp))
305
+ end
306
+
307
+ def get() # :nodoc:
308
+ array_to_datetime(super(), :local)
309
+ end
310
+ end
311
+
312
+ class UTCDateTime < OCI8::BindType::OCITimestamp
313
+ include OCI8::BindType::Util
314
+
315
+ def set(val) # :nodoc:
316
+ super(datetime_to_array(val, :timestamp))
317
+ end
318
+
319
+ def get() # :nodoc:
320
+ array_to_datetime(super(), :utc)
321
+ end
322
+ end
323
+
324
+ #--
325
+ # OCI8::BindType::Time
326
+ #++
327
+ # This is a helper class to select or bind Oracle data types such as
328
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
329
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt>. The retrieved value
330
+ # is a \Time.
331
+ #
332
+ # === How to select \Time values.
333
+ #
334
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
335
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt> are selected as a \Time
336
+ # by default. If the default behaviour is changed, you can select it
337
+ # as a \Time by explicitly calling OCI8::Cursor#define as follows:
338
+ #
339
+ # cursor = conn.parse("SELECT hiredate FROM emp")
340
+ # cursor.define(1, nil, Time)
341
+ # cursor.exec()
342
+ #
343
+ # === Note for ruby prior to 1.9.2
344
+ #
345
+ # If the retrieved value cannot be represented by \Time, it become
346
+ # a \DateTime. The fallback is done only when the ruby is before 1.9.2
347
+ # and one of the following conditions are met.
348
+ # - The timezone part is neither local nor utc.
349
+ # - The time is out of the time_t[http://en.wikipedia.org/wiki/Time_t].
350
+ #
351
+ # If the retrieved value has the precision of fractional second more
352
+ # than 6, the fractional second is truncated to microsecond, which
353
+ # is the precision of standard \Time class.
354
+ #
355
+ # To avoid this fractional second truncation:
356
+ # - Upgrade to ruby 1.9.2, whose \Time precision is nanosecond.
357
+ # - Otherwise, change the defalt mapping to use \DateTime as follows.
358
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::DateTime
359
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::DateTime
360
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::DateTime
361
+ #
362
+ # === Note for default time zone
363
+ #
364
+ # The retrieved value's time zone is determined by the session time zone
365
+ # if its data type is <tt>DATE</tt>, <tt>TIMESTAMP</tt> or <tt>TIMESTAMP
366
+ # WITH LOCAL TIME ZONE</tt>.
367
+ #
368
+ # The session time zone is same with local machine's by default.
369
+ # It is changed by the following SQL.
370
+ #
371
+ # ALTER SESSION SET TIME_ZONE='-05:00'
372
+ #
373
+ # === Note for Oracle 8.x client
374
+ #
375
+ # Timestamp data types and session time zone are new features in
376
+ # Oracle 9i. This class is available only to fetch or bind <tt>DATE</tt>
377
+ # when using Oracle 8.x client.
378
+ #
379
+ # The retrieved value's time zone is determined not by the session
380
+ # time zone, but by the OCI8::BindType.default_timezone
381
+ # The time zone can be changed as follows:
382
+ #
383
+ # OCI8::BindType.default_timezone = :local
384
+ # # or
385
+ # OCI8::BindType.default_timezone = :utc
386
+ #
387
+ class Time < OCI8::BindType::OCITimestampTZ
388
+ include OCI8::BindType::Util
389
+
390
+ def set(val) # :nodoc:
391
+ super(datetime_to_array(val, :timestamp_tz))
392
+ end
393
+
394
+ def get() # :nodoc:
395
+ array_to_time(super(), nil)
396
+ end
397
+ end
398
+
399
+ class LocalTime < OCI8::BindType::OCITimestamp
400
+ include OCI8::BindType::Util
401
+
402
+ def set(val) # :nodoc:
403
+ super(datetime_to_array(val, :timestamp))
404
+ end
405
+
406
+ def get() # :nodoc:
407
+ array_to_time(super(), :local)
408
+ end
409
+ end
410
+
411
+ class UTCTime < OCI8::BindType::OCITimestamp
412
+ include OCI8::BindType::Util
413
+
414
+ def set(val) # :nodoc:
415
+ super(datetime_to_array(val, :timestamp))
416
+ end
417
+
418
+ def get() # :nodoc:
419
+ array_to_time(super(), :utc)
420
+ end
421
+ end
422
+
423
+ #--
424
+ # OCI8::BindType::IntervalYM
425
+ #++
426
+ #
427
+ # This is a helper class to select or bind Oracle data type
428
+ # <tt>INTERVAL YEAR TO MONTH</tt>. The retrieved value is
429
+ # the number of months between two timestamps.
430
+ #
431
+ # The value can be applied to \DateTime#>> to shift months.
432
+ # It can be applied to \Time#months_since if activisupport has
433
+ # been loaded.
434
+ #
435
+ # === How to select <tt>INTERVAL YEAR TO MONTH</tt>
436
+ #
437
+ # <tt>INTERVAL YEAR TO MONTH</tt> is selected as an Integer.
438
+ #
439
+ # conn.exec("select (current_timestamp - hiredate) year to month from emp") do |hired_months|
440
+ # puts "hired_months = #{hired_months}"
441
+ # end
442
+ #
443
+ # == How to bind <tt>INTERVAL YEAR TO MONTH</tt>
444
+ #
445
+ # You cannot bind a bind variable as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
446
+ # It must be bound explicitly by OCI8::Cursor#bind_param.
447
+ #
448
+ # # output bind variable
449
+ # cursor = conn.parse(<<-EOS)
450
+ # BEGIN
451
+ # :interval := (:ts1 - :ts2) YEAR TO MONTH;
452
+ # END;
453
+ # EOS
454
+ # cursor.bind_param(:interval, nil, :interval_ym)
455
+ # cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
456
+ # cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
457
+ # cursor.exec
458
+ # cursor[:interval] # => 4 (months)
459
+ # cursor.close
460
+ #
461
+ # # input bind variable
462
+ # cursor = conn.parse(<<-EOS)
463
+ # BEGIN
464
+ # :ts1 := :ts2 + :interval;
465
+ # END;
466
+ # EOS
467
+ # cursor.bind_param(:ts1, nil, DateTime)
468
+ # cursor.bind_param(:ts2, Date.parse('1969-11-19'))
469
+ # cursor.bind_param(:interval, 4, :interval_ym)
470
+ # cursor.exec
471
+ # cursor[:ts1].strftime('%Y-%m-%d') # => 1970-03-19
472
+ # cursor.close
473
+ #
474
+ class IntervalYM < OCI8::BindType::OCIIntervalYM
475
+ def set(val) # :nodoc:
476
+ unless val.nil?
477
+ val = [val / 12, val % 12]
478
+ end
479
+ super(val)
480
+ end
481
+ def get() # :nodoc:
482
+ val = super()
483
+ return nil if val.nil?
484
+ year, month = val
485
+ year * 12 + month
486
+ end
487
+ end # OCI8::BindType::IntervalYM
488
+
489
+ #--
490
+ # OCI8::BindType::IntervalDS
491
+ #++
492
+ #
493
+ # (new in 2.0)
494
+ #
495
+ # This is a helper class to select or bind Oracle data type
496
+ # <tt>INTERVAL DAY TO SECOND</tt>. The retrieved value is
497
+ # the number of seconds between two typestamps as a \Float.
498
+ #
499
+ # Note that it is the number days as a \Rational if
500
+ # OCI8::BindType::IntervalDS.unit is :day or the ruby-oci8
501
+ # version is prior to 2.0.3.
502
+ #
503
+ # == How to bind <tt>INTERVAL DAY TO SECOND</tt>
504
+ #
505
+ # You cannot bind a bind variable as <tt>INTERVAL DAY TO SECOND</tt>
506
+ # implicitly. It must be bound explicitly by OCI8::Cursor#bind_param.
507
+ #
508
+ # # output bind variable
509
+ # cursor = conn.parse(<<-EOS)
510
+ # BEGIN
511
+ # :interval := (:ts1 - :ts2) DAY TO SECOND(9);
512
+ # END;
513
+ # EOS
514
+ # cursor.bind_param(:interval, nil, :interval_ds)
515
+ # cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
516
+ # cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
517
+ # cursor.exec
518
+ # cursor[:interval] # => 10492615.0 seconds
519
+ # cursor.close
520
+ #
521
+ # # input bind variable
522
+ # cursor = conn.parse(<<-EOS)
523
+ # BEGIN
524
+ # :ts1 := :ts2 + :interval;
525
+ # END;
526
+ # EOS
527
+ # cursor.bind_param(:ts1, nil, DateTime)
528
+ # cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
529
+ # cursor.bind_param(:interval, 10492615.0, :interval_ds)
530
+ # cursor.exec
531
+ # cursor[:ts1].strftime('%Y-%m-%d %H:%M:%S') # => 1969-11-19 06:54:35
532
+ # cursor.close
533
+ #
534
+ class IntervalDS < OCI8::BindType::OCIIntervalDS
535
+ @@hour = 1 / 24.to_r
536
+ @@minute = @@hour / 60
537
+ @@sec = @@minute / 60
538
+ @@fsec = @@sec / 1000000000
539
+ @@unit = :second
540
+
541
+ # call-seq:
542
+ # OCI8::BindType::IntervalDS.unit -> :second or :day
543
+ #
544
+ # (new in 2.0.3)
545
+ #
546
+ # Retrieves the unit of interval.
547
+ def self.unit
548
+ @@unit
549
+ end
550
+
551
+ # call-seq:
552
+ # OCI8::BindType::IntervalDS.unit = :second or :day
553
+ #
554
+ # (new in 2.0.3)
555
+ #
556
+ # Changes the unit of interval. :second is the default.
557
+ def self.unit=(val)
558
+ case val
559
+ when :second, :day
560
+ @@unit = val
561
+ else
562
+ raise 'unit should be :second or :day'
563
+ end
564
+ end
565
+
566
+ def set(val) # :nodoc:
567
+ unless val.nil?
568
+ if val < 0
569
+ is_minus = true
570
+ val = -val
571
+ else
572
+ is_minus = false
573
+ end
574
+ if @@unit == :second
575
+ day, val = val.divmod 86400
576
+ hour, val = val.divmod 3600
577
+ minute, val = val.divmod 60
578
+ sec, val = val.divmod 1
579
+ else
580
+ day, val = val.divmod 1
581
+ hour, val = (val * 24).divmod 1
582
+ minute, val = (val * 60).divmod 1
583
+ sec, val = (val * 60).divmod 1
584
+ end
585
+ fsec, val = (val * 1000000000).divmod 1
586
+ if is_minus
587
+ day = - day
588
+ hour = - hour
589
+ minute = - minute
590
+ sec = - sec
591
+ fsec = - fsec
592
+ end
593
+ val = [day, hour, minute, sec, fsec]
594
+ end
595
+ super(val)
596
+ end
597
+
598
+ def get() # :nodoc:
599
+ val = super()
600
+ return nil if val.nil?
601
+ day, hour, minute, sec, fsec = val
602
+ if @@unit == :second
603
+ fsec = fsec / 1000000000.0
604
+ day * 86400 + hour * 3600 + minute * 60 + sec + fsec
605
+ else
606
+ day + (hour * @@hour) + (minute * @@minute) + (sec * @@sec) + (fsec * @@fsec)
607
+ end
608
+ end
609
+ end # OCI8::BindType::IntervalDS
610
+ end # OCI8::BindType
611
+ end # OCI8