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.
- data/ChangeLog +1912 -0
- data/Makefile +96 -0
- data/NEWS +223 -0
- data/README +86 -0
- data/VERSION +1 -0
- data/dist-files +77 -0
- data/doc/api.en.html +527 -0
- data/doc/api.en.rd +554 -0
- data/doc/api.ja.html +525 -0
- data/doc/api.ja.rd +557 -0
- data/doc/manual.css +35 -0
- data/lib/.document +1 -0
- data/lib/dbd/OCI8.rb +591 -0
- data/lib/oci8.rb +82 -0
- data/lib/oci8.rb.in +82 -0
- data/lib/oci8/.document +5 -0
- data/lib/oci8/bindtype.rb +319 -0
- data/lib/oci8/compat.rb +113 -0
- data/lib/oci8/datetime.rb +619 -0
- data/lib/oci8/encoding-init.rb +40 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2077 -0
- data/lib/oci8/object.rb +562 -0
- data/lib/oci8/oci8.rb +571 -0
- data/lib/oci8/oracle_version.rb +144 -0
- data/lib/oci8lib_18.so +0 -0
- data/lib/oci8lib_191.so +0 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-oci8.gemspec +63 -0
- data/setup.rb +1331 -0
- data/test/README +4 -0
- data/test/config.rb +109 -0
- data/test/test_all.rb +50 -0
- data/test/test_appinfo.rb +63 -0
- data/test/test_array_dml.rb +333 -0
- data/test/test_bind_raw.rb +46 -0
- data/test/test_bind_time.rb +178 -0
- data/test/test_break.rb +83 -0
- data/test/test_clob.rb +79 -0
- data/test/test_connstr.rb +81 -0
- data/test/test_datetime.rb +622 -0
- data/test/test_dbi.rb +366 -0
- data/test/test_dbi_clob.rb +53 -0
- data/test/test_encoding.rb +100 -0
- data/test/test_metadata.rb +257 -0
- data/test/test_oci8.rb +434 -0
- data/test/test_oracle_version.rb +70 -0
- data/test/test_oradate.rb +256 -0
- data/test/test_oranumber.rb +655 -0
- data/test/test_rowid.rb +33 -0
- metadata +108 -0
data/lib/oci8/compat.rb
ADDED
@@ -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
|