ruby-oci8 2.0.4-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.
Files changed (52) hide show
  1. data/ChangeLog +1912 -0
  2. data/Makefile +96 -0
  3. data/NEWS +223 -0
  4. data/README +86 -0
  5. data/VERSION +1 -0
  6. data/dist-files +77 -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/lib/.document +1 -0
  13. data/lib/dbd/OCI8.rb +591 -0
  14. data/lib/oci8.rb +82 -0
  15. data/lib/oci8.rb.in +82 -0
  16. data/lib/oci8/.document +5 -0
  17. data/lib/oci8/bindtype.rb +319 -0
  18. data/lib/oci8/compat.rb +113 -0
  19. data/lib/oci8/datetime.rb +619 -0
  20. data/lib/oci8/encoding-init.rb +40 -0
  21. data/lib/oci8/encoding.yml +537 -0
  22. data/lib/oci8/metadata.rb +2077 -0
  23. data/lib/oci8/object.rb +562 -0
  24. data/lib/oci8/oci8.rb +571 -0
  25. data/lib/oci8/oracle_version.rb +144 -0
  26. data/lib/oci8lib_18.so +0 -0
  27. data/lib/oci8lib_191.so +0 -0
  28. data/metaconfig +142 -0
  29. data/pre-distclean.rb +7 -0
  30. data/ruby-oci8.gemspec +63 -0
  31. data/setup.rb +1331 -0
  32. data/test/README +4 -0
  33. data/test/config.rb +109 -0
  34. data/test/test_all.rb +50 -0
  35. data/test/test_appinfo.rb +63 -0
  36. data/test/test_array_dml.rb +333 -0
  37. data/test/test_bind_raw.rb +46 -0
  38. data/test/test_bind_time.rb +178 -0
  39. data/test/test_break.rb +83 -0
  40. data/test/test_clob.rb +79 -0
  41. data/test/test_connstr.rb +81 -0
  42. data/test/test_datetime.rb +622 -0
  43. data/test/test_dbi.rb +366 -0
  44. data/test/test_dbi_clob.rb +53 -0
  45. data/test/test_encoding.rb +100 -0
  46. data/test/test_metadata.rb +257 -0
  47. data/test/test_oci8.rb +434 -0
  48. data/test/test_oracle_version.rb +70 -0
  49. data/test/test_oradate.rb +256 -0
  50. data/test/test_oranumber.rb +655 -0
  51. data/test/test_rowid.rb +33 -0
  52. metadata +108 -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,619 @@
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
+ def self.default_timezone
42
+ @@default_timezone
43
+ end
44
+
45
+ def self.default_timezone=(tz)
46
+ if tz != :local and tz != :utc
47
+ raise ArgumentError, "expected :local or :utc but #{tz}"
48
+ end
49
+ @@default_timezone = tz
50
+ end
51
+
52
+ private
53
+
54
+ def datetime_to_array(val, full)
55
+ return nil if val.nil?
56
+
57
+ # year
58
+ year = val.year
59
+ # month
60
+ if val.respond_to? :mon
61
+ month = val.mon
62
+ elsif val.respond_to? :month
63
+ month = val.month
64
+ else
65
+ raise "expect Time, Date or DateTime but #{val.class}"
66
+ end
67
+ # day
68
+ if val.respond_to? :mday
69
+ day = val.mday
70
+ elsif val.respond_to? :day
71
+ day = val.day
72
+ else
73
+ raise "expect Time, Date or DateTime but #{val.class}"
74
+ end
75
+ # hour
76
+ if val.respond_to? :hour
77
+ hour = val.hour
78
+ else
79
+ hour = 0
80
+ end
81
+ # minute
82
+ if val.respond_to? :min
83
+ minute = val.min
84
+ else
85
+ minute = 0
86
+ end
87
+ # second
88
+ if val.respond_to? :sec
89
+ sec = val.sec
90
+ else
91
+ sec = 0
92
+ end
93
+ return [year, month, day, hour, minute, sec] unless full
94
+
95
+ # fractional second
96
+ if val.respond_to? :sec_fraction
97
+ fsec = (val.sec_fraction * @@datetime_fsec_base).to_i
98
+ elsif val.respond_to? :nsec
99
+ fsec = val.nsec
100
+ elsif val.respond_to? :usec
101
+ fsec = val.usec * 1000
102
+ else
103
+ fsec = 0
104
+ end
105
+ # time zone
106
+ if val.respond_to? :offset
107
+ # DateTime
108
+ tz_min = (val.offset * 1440).to_i
109
+ elsif val.respond_to? :utc_offset
110
+ # Time
111
+ tz_min = val.utc_offset / 60
112
+ else
113
+ tz_hour = nil
114
+ tz_min = nil
115
+ end
116
+ if tz_min
117
+ if tz_min < 0
118
+ tz_min = - tz_min
119
+ tz_hour = - (tz_min / 60)
120
+ tz_min = (tz_min % 60)
121
+ else
122
+ tz_hour = tz_min / 60
123
+ tz_min = tz_min % 60
124
+ end
125
+ end
126
+ [year, month, day, hour, minute, sec, fsec, tz_hour, tz_min]
127
+ end
128
+
129
+ def ocidate_to_datetime(ary)
130
+ return nil if ary.nil?
131
+
132
+ year, month, day, hour, minute, sec = ary
133
+ if @@default_timezone == :local
134
+ if ::DateTime.respond_to? :local_offset
135
+ offset = ::DateTime.local_offset # Use a method defined by active support.
136
+ else
137
+ # Do as active support does.
138
+ offset = ::Time.local(2007).utc_offset.to_r / 86400
139
+ end
140
+ else
141
+ offset = 0
142
+ end
143
+ ::DateTime.civil(year, month, day, hour, minute, sec, offset)
144
+ end
145
+
146
+ def ocidate_to_time(ary)
147
+ return nil if ary.nil?
148
+
149
+ year, month, day, hour, minute, sec = ary
150
+ if @@time_new_accepts_timezone || year >= 139 || year < 0
151
+ begin
152
+ return ::Time.send(@@default_timezone, year, month, day, hour, minute, sec)
153
+ rescue StandardError
154
+ end
155
+ end
156
+ ocidate_to_datetime(ary)
157
+ end
158
+
159
+ if OCI8.oracle_client_version >= ORAVER_9_0
160
+
161
+ def ocitimestamp_to_datetime(ary)
162
+ return nil if ary.nil?
163
+
164
+ year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
165
+ if sec >= 59 and fsec != 0
166
+ # convert to a DateTime via a String as a last resort.
167
+ if tz_hour >= 0 && tz_min >= 0
168
+ sign = ?+
169
+ else
170
+ sign = ?-
171
+ tz_hour = - tz_hour
172
+ tz_min = - tz_min
173
+ end
174
+ time_str = format("%04d-%02d-%02dT%02d:%02d:%02d.%09d%c%02d:%02d",
175
+ year, month, day, hour, minute, sec, fsec, sign, tz_hour, tz_min)
176
+ ::DateTime.parse(time_str)
177
+ else
178
+ sec += fsec.to_r / 1000000000
179
+ offset = tz_hour.to_r / 24 + tz_min.to_r / 1440
180
+ ::DateTime.civil(year, month, day, hour, minute, sec, offset)
181
+ end
182
+ end
183
+
184
+ if @@time_new_accepts_timezone
185
+
186
+ # after ruby 1.9.2
187
+ def ocitimestamp_to_time(ary)
188
+ return nil if ary.nil?
189
+
190
+ year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
191
+
192
+ sec += fsec / Rational(1000000000)
193
+ utc_offset = tz_hour * 3600 + tz_min * 60
194
+ return ::Time.new(year, month, day, hour, minute, sec, utc_offset)
195
+ end
196
+
197
+ else
198
+
199
+ # prior to ruby 1.9.2
200
+ def ocitimestamp_to_time(ary)
201
+ return nil if ary.nil?
202
+
203
+ year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
204
+
205
+ if year >= 139 || year < 0
206
+ begin
207
+ if tz_hour == 0 and tz_min == 0
208
+ return ::Time.utc(year, month, day, hour, minute, sec, fsec / Rational(1000))
209
+ else
210
+ tm = ::Time.local(year, month, day, hour, minute, sec, fsec / Rational(1000))
211
+ return tm if tm.utc_offset == tz_hour * 3600 + tz_min * 60
212
+ end
213
+ rescue StandardError
214
+ end
215
+ end
216
+ ocitimestamp_to_datetime(ary)
217
+ end
218
+
219
+ end
220
+ end
221
+ end
222
+
223
+ class DateTimeViaOCIDate < OCI8::BindType::OCIDate # :nodoc:
224
+ include OCI8::BindType::Util
225
+
226
+ def set(val) # :nodoc:
227
+ super(datetime_to_array(val, false))
228
+ end
229
+
230
+ def get() # :nodoc:
231
+ ocidate_to_datetime(super())
232
+ end
233
+ end
234
+
235
+ class TimeViaOCIDate < OCI8::BindType::OCIDate # :nodoc:
236
+ include OCI8::BindType::Util
237
+
238
+ def set(val) # :nodoc:
239
+ super(datetime_to_array(val, false))
240
+ end
241
+
242
+ def get() # :nodoc:
243
+ ocidate_to_time(super())
244
+ end
245
+ end
246
+
247
+ if OCI8.oracle_client_version >= ORAVER_9_0
248
+ class DateTimeViaOCITimestamp < OCI8::BindType::OCITimestamp # :nodoc:
249
+ include OCI8::BindType::Util
250
+
251
+ def set(val) # :nodoc:
252
+ super(datetime_to_array(val, true))
253
+ end
254
+
255
+ def get() # :nodoc:
256
+ ocitimestamp_to_datetime(super())
257
+ end
258
+ end
259
+
260
+ class TimeViaOCITimestamp < OCI8::BindType::OCITimestamp # :nodoc:
261
+ include OCI8::BindType::Util
262
+
263
+ def set(val) # :nodoc:
264
+ super(datetime_to_array(val, true))
265
+ end
266
+
267
+ def get() # :nodoc:
268
+ ocitimestamp_to_time(super())
269
+ end
270
+ end
271
+ end
272
+
273
+ #--
274
+ # OCI8::BindType::DateTime
275
+ #++
276
+ # This is a helper class to select or bind Oracle data types such as
277
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
278
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt>. The retrieved value
279
+ # is a \DateTime.
280
+ #
281
+ # === How to select \DataTime values.
282
+ #
283
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
284
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt> are selected as a \Time
285
+ # by default. You change the behaviour by explicitly calling
286
+ # OCI8::Cursor#define as follows:
287
+ #
288
+ # cursor = conn.parse("SELECT hiredate FROM emp")
289
+ # cursor.define(1, nil, DateTime)
290
+ # cursor.exec()
291
+ #
292
+ # Otherwise, you can change the default mapping for all queries.
293
+ #
294
+ # # Changes the mapping for DATE
295
+ # OCI8::BindType::Mapping[OCI8::SQLT_DAT] = OCI8::BindType::DateTime
296
+ #
297
+ # # Changes the mapping for TIMESTAMP
298
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::DateTime
299
+ #
300
+ # # Changes the mapping for TIMESTAMP WITH TIME ZONE
301
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::DateTime
302
+ #
303
+ # # Changes the mapping for TIMESTAMP WITH LOCAL TIME ZONE
304
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::DateTime
305
+ #
306
+ # === Note for default time zone
307
+ #
308
+ # The retrieved value's time zone is determined by the session time zone
309
+ # if its data type is <tt>DATE</tt>, <tt>TIMESTAMP</tt> or <tt>TIMESTAMP
310
+ # WITH LOCAL TIME ZONE</tt>.
311
+ #
312
+ # The session time zone is same with local machine's by default.
313
+ # It is changed by the following SQL.
314
+ #
315
+ # ALTER SESSION SET TIME_ZONE='-05:00'
316
+ #
317
+ # === Note for Oracle 8.x client
318
+ #
319
+ # Timestamp data types and session time zone are new features in
320
+ # Oracle 9i. This class is available only to fetch or bind <tt>DATE</tt>
321
+ # when using Oracle 8.x client.
322
+ #
323
+ # The retrieved value's time zone is determined not by the session
324
+ # time zone, but by the OCI8::BindType.default_timezone
325
+ # The time zone can be changed as follows:
326
+ #
327
+ # OCI8::BindType.default_timezone = :local
328
+ # # or
329
+ # OCI8::BindType.default_timezone = :utc
330
+ #
331
+ # If you are in the regions where daylight saving time is adopted,
332
+ # you should use OCI8::BindType::Time.
333
+ #
334
+ class DateTime
335
+ if OCI8.oracle_client_version >= ORAVER_9_0
336
+ def self.create(con, val, param, max_array_size) # :nodoc:
337
+ if true # TODO: check Oracle server version
338
+ DateTimeViaOCITimestamp.new(con, val, param, max_array_size)
339
+ else
340
+ DateTimeViaOCIDate.new(con, val, param, max_array_size)
341
+ end
342
+ end
343
+ else
344
+ def self.create(con, val, param, max_array_size) # :nodoc:
345
+ DateTimeViaOCIDate.new(con, val, param, max_array_size)
346
+ end
347
+ end
348
+ end
349
+
350
+ #--
351
+ # OCI8::BindType::Time
352
+ #++
353
+ # This is a helper class to select or bind Oracle data types such as
354
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
355
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt>. The retrieved value
356
+ # is a \Time.
357
+ #
358
+ # === How to select \Time values.
359
+ #
360
+ # <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
361
+ # and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt> are selected as a \Time
362
+ # by default. If the default behaviour is changed, you can select it
363
+ # as a \Time by explicitly calling OCI8::Cursor#define as follows:
364
+ #
365
+ # cursor = conn.parse("SELECT hiredate FROM emp")
366
+ # cursor.define(1, nil, Time)
367
+ # cursor.exec()
368
+ #
369
+ # === Note for ruby prior to 1.9.2
370
+ #
371
+ # If the retrieved value cannot be represented by \Time, it become
372
+ # a \DateTime. The fallback is done only when the ruby is before 1.9.2
373
+ # and one of the following conditions are met.
374
+ # - The timezone part is neither local nor utc.
375
+ # - The time is out of the time_t[http://en.wikipedia.org/wiki/Time_t].
376
+ #
377
+ # If the retrieved value has the precision of fractional second more
378
+ # than 6, the fractional second is truncated to microsecond, which
379
+ # is the precision of standard \Time class.
380
+ #
381
+ # To avoid this fractional second truncation:
382
+ # - Upgrade to ruby 1.9.2, whose \Time precision is nanosecond.
383
+ # - Otherwise, change the defalt mapping to use \DateTime as follows.
384
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::DateTime
385
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::DateTime
386
+ # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::DateTime
387
+ #
388
+ # === Note for default time zone
389
+ #
390
+ # The retrieved value's time zone is determined by the session time zone
391
+ # if its data type is <tt>DATE</tt>, <tt>TIMESTAMP</tt> or <tt>TIMESTAMP
392
+ # WITH LOCAL TIME ZONE</tt>.
393
+ #
394
+ # The session time zone is same with local machine's by default.
395
+ # It is changed by the following SQL.
396
+ #
397
+ # ALTER SESSION SET TIME_ZONE='-05:00'
398
+ #
399
+ # === Note for Oracle 8.x client
400
+ #
401
+ # Timestamp data types and session time zone are new features in
402
+ # Oracle 9i. This class is available only to fetch or bind <tt>DATE</tt>
403
+ # when using Oracle 8.x client.
404
+ #
405
+ # The retrieved value's time zone is determined not by the session
406
+ # time zone, but by the OCI8::BindType.default_timezone
407
+ # The time zone can be changed as follows:
408
+ #
409
+ # OCI8::BindType.default_timezone = :local
410
+ # # or
411
+ # OCI8::BindType.default_timezone = :utc
412
+ #
413
+ class Time
414
+ if OCI8.oracle_client_version >= ORAVER_9_0
415
+ def self.create(con, val, param, max_array_size) # :nodoc:
416
+ if true # TODO: check Oracle server version
417
+ TimeViaOCITimestamp.new(con, val, param, max_array_size)
418
+ else
419
+ TimeViaOCIDate.new(con, val, param, max_array_size)
420
+ end
421
+ end
422
+ else
423
+ def self.create(con, val, param, max_array_size) # :nodoc:
424
+ TimeViaOCIDate.new(con, val, param, max_array_size)
425
+ end
426
+ end
427
+ end
428
+
429
+ if OCI8.oracle_client_version >= ORAVER_9_0
430
+ #--
431
+ # OCI8::BindType::IntervalYM
432
+ #++
433
+ #
434
+ # This is a helper class to select or bind Oracle data type
435
+ # <tt>INTERVAL YEAR TO MONTH</tt>. The retrieved value is
436
+ # the number of months between two timestamps.
437
+ #
438
+ # The value can be applied to \DateTime#>> to shift months.
439
+ # It can be applied to \Time#months_since if activisupport has
440
+ # been loaded.
441
+ #
442
+ # === How to select <tt>INTERVAL YEAR TO MONTH</tt>
443
+ #
444
+ # <tt>INTERVAL YEAR TO MONTH</tt> is selected as an Integer.
445
+ #
446
+ # conn.exec("select (current_timestamp - hiredate) year to month from emp") do |hired_months|
447
+ # puts "hired_months = #{hired_months}"
448
+ # end
449
+ #
450
+ # == How to bind <tt>INTERVAL YEAR TO MONTH</tt>
451
+ #
452
+ # You cannot bind a bind variable as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
453
+ # It must be bound explicitly by OCI8::Cursor#bind_param.
454
+ #
455
+ # # output bind variable
456
+ # cursor = conn.parse(<<-EOS)
457
+ # BEGIN
458
+ # :interval := (:ts1 - :ts2) YEAR TO MONTH;
459
+ # END;
460
+ # EOS
461
+ # cursor.bind_param(:interval, nil, :interval_ym)
462
+ # cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
463
+ # cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
464
+ # cursor.exec
465
+ # cursor[:interval] # => 4 (months)
466
+ # cursor.close
467
+ #
468
+ # # input bind variable
469
+ # cursor = conn.parse(<<-EOS)
470
+ # BEGIN
471
+ # :ts1 := :ts2 + :interval;
472
+ # END;
473
+ # EOS
474
+ # cursor.bind_param(:ts1, nil, DateTime)
475
+ # cursor.bind_param(:ts2, Date.parse('1969-11-19'))
476
+ # cursor.bind_param(:interval, 4, :interval_ym)
477
+ # cursor.exec
478
+ # cursor[:ts1].strftime('%Y-%m-%d') # => 1970-03-19
479
+ # cursor.close
480
+ #
481
+ class IntervalYM < OCI8::BindType::OCIIntervalYM
482
+ def set(val) # :nodoc:
483
+ unless val.nil?
484
+ val = [val / 12, val % 12]
485
+ end
486
+ super(val)
487
+ end
488
+ def get() # :nodoc:
489
+ val = super()
490
+ return nil if val.nil?
491
+ year, month = val
492
+ year * 12 + month
493
+ end
494
+ end # OCI8::BindType::IntervalYM
495
+
496
+ #--
497
+ # OCI8::BindType::IntervalDS
498
+ #++
499
+ #
500
+ # (new in 2.0)
501
+ #
502
+ # This is a helper class to select or bind Oracle data type
503
+ # <tt>INTERVAL DAY TO SECOND</tt>. The retrieved value is
504
+ # the number of seconds between two typestamps as a \Float.
505
+ #
506
+ # Note that it is the number days as a \Rational if
507
+ # OCI8::BindType::IntervalDS.unit is :day or the ruby-oci8
508
+ # version is prior to 2.0.3.
509
+ #
510
+ # == How to bind <tt>INTERVAL DAY TO SECOND</tt>
511
+ #
512
+ # You cannot bind a bind variable as <tt>INTERVAL DAY TO SECOND</tt>
513
+ # implicitly. It must be bound explicitly by OCI8::Cursor#bind_param.
514
+ #
515
+ # # output bind variable
516
+ # cursor = conn.parse(<<-EOS)
517
+ # BEGIN
518
+ # :interval := (:ts1 - :ts2) DAY TO SECOND(9);
519
+ # END;
520
+ # EOS
521
+ # cursor.bind_param(:interval, nil, :interval_ds)
522
+ # cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
523
+ # cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
524
+ # cursor.exec
525
+ # cursor[:interval] # => 10492615.0 seconds
526
+ # cursor.close
527
+ #
528
+ # # input bind variable
529
+ # cursor = conn.parse(<<-EOS)
530
+ # BEGIN
531
+ # :ts1 := :ts2 + :interval;
532
+ # END;
533
+ # EOS
534
+ # cursor.bind_param(:ts1, nil, DateTime)
535
+ # cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
536
+ # cursor.bind_param(:interval, 10492615.0, :interval_ds)
537
+ # cursor.exec
538
+ # cursor[:ts1].strftime('%Y-%m-%d %H:%M:%S') # => 1969-11-19 06:54:35
539
+ # cursor.close
540
+ #
541
+ class IntervalDS < OCI8::BindType::OCIIntervalDS
542
+ @@hour = 1 / 24.to_r
543
+ @@minute = @@hour / 60
544
+ @@sec = @@minute / 60
545
+ @@fsec = @@sec / 1000000000
546
+ @@unit = :second
547
+
548
+ # call-seq:
549
+ # OCI8::BindType::IntervalDS.unit -> :second or :day
550
+ #
551
+ # (new in 2.0.3)
552
+ #
553
+ # Retrieves the unit of interval.
554
+ def self.unit
555
+ @@unit
556
+ end
557
+
558
+ # call-seq:
559
+ # OCI8::BindType::IntervalDS.unit = :second or :day
560
+ #
561
+ # (new in 2.0.3)
562
+ #
563
+ # Changes the unit of interval. :second is the default.
564
+ def self.unit=(val)
565
+ case val
566
+ when :second, :day
567
+ @@unit = val
568
+ else
569
+ raise 'unit should be :second or :day'
570
+ end
571
+ end
572
+
573
+ def set(val) # :nodoc:
574
+ unless val.nil?
575
+ if val < 0
576
+ is_minus = true
577
+ val = -val
578
+ else
579
+ is_minus = false
580
+ end
581
+ if @@unit == :second
582
+ day, val = val.divmod 86400
583
+ hour, val = val.divmod 3600
584
+ minute, val = val.divmod 60
585
+ sec, val = val.divmod 1
586
+ else
587
+ day, val = val.divmod 1
588
+ hour, val = (val * 24).divmod 1
589
+ minute, val = (val * 60).divmod 1
590
+ sec, val = (val * 60).divmod 1
591
+ end
592
+ fsec, val = (val * 1000000000).divmod 1
593
+ if is_minus
594
+ day = - day
595
+ hour = - hour
596
+ minute = - minute
597
+ sec = - sec
598
+ fsec = - fsec
599
+ end
600
+ val = [day, hour, minute, sec, fsec]
601
+ end
602
+ super(val)
603
+ end
604
+
605
+ def get() # :nodoc:
606
+ val = super()
607
+ return nil if val.nil?
608
+ day, hour, minute, sec, fsec = val
609
+ if @@unit == :second
610
+ fsec = fsec / 1000000000.0
611
+ day * 86400 + hour * 3600 + minute * 60 + sec + fsec
612
+ else
613
+ day + (hour * @@hour) + (minute * @@minute) + (sec * @@sec) + (fsec * @@fsec)
614
+ end
615
+ end
616
+ end # OCI8::BindType::IntervalDS
617
+ end
618
+ end # OCI8::BindType
619
+ end # OCI8