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