ruby-oci8 1.0.7-x86-mswin32-60 → 2.0.1-x86-mswin32-60

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 (58) hide show
  1. data/ChangeLog +1289 -383
  2. data/Makefile +48 -12
  3. data/NEWS +5 -419
  4. data/README +56 -385
  5. data/VERSION +1 -1
  6. data/dist-files +27 -27
  7. data/lib/.document +2 -0
  8. data/lib/dbd/OCI8.rb +2 -17
  9. data/lib/oci8.rb +48 -1622
  10. data/lib/oci8.rb.in +48 -1622
  11. data/lib/oci8/.document +5 -0
  12. data/lib/oci8/compat.rb +108 -0
  13. data/lib/oci8/datetime.rb +491 -0
  14. data/lib/oci8/encoding-init.rb +40 -0
  15. data/lib/oci8/encoding.yml +537 -0
  16. data/lib/oci8/metadata.rb +2077 -0
  17. data/lib/oci8/object.rb +548 -0
  18. data/lib/oci8/oci8.rb +798 -0
  19. data/lib/oci8/oracle_version.rb +144 -0
  20. data/lib/oci8lib_18.so +0 -0
  21. data/lib/oci8lib_191.so +0 -0
  22. data/metaconfig +3 -3
  23. data/ruby-oci8.gemspec +24 -15
  24. data/setup.rb +4 -4
  25. data/test/config.rb +64 -84
  26. data/test/test_all.rb +14 -21
  27. data/test/test_array_dml.rb +333 -0
  28. data/test/test_bind_raw.rb +18 -25
  29. data/test/test_bind_time.rb +78 -91
  30. data/test/test_break.rb +37 -35
  31. data/test/test_clob.rb +33 -89
  32. data/test/test_connstr.rb +5 -4
  33. data/test/test_datetime.rb +469 -0
  34. data/test/test_dbi.rb +99 -60
  35. data/test/test_dbi_clob.rb +3 -8
  36. data/test/test_metadata.rb +65 -51
  37. data/test/test_oci8.rb +151 -55
  38. data/test/test_oracle_version.rb +70 -0
  39. data/test/test_oradate.rb +76 -83
  40. data/test/test_oranumber.rb +405 -71
  41. data/test/test_rowid.rb +6 -11
  42. metadata +21 -25
  43. data/ext/oci8/oci8lib.so +0 -0
  44. data/ruby-oci8.spec +0 -62
  45. data/support/README +0 -4
  46. data/support/runit/assert.rb +0 -281
  47. data/support/runit/cui/testrunner.rb +0 -101
  48. data/support/runit/error.rb +0 -4
  49. data/support/runit/method_mappable.rb +0 -20
  50. data/support/runit/robserver.rb +0 -25
  51. data/support/runit/setuppable.rb +0 -15
  52. data/support/runit/teardownable.rb +0 -16
  53. data/support/runit/testcase.rb +0 -113
  54. data/support/runit/testfailure.rb +0 -25
  55. data/support/runit/testresult.rb +0 -121
  56. data/support/runit/testsuite.rb +0 -43
  57. data/support/runit/version.rb +0 -3
  58. data/test/test_describe.rb +0 -137
@@ -0,0 +1,5 @@
1
+ oci8.rb
2
+ object.rb
3
+ metadata.rb
4
+ oracle_version.rb
5
+
@@ -0,0 +1,108 @@
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
+ end
@@ -0,0 +1,491 @@
1
+ require 'date'
2
+
3
+ class OCI8
4
+
5
+ module BindType
6
+
7
+ module Util # :nodoc:
8
+
9
+ @@datetime_fsec_base = (1 / ::DateTime.parse('0001-01-01 00:00:00.000000001').sec_fraction).to_i
10
+ @@time_offset = ::Time.now.utc_offset
11
+ @@datetime_offset = ::DateTime.now.offset
12
+
13
+ @@default_timezone = :local
14
+ def self.default_timezone
15
+ @@default_timezone
16
+ end
17
+
18
+ # Determines default timezone of Time and DateTime retrived from Oracle.
19
+ # This accepts :local or :utc. The default is :local.
20
+ #
21
+ # This parameter is used when both or either of Oracle server and client
22
+ # version is Oracle 8i or lower. If both versions are Oracle 9i or upper,
23
+ # the default timezone is determined by the session timezone.
24
+ def self.default_timezone=(tz)
25
+ if tz != :local and tz != :utc
26
+ raise ArgumentError, "expected :local or :utc but #{tz}"
27
+ end
28
+ @@default_timezone = tz
29
+ end
30
+
31
+ private
32
+
33
+ def datetime_to_array(val, full)
34
+ # year
35
+ year = val.year
36
+ # month
37
+ if val.respond_to? :mon
38
+ month = val.mon
39
+ elsif val.respond_to? :month
40
+ month = val.month
41
+ else
42
+ raise "expect Time, Date or DateTime but #{val.class}"
43
+ end
44
+ # day
45
+ if val.respond_to? :mday
46
+ day = val.mday
47
+ elsif val.respond_to? :day
48
+ day = val.day
49
+ else
50
+ raise "expect Time, Date or DateTime but #{val.class}"
51
+ end
52
+ # hour
53
+ if val.respond_to? :hour
54
+ hour = val.hour
55
+ else
56
+ hour = 0
57
+ end
58
+ # minute
59
+ if val.respond_to? :min
60
+ minute = val.min
61
+ else
62
+ minute = 0
63
+ end
64
+ # second
65
+ if val.respond_to? :sec
66
+ sec = val.sec
67
+ else
68
+ sec = 0
69
+ end
70
+ return [year, month, day, hour, minute, sec] unless full
71
+
72
+ # sec_fraction
73
+ if val.respond_to? :sec_fraction
74
+ fsec = (val.sec_fraction * @@datetime_fsec_base).to_i
75
+ else
76
+ fsec = 0
77
+ end
78
+ # time zone
79
+ if val.respond_to? :offset
80
+ # DateTime
81
+ tz_min = (val.offset * 1440).to_i
82
+ elsif val.respond_to? :utc_offset
83
+ # Time
84
+ tz_min = val.utc_offset / 60
85
+ else
86
+ tz_hour = nil
87
+ tz_min = nil
88
+ end
89
+ if tz_min
90
+ if tz_min < 0
91
+ tz_min = - tz_min
92
+ tz_hour = - (tz_min / 60)
93
+ tz_min = (tz_min % 60)
94
+ else
95
+ tz_hour = tz_min / 60
96
+ tz_min = tz_min % 60
97
+ end
98
+ end
99
+ [year, month, day, hour, minute, sec, fsec, tz_hour, tz_min]
100
+ end
101
+
102
+ def ocidate_to_datetime(ary)
103
+ year, month, day, hour, minute, sec = ary
104
+ if @@default_timezone == :local
105
+ offset = @@datetime_offset
106
+ else
107
+ offset = 0
108
+ end
109
+ ::DateTime.civil(year, month, day, hour, minute, sec, offset)
110
+ end
111
+
112
+ def ocidate_to_time(ary)
113
+ year, month, day, hour, minute, sec = ary
114
+ if year >= 139
115
+ begin
116
+ return ::Time.send(@@default_timezone, year, month, day, hour, minute, sec)
117
+ rescue StandardError
118
+ end
119
+ end
120
+ ocidate_to_datetime(ary)
121
+ end
122
+
123
+ if OCI8.oracle_client_version >= ORAVER_9_0
124
+
125
+ def ocitimestamp_to_datetime(ary)
126
+ year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
127
+ if sec >= 59 and fsec != 0
128
+ # convert to a DateTime via a String as a last resort.
129
+ if tz_hour >= 0 && tz_min >= 0
130
+ sign = ?+
131
+ else
132
+ sign = ?-
133
+ tz_hour = - tz_hour
134
+ tz_min = - tz_min
135
+ end
136
+ time_str = format("%04d-%02d-%02dT%02d:%02d:%02d.%09d%c%02d:%02d",
137
+ year, month, day, hour, minute, sec, fsec, sign, tz_hour, tz_min)
138
+ ::DateTime.parse(time_str)
139
+ else
140
+ sec += fsec.to_r / 1000000000
141
+ offset = tz_hour.to_r / 24 + tz_min.to_r / 1440
142
+ ::DateTime.civil(year, month, day, hour, minute, sec, offset)
143
+ end
144
+ end
145
+
146
+ def ocitimestamp_to_time(ary)
147
+ year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
148
+
149
+ if tz_hour == 0 and tz_min == 0
150
+ timezone = :utc
151
+ elsif @@time_offset == tz_hour * 3600 + tz_min * 60
152
+ timezone = :local
153
+ end
154
+ if timezone and year >= 139
155
+ begin
156
+ # Ruby 1.9 Time class's resolution is nanosecond.
157
+ # But the last argument type is millisecond.
158
+ # 'fsec' is converted to a Float to pass sub-millisecond part.
159
+ return ::Time.send(timezone, year, month, day, hour, minute, sec, fsec / 1000.0)
160
+ rescue StandardError
161
+ end
162
+ end
163
+ ocitimestamp_to_datetime(ary)
164
+ end
165
+ end
166
+ end
167
+
168
+ class DateTimeViaOCIDate < OCI8::BindType::OCIDate
169
+ include OCI8::BindType::Util
170
+
171
+ def set(val) # :nodoc:
172
+ val &&= datetime_to_array(val, false)
173
+ super(val)
174
+ end
175
+
176
+ def get() # :nodoc:
177
+ val = super()
178
+ val ? ocidate_to_datetime(val) : nil
179
+ end
180
+ end
181
+
182
+ class TimeViaOCIDate < OCI8::BindType::OCIDate
183
+ include OCI8::BindType::Util
184
+
185
+ def set(val) # :nodoc:
186
+ val &&= datetime_to_array(val, false)
187
+ super(val)
188
+ end
189
+
190
+ def get() # :nodoc:
191
+ val = super()
192
+ val ? ocidate_to_time(val) : nil
193
+ end
194
+ end
195
+
196
+ if OCI8.oracle_client_version >= ORAVER_9_0
197
+ class DateTimeViaOCITimestamp < OCI8::BindType::OCITimestamp
198
+ include OCI8::BindType::Util
199
+
200
+ def set(val) # :nodoc:
201
+ val &&= datetime_to_array(val, true)
202
+ super(val)
203
+ end
204
+
205
+ def get() # :nodoc:
206
+ val = super()
207
+ val ? ocitimestamp_to_datetime(val) : nil
208
+ end
209
+ end
210
+
211
+ class TimeViaOCITimestamp < OCI8::BindType::OCITimestamp
212
+ include OCI8::BindType::Util
213
+
214
+ def set(val) # :nodoc:
215
+ val &&= datetime_to_array(val, true)
216
+ super(val)
217
+ end
218
+
219
+ def get() # :nodoc:
220
+ val = super()
221
+ val ? ocitimestamp_to_time(val) : nil
222
+ end
223
+ end
224
+ end
225
+
226
+
227
+ #--
228
+ # OCI8::BindType::DateTime
229
+ #++
230
+ # This is a helper class to bind ruby's
231
+ # DateTime[http://www.ruby-doc.org/core/classes/DateTime.html]
232
+ # object as Oracle's <tt>TIMESTAMP WITH TIME ZONE</tt> datatype.
233
+ #
234
+ # == Select
235
+ #
236
+ # The fetched value for a <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH
237
+ # TIME ZONE</tt> or <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt> column
238
+ # is a DateTime[http://www.ruby-doc.org/core/classes/DateTime.html].
239
+ # The time zone part is a session time zone if the Oracle datatype doesn't
240
+ # have time zone information. The session time zone is the client machine's
241
+ # time zone by default.
242
+ #
243
+ # You can change the session time zone by executing the following SQL.
244
+ #
245
+ # ALTER SESSION SET TIME_ZONE='-05:00'
246
+ #
247
+ # == Bind
248
+ #
249
+ # To bind a DateTime[http://www.ruby-doc.org/core/classes/DateTime.html]
250
+ # value implicitly:
251
+ #
252
+ # conn.exec("INSERT INTO lunar_landings(ship_name, landing_time) VALUES(:1, :2)",
253
+ # 'Apollo 11',
254
+ # DateTime.parse('1969-7-20 20:17:40 00:00'))
255
+ #
256
+ # The bind variable <code>:2</code> is bound as <tt>TIMESTAMP WITH TIME ZONE</tt> on Oracle.
257
+ #
258
+ # To bind explicitly:
259
+ #
260
+ # cursor = conn.exec("INSERT INTO lunar_landings(ship_name, landing_time) VALUES(:1, :2)")
261
+ # cursor.bind_param(':1', nil, String, 60)
262
+ # cursor.bind_param(':2', nil, DateTime)
263
+ # [['Apollo 11', DateTime.parse('1969-07-20 20:17:40 00:00'))],
264
+ # ['Apollo 12', DateTime.parse('1969-11-19 06:54:35 00:00'))],
265
+ # ['Apollo 14', DateTime.parse('1971-02-05 09:18:11 00:00'))],
266
+ # ['Apollo 15', DateTime.parse('1971-07-30 22:16:29 00:00'))],
267
+ # ['Apollo 16', DateTime.parse('1972-04-21 02:23:35 00:00'))],
268
+ # ['Apollo 17', DateTime.parse('1972-12-11 19:54:57 00:00'))]
269
+ # ].each do |ship_name, landing_time|
270
+ # cursor[':1'] = ship_name
271
+ # cursor[':2'] = landing_time
272
+ # cursor.exec
273
+ # end
274
+ # cursor.close
275
+ #
276
+ # On setting a object to the bind variable, you can use any object
277
+ # which has at least three instance methods _year_, _mon_ (or _month_)
278
+ # and _mday_ (or _day_). If the object responses to _hour_, _min_,
279
+ # _sec_ or _sec_fraction_, the responsed values are used for hour,
280
+ # minute, second or fraction of a second respectively.
281
+ # If not, zeros are set. If the object responses to _offset_ or
282
+ # _utc_offset_, it is used for time zone. If not, the session time
283
+ # zone is used.
284
+ #
285
+ # The acceptable value are listed below.
286
+ # _year_:: -4712 to 9999 [excluding year 0]
287
+ # _mon_ (or _month_):: 0 to 12
288
+ # _mday_ (or _day_):: 0 to 31 [depends on the month]
289
+ # _hour_:: 0 to 23
290
+ # _min_:: 0 to 59
291
+ # _sec_:: 0 to 59
292
+ # _sec_fraction_:: 0 to (999_999_999.to_r / (24*60*60* 1_000_000_000)) [999,999,999 nanoseconds]
293
+ # _offset_:: (-12.to_r / 24) to (14.to_r / 24) [-12:00 to +14:00]
294
+ # _utc_offset_:: -12*3600 <= utc_offset <= 24*3600 [-12:00 to +14:00]
295
+ #
296
+ # The output value of the bind varible is always a
297
+ # DateTime[http://www.ruby-doc.org/core/classes/DateTime.html].
298
+ #
299
+ # cursor = conn.exec("BEGIN :ts := current_timestamp; END")
300
+ # cursor.bind_param(:ts, nil, DateTime)
301
+ # cursor.exec
302
+ # cursor[:ts] # => a DateTime.
303
+ # cursor.close
304
+ #
305
+ class DateTime
306
+ if OCI8.oracle_client_version >= ORAVER_9_0
307
+ def self.create(con, val, param, max_array_size)
308
+ if true # TODO: check Oracle server version
309
+ DateTimeViaOCITimestamp.new(con, val, param, max_array_size)
310
+ else
311
+ DateTimeViaOCIDate.new(con, val, param, max_array_size)
312
+ end
313
+ end
314
+ else
315
+ def self.create(con, val, param, max_array_size)
316
+ DateTimeViaOCIDate.new(con, val, param, max_array_size)
317
+ end
318
+ end
319
+ end
320
+
321
+ class Time
322
+ if OCI8.oracle_client_version >= ORAVER_9_0
323
+ def self.create(con, val, param, max_array_size)
324
+ if true # TODO: check Oracle server version
325
+ TimeViaOCITimestamp.new(con, val, param, max_array_size)
326
+ else
327
+ TimeViaOCIDate.new(con, val, param, max_array_size)
328
+ end
329
+ end
330
+ else
331
+ def self.create(con, val, param, max_array_size)
332
+ TimeViaOCIDate.new(con, val, param, max_array_size)
333
+ end
334
+ end
335
+ end
336
+
337
+ if OCI8.oracle_client_version >= ORAVER_9_0
338
+ #--
339
+ # OCI8::BindType::IntervalYM
340
+ #++
341
+ #
342
+ # This is a helper class to bind ruby's
343
+ # Integer[http://www.ruby-doc.org/core/classes/Integer.html]
344
+ # object as Oracle's <tt>INTERVAL YEAR TO MONTH</tt> datatype.
345
+ #
346
+ # == Select
347
+ #
348
+ # The fetched value for a <tt>INTERVAL YEAR TO MONTH</tt> column
349
+ # is an Integer[http://www.ruby-doc.org/core/classes/Integer.html]
350
+ # which means the months between two timestamps.
351
+ #
352
+ # == Bind
353
+ #
354
+ # You cannot bind as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
355
+ # It must be bound explicitly with :interval_ym.
356
+ #
357
+ # # output bind variable
358
+ # cursor = conn.parse(<<-EOS)
359
+ # BEGIN
360
+ # :interval := (:ts1 - :ts2) YEAR TO MONTH;
361
+ # END;
362
+ # EOS
363
+ # cursor.bind_param(:interval, nil, :interval_ym)
364
+ # cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
365
+ # cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
366
+ # cursor.exec
367
+ # cursor[:interval] # => 4 (months)
368
+ # cursor.close
369
+ #
370
+ # # input bind variable
371
+ # cursor = conn.parse(<<-EOS)
372
+ # BEGIN
373
+ # :ts1 := :ts2 + :interval;
374
+ # END;
375
+ # EOS
376
+ # cursor.bind_param(:ts1, nil, DateTime)
377
+ # cursor.bind_param(:ts2, Date.parse('1969-11-19'))
378
+ # cursor.bind_param(:interval, 4, :interval_ym)
379
+ # cursor.exec
380
+ # cursor[:ts1].strftime('%Y-%m-%d') # => 1970-03-19
381
+ # cursor.close
382
+ #
383
+ class IntervalYM < OCI8::BindType::OCIIntervalYM
384
+ def set(val) # :nodoc:
385
+ unless val.nil?
386
+ val = [val / 12, val % 12]
387
+ end
388
+ super(val)
389
+ end
390
+ def get() # :nodoc:
391
+ val = super()
392
+ return nil if val.nil?
393
+ year, month = val
394
+ year * 12 + month
395
+ end
396
+ end # OCI8::BindType::IntervalYM
397
+
398
+ #--
399
+ # OCI8::BindType::IntervalDS
400
+ #++
401
+ #
402
+ # This is a helper class to bind ruby's
403
+ # Rational[http://www.ruby-doc.org/core/classes/Rational.html]
404
+ # object as Oracle's <tt>INTERVAL DAY TO SECOND</tt> datatype.
405
+ #
406
+ # == Select
407
+ #
408
+ # The fetched value for a <tt>INTERVAL DAY TO SECOND</tt> column
409
+ # is a Rational[http://www.ruby-doc.org/core/classes/Rational.html]
410
+ # or an Integer[http://www.ruby-doc.org/core/classes/Integer.html].
411
+ # The value is usable to apply to
412
+ # DateTime[http://www.ruby-doc.org/core/classes/DateTime.html]#+ and
413
+ # DateTime[http://www.ruby-doc.org/core/classes/DateTime.html]#-.
414
+ #
415
+ # == Bind
416
+ #
417
+ # You cannot bind as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
418
+ # It must be bound explicitly with :interval_ds.
419
+ #
420
+ # # output
421
+ # ts1 = DateTime.parse('1969-11-19 06:54:35 00:00')
422
+ # ts2 = DateTime.parse('1969-07-20 20:17:40 00:00')
423
+ # cursor = conn.parse(<<-EOS)
424
+ # BEGIN
425
+ # :itv := (:ts1 - :ts2) DAY TO SECOND;
426
+ # END;
427
+ # EOS
428
+ # cursor.bind_param(:itv, nil, :interval_ds)
429
+ # cursor.bind_param(:ts1, ts1)
430
+ # cursor.bind_param(:ts2, ts2)
431
+ # cursor.exec
432
+ # cursor[:itv] # == ts1 - ts2
433
+ # cursor.close
434
+ #
435
+ # # input
436
+ # ts2 = DateTime.parse('1969-07-20 20:17:40 00:00')
437
+ # itv = 121 + 10.to_r/24 + 36.to_r/(24*60) + 55.to_r/(24*60*60)
438
+ # # 121 days, 10 hours, 36 minutes, 55 seconds
439
+ # cursor = conn.parse(<<-EOS)
440
+ # BEGIN
441
+ # :ts1 := :ts2 + :itv;
442
+ # END;
443
+ # EOS
444
+ # cursor.bind_param(:ts1, nil, DateTime)
445
+ # cursor.bind_param(:ts2, ts2)
446
+ # cursor.bind_param(:itv, itv, :interval_ds)
447
+ # cursor.exec
448
+ # cursor[:ts1].strftime('%Y-%m-%d %H:%M:%S') # => 1969-11-19 06:54:35
449
+ # cursor.close
450
+ #
451
+ class IntervalDS < OCI8::BindType::OCIIntervalDS
452
+ @@hour = 1 / 24.to_r
453
+ @@minute = @@hour / 60
454
+ @@sec = @@minute / 60
455
+ @@fsec = @@sec / 1000000000
456
+
457
+ def set(val) # :nodoc:
458
+ unless val.nil?
459
+ if val < 0
460
+ is_minus = true
461
+ val = -val
462
+ else
463
+ is_minus = false
464
+ end
465
+ day, val = val.divmod 1
466
+ hour, val = (val * 24).divmod 1
467
+ minute, val = (val * 60).divmod 1
468
+ sec, val = (val * 60).divmod 1
469
+ fsec, val = (val * 1000000000).divmod 1
470
+ if is_minus
471
+ day = - day
472
+ hour = - hour
473
+ minute = - minute
474
+ sec = - sec
475
+ fsec = - fsec
476
+ end
477
+ val = [day, hour, minute, sec, fsec]
478
+ end
479
+ super(val)
480
+ end
481
+
482
+ def get() # :nodoc:
483
+ val = super()
484
+ return nil if val.nil?
485
+ day, hour, minute, sec, fsec = val
486
+ day + (hour * @@hour) + (minute * @@minute) + (sec * @@sec) + (fsec * @@fsec)
487
+ end
488
+ end # OCI8::BindType::IntervalDS
489
+ end
490
+ end # OCI8::BindType
491
+ end # OCI8