ruby-oci8 2.0.2 → 2.0.3
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 +121 -0
- data/Makefile +11 -4
- data/NEWS +126 -0
- data/VERSION +1 -1
- data/ext/oci8/.document +16 -1
- data/ext/oci8/apiwrap.yml +9 -0
- data/ext/oci8/attr.c +1 -1
- data/ext/oci8/bind.c +1 -38
- data/ext/oci8/extconf.rb +8 -9
- data/ext/oci8/lob.c +5 -3
- data/ext/oci8/object.c +12 -0
- data/ext/oci8/oci8.c +403 -115
- data/ext/oci8/oci8.h +4 -0
- data/ext/oci8/oci8lib.c +10 -1
- data/ext/oci8/ocidatetime.c +47 -5
- data/ext/oci8/ocinumber.c +254 -47
- data/ext/oci8/oraconf.rb +40 -11
- data/ext/oci8/oradate.c +1 -1
- data/lib/.document +0 -1
- data/lib/oci8.rb.in +1 -1
- data/lib/oci8/.document +2 -2
- data/lib/oci8/bindtype.rb +32 -8
- data/lib/oci8/compat.rb +5 -0
- data/lib/oci8/datetime.rb +284 -160
- data/lib/oci8/object.rb +18 -4
- data/lib/oci8/oci8.rb +24 -4
- data/test/test_appinfo.rb +34 -0
- data/test/test_clob.rb +13 -0
- data/test/test_datetime.rb +160 -7
- data/test/test_oci8.rb +31 -3
- data/test/test_oranumber.rb +12 -7
- metadata +3 -3
data/ext/oci8/oraconf.rb
CHANGED
@@ -353,8 +353,10 @@ EOS
|
|
353
353
|
end
|
354
354
|
print <<EOS
|
355
355
|
---------------------------------------------------
|
356
|
-
|
357
|
-
#{$!.to_s}
|
356
|
+
Error Message:
|
357
|
+
#{$!.to_s.gsub(/\n/, "\n ")}
|
358
|
+
Backtrace:
|
359
|
+
#{$!.backtrace.join("\n ")}
|
358
360
|
---------------------------------------------------
|
359
361
|
See:
|
360
362
|
* http://ruby-oci8.rubyforge.org/#{lang}/HowToInstall.html
|
@@ -383,15 +385,16 @@ EOS
|
|
383
385
|
# get library load path names
|
384
386
|
oci_basename = 'libclntsh'
|
385
387
|
oci_glob_postfix = '.[0-9]*'
|
386
|
-
|
388
|
+
nls_data_basename = ['libociei', 'libociicus']
|
387
389
|
@@ld_envs = %w[LD_LIBRARY_PATH]
|
388
390
|
so_ext = 'so'
|
391
|
+
nls_data_ext = nil
|
389
392
|
check_proc = nil
|
390
393
|
case RUBY_PLATFORM
|
391
394
|
when /mswin32|cygwin|mingw32|bccwin32/
|
392
395
|
oci_basename = 'oci'
|
393
396
|
oci_glob_postfix = ''
|
394
|
-
|
397
|
+
nls_data_basename = ['oraociei11', 'oraociicus11', 'oraociei10', 'oraociicus10']
|
395
398
|
@@ld_envs = %w[PATH]
|
396
399
|
so_ext = 'dll'
|
397
400
|
when /i.86-linux/
|
@@ -434,6 +437,7 @@ EOS
|
|
434
437
|
oci_glob_postfix = ''
|
435
438
|
@@ld_envs = %w[LIBPATH]
|
436
439
|
so_ext = 'a'
|
440
|
+
nls_data_ext = 'so'
|
437
441
|
when /hppa.*-hpux/
|
438
442
|
if [0].pack('l!').length == 4
|
439
443
|
@@ld_envs = %w[SHLIB_PATH]
|
@@ -529,8 +533,9 @@ EOS
|
|
529
533
|
end
|
530
534
|
|
531
535
|
if ld_path
|
532
|
-
|
533
|
-
|
536
|
+
nls_data_ext ||= so_ext # nls_data_ext is same with so_ext by default.
|
537
|
+
nls_data_basename.each do |basename|
|
538
|
+
if File.exist?(File.join(ld_path, "#{basename}.#{nls_data_ext}"))
|
534
539
|
puts " #{file} looks like an instant client."
|
535
540
|
return ld_path
|
536
541
|
end
|
@@ -613,6 +618,7 @@ You need /usr/include/sys/types.h to compile ruby-oci8.
|
|
613
618
|
EOS
|
614
619
|
end
|
615
620
|
puts "ok"
|
621
|
+
$stdout.flush
|
616
622
|
end # check_ruby_header
|
617
623
|
|
618
624
|
def try_link_oci
|
@@ -860,10 +866,33 @@ EOS
|
|
860
866
|
def get_home
|
861
867
|
oracle_home = ENV['ORACLE_HOME']
|
862
868
|
if oracle_home.nil?
|
863
|
-
|
869
|
+
msg = <<EOS
|
864
870
|
Set the environment variable ORACLE_HOME if Oracle Full Client.
|
865
871
|
Append the path of Oracle client libraries to #{OraConf.ld_envs[0]} if Oracle Instant Client.
|
866
872
|
EOS
|
873
|
+
|
874
|
+
# check sudo environment
|
875
|
+
sudo_command = ENV['SUDO_COMMAND']
|
876
|
+
if /\w*make\b/ =~ sudo_command
|
877
|
+
msg += <<EOS
|
878
|
+
|
879
|
+
The 'sudo' command unset some environment variables for security reasons.
|
880
|
+
Use it only when running 'make install' as follows
|
881
|
+
make
|
882
|
+
sudo make install
|
883
|
+
EOS
|
884
|
+
end
|
885
|
+
if /\w+\/gem\b/ =~ sudo_command
|
886
|
+
msg += <<EOS
|
887
|
+
|
888
|
+
The 'sudo' command unset some environment variables for security reasons.
|
889
|
+
Pass required varialbes as follows
|
890
|
+
sudo env #{OraConf.ld_envs[0]}=$#{OraConf.ld_envs[0]} #{sudo_command}
|
891
|
+
or
|
892
|
+
sudo env ORACLE_HOME=$ORACLE_HOME #{sudo_command}
|
893
|
+
EOS
|
894
|
+
end
|
895
|
+
raise msg
|
867
896
|
end
|
868
897
|
oracle_home
|
869
898
|
end
|
@@ -953,10 +982,10 @@ EOS
|
|
953
982
|
|
954
983
|
# monkey patching!
|
955
984
|
Object.module_eval do
|
956
|
-
alias :
|
957
|
-
def link_command(
|
958
|
-
|
959
|
-
|
985
|
+
alias :link_command_pre_oci8 :link_command
|
986
|
+
def link_command(*args)
|
987
|
+
args[1] = "" if args[1] == $libs
|
988
|
+
link_command_pre_oci8(*args)
|
960
989
|
end
|
961
990
|
end
|
962
991
|
|
data/ext/oci8/oradate.c
CHANGED
data/lib/.document
CHANGED
data/lib/oci8.rb.in
CHANGED
data/lib/oci8/.document
CHANGED
data/lib/oci8/bindtype.rb
CHANGED
@@ -24,6 +24,28 @@ class OCI8
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
class BigDecimal < OCI8::BindType::OraNumber
|
28
|
+
@@bigdecimal_is_required = false
|
29
|
+
def get()
|
30
|
+
unless @@bigdecimal_is_required
|
31
|
+
require 'bigdecimal'
|
32
|
+
@@bigdecimal_is_required = true
|
33
|
+
end
|
34
|
+
(val = super()) && val.to_d
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Rational < OCI8::BindType::OraNumber
|
39
|
+
@@rational_is_required = false
|
40
|
+
def get()
|
41
|
+
unless @@rational_is_required
|
42
|
+
require 'rational'
|
43
|
+
@@rational_is_required = true
|
44
|
+
end
|
45
|
+
(val = super()) && val.to_r
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
27
49
|
# get/set Number (for OCI8::SQLT_NUM)
|
28
50
|
class Number
|
29
51
|
def self.create(con, val, param, max_array_size)
|
@@ -54,8 +76,8 @@ class OCI8
|
|
54
76
|
if precision < 15 # the precision of double.
|
55
77
|
klass = OCI8::BindType::Float
|
56
78
|
else
|
57
|
-
# use BigDecimal instead
|
58
|
-
klass = OCI8::BindType::
|
79
|
+
# use BigDecimal instead
|
80
|
+
klass = OCI8::BindType::BigDecimal
|
59
81
|
end
|
60
82
|
end
|
61
83
|
klass.new(con, val, nil, max_array_size)
|
@@ -156,6 +178,8 @@ end
|
|
156
178
|
# bind or explicitly define
|
157
179
|
OCI8::BindType::Mapping[String] = OCI8::BindType::String
|
158
180
|
OCI8::BindType::Mapping[OraNumber] = OCI8::BindType::OraNumber
|
181
|
+
OCI8::BindType::Mapping['BigDecimal'] = OCI8::BindType::BigDecimal
|
182
|
+
OCI8::BindType::Mapping['Rational'] = OCI8::BindType::Rational
|
159
183
|
OCI8::BindType::Mapping[Fixnum] = OCI8::BindType::Integer
|
160
184
|
OCI8::BindType::Mapping[Float] = OCI8::BindType::Float
|
161
185
|
OCI8::BindType::Mapping[Integer] = OCI8::BindType::Integer
|
@@ -263,9 +287,9 @@ OCI8::BindType::Mapping[:number] = OCI8::BindType::Number
|
|
263
287
|
# datatypes that have no explicit setting of their precision
|
264
288
|
# and scale.
|
265
289
|
#
|
266
|
-
# The default mapping is Float for ruby-oci8 1.0.
|
267
|
-
# for
|
268
|
-
OCI8::BindType::Mapping[:number_unknown_prec] = OCI8::BindType::
|
290
|
+
# The default mapping is Float for ruby-oci8 1.0, OraNumber for 2.0.0 ~ 2.0.2,
|
291
|
+
# BigDecimal for 2.0.3 ~.
|
292
|
+
OCI8::BindType::Mapping[:number_unknown_prec] = OCI8::BindType::BigDecimal
|
269
293
|
|
270
294
|
# mapping for number without precision and scale.
|
271
295
|
#
|
@@ -276,9 +300,9 @@ OCI8::BindType::Mapping[:number_unknown_prec] = OCI8::BindType::OraNumber
|
|
276
300
|
# note: This is available only on Oracle 9.2.0.3 or above.
|
277
301
|
# see: Oracle 9.2.0.x Patch Set Notes.
|
278
302
|
#
|
279
|
-
# The default mapping is Float for ruby-oci8 1.0.
|
280
|
-
# for
|
281
|
-
OCI8::BindType::Mapping[:number_no_prec_setting] = OCI8::BindType::
|
303
|
+
# The default mapping is Float for ruby-oci8 1.0, OraNumber for 2.0.0 ~ 2.0.2,
|
304
|
+
# BigDecimal for 2.0.3 ~.
|
305
|
+
OCI8::BindType::Mapping[:number_no_prec_setting] = OCI8::BindType::BigDecimal
|
282
306
|
|
283
307
|
if defined? OCI8::BindType::BinaryDouble
|
284
308
|
OCI8::BindType::Mapping[:binary_float] = OCI8::BindType::BinaryDouble
|
data/lib/oci8/compat.rb
CHANGED
data/lib/oci8/datetime.rb
CHANGED
@@ -4,23 +4,44 @@ class OCI8
|
|
4
4
|
|
5
5
|
module BindType
|
6
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
|
+
|
7
29
|
module Util # :nodoc:
|
8
30
|
|
9
31
|
@@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
32
|
|
13
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
|
+
|
14
41
|
def self.default_timezone
|
15
42
|
@@default_timezone
|
16
43
|
end
|
17
44
|
|
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
45
|
def self.default_timezone=(tz)
|
25
46
|
if tz != :local and tz != :utc
|
26
47
|
raise ArgumentError, "expected :local or :utc but #{tz}"
|
@@ -31,6 +52,8 @@ class OCI8
|
|
31
52
|
private
|
32
53
|
|
33
54
|
def datetime_to_array(val, full)
|
55
|
+
return nil if val.nil?
|
56
|
+
|
34
57
|
# year
|
35
58
|
year = val.year
|
36
59
|
# month
|
@@ -100,9 +123,16 @@ class OCI8
|
|
100
123
|
end
|
101
124
|
|
102
125
|
def ocidate_to_datetime(ary)
|
126
|
+
return nil if ary.nil?
|
127
|
+
|
103
128
|
year, month, day, hour, minute, sec = ary
|
104
129
|
if @@default_timezone == :local
|
105
|
-
|
130
|
+
if ::DateTime.respond_to? :local_offset
|
131
|
+
offset = ::DateTime.local_offset # Use a method defined by active support.
|
132
|
+
else
|
133
|
+
# Do as active support does.
|
134
|
+
offset = ::Time.local(2007).utc_offset.to_r / 86400
|
135
|
+
end
|
106
136
|
else
|
107
137
|
offset = 0
|
108
138
|
end
|
@@ -110,8 +140,10 @@ class OCI8
|
|
110
140
|
end
|
111
141
|
|
112
142
|
def ocidate_to_time(ary)
|
143
|
+
return nil if ary.nil?
|
144
|
+
|
113
145
|
year, month, day, hour, minute, sec = ary
|
114
|
-
if year >= 139
|
146
|
+
if @@time_new_accepts_timezone || year >= 139 || year < 0
|
115
147
|
begin
|
116
148
|
return ::Time.send(@@default_timezone, year, month, day, hour, minute, sec)
|
117
149
|
rescue StandardError
|
@@ -123,6 +155,8 @@ class OCI8
|
|
123
155
|
if OCI8.oracle_client_version >= ORAVER_9_0
|
124
156
|
|
125
157
|
def ocitimestamp_to_datetime(ary)
|
158
|
+
return nil if ary.nil?
|
159
|
+
|
126
160
|
year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
|
127
161
|
if sec >= 59 and fsec != 0
|
128
162
|
# convert to a DateTime via a String as a last resort.
|
@@ -143,168 +177,159 @@ class OCI8
|
|
143
177
|
end
|
144
178
|
end
|
145
179
|
|
146
|
-
|
147
|
-
|
180
|
+
if @@time_new_accepts_timezone
|
181
|
+
|
182
|
+
# after ruby 1.9.2
|
183
|
+
def ocitimestamp_to_time(ary)
|
184
|
+
return nil if ary.nil?
|
148
185
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
186
|
+
year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
|
187
|
+
|
188
|
+
sec += fsec / Rational(1000000000)
|
189
|
+
utc_offset = tz_hour * 3600 + tz_min * 60
|
190
|
+
return ::Time.new(year, month, day, hour, minute, sec, utc_offset)
|
153
191
|
end
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
192
|
+
|
193
|
+
else
|
194
|
+
|
195
|
+
# prior to ruby 1.9.2
|
196
|
+
def ocitimestamp_to_time(ary)
|
197
|
+
return nil if ary.nil?
|
198
|
+
|
199
|
+
year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
|
200
|
+
|
201
|
+
if year >= 139 || year < 0
|
202
|
+
begin
|
203
|
+
if tz_hour == 0 and tz_min == 0
|
204
|
+
return ::Time.utc(year, month, day, hour, minute, sec, fsec / Rational(1000))
|
205
|
+
else
|
206
|
+
tm = ::Time.local(year, month, day, hour, minute, sec, fsec / Rational(1000))
|
207
|
+
return tm if tm.utc_offset == tz_hour * 3600 + tz_min * 60
|
208
|
+
end
|
209
|
+
rescue StandardError
|
210
|
+
end
|
161
211
|
end
|
212
|
+
ocitimestamp_to_datetime(ary)
|
162
213
|
end
|
163
|
-
|
214
|
+
|
164
215
|
end
|
165
216
|
end
|
166
217
|
end
|
167
218
|
|
168
|
-
class DateTimeViaOCIDate < OCI8::BindType::OCIDate
|
219
|
+
class DateTimeViaOCIDate < OCI8::BindType::OCIDate # :nodoc:
|
169
220
|
include OCI8::BindType::Util
|
170
221
|
|
171
222
|
def set(val) # :nodoc:
|
172
|
-
|
173
|
-
super(val)
|
223
|
+
super(datetime_to_array(val, false))
|
174
224
|
end
|
175
225
|
|
176
226
|
def get() # :nodoc:
|
177
|
-
|
178
|
-
val ? ocidate_to_datetime(val) : nil
|
227
|
+
ocidate_to_datetime(super())
|
179
228
|
end
|
180
229
|
end
|
181
230
|
|
182
|
-
class TimeViaOCIDate < OCI8::BindType::OCIDate
|
231
|
+
class TimeViaOCIDate < OCI8::BindType::OCIDate # :nodoc:
|
183
232
|
include OCI8::BindType::Util
|
184
233
|
|
185
234
|
def set(val) # :nodoc:
|
186
|
-
|
187
|
-
super(val)
|
235
|
+
super(datetime_to_array(val, false))
|
188
236
|
end
|
189
237
|
|
190
238
|
def get() # :nodoc:
|
191
|
-
|
192
|
-
val ? ocidate_to_time(val) : nil
|
239
|
+
ocidate_to_time(super())
|
193
240
|
end
|
194
241
|
end
|
195
242
|
|
196
243
|
if OCI8.oracle_client_version >= ORAVER_9_0
|
197
|
-
class DateTimeViaOCITimestamp < OCI8::BindType::OCITimestamp
|
244
|
+
class DateTimeViaOCITimestamp < OCI8::BindType::OCITimestamp # :nodoc:
|
198
245
|
include OCI8::BindType::Util
|
199
246
|
|
200
247
|
def set(val) # :nodoc:
|
201
|
-
|
202
|
-
super(val)
|
248
|
+
super(datetime_to_array(val, true))
|
203
249
|
end
|
204
250
|
|
205
251
|
def get() # :nodoc:
|
206
|
-
|
207
|
-
val ? ocitimestamp_to_datetime(val) : nil
|
252
|
+
ocitimestamp_to_datetime(super())
|
208
253
|
end
|
209
254
|
end
|
210
255
|
|
211
|
-
class TimeViaOCITimestamp < OCI8::BindType::OCITimestamp
|
256
|
+
class TimeViaOCITimestamp < OCI8::BindType::OCITimestamp # :nodoc:
|
212
257
|
include OCI8::BindType::Util
|
213
258
|
|
214
259
|
def set(val) # :nodoc:
|
215
|
-
|
216
|
-
super(val)
|
260
|
+
super(datetime_to_array(val, true))
|
217
261
|
end
|
218
262
|
|
219
263
|
def get() # :nodoc:
|
220
|
-
|
221
|
-
val ? ocitimestamp_to_time(val) : nil
|
264
|
+
ocitimestamp_to_time(super())
|
222
265
|
end
|
223
266
|
end
|
224
267
|
end
|
225
268
|
|
226
|
-
|
227
269
|
#--
|
228
270
|
# OCI8::BindType::DateTime
|
229
271
|
#++
|
230
|
-
# This is a helper class to bind
|
231
|
-
#
|
232
|
-
#
|
272
|
+
# This is a helper class to select or bind Oracle data types such as
|
273
|
+
# <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
|
274
|
+
# and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt>. The retrieved value
|
275
|
+
# is a \DateTime.
|
276
|
+
#
|
277
|
+
# === How to select \DataTime values.
|
278
|
+
#
|
279
|
+
# <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
|
280
|
+
# and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt> are selected as a \Time
|
281
|
+
# by default. You change the behaviour by explicitly calling
|
282
|
+
# OCI8::Cursor#define as follows:
|
283
|
+
#
|
284
|
+
# cursor = conn.parse("SELECT hiredate FROM emp")
|
285
|
+
# cursor.define(1, nil, DateTime)
|
286
|
+
# cursor.exec()
|
287
|
+
#
|
288
|
+
# Otherwise, you can change the default mapping for all queries.
|
233
289
|
#
|
234
|
-
#
|
290
|
+
# # Changes the mapping for DATE
|
291
|
+
# OCI8::BindType::Mapping[OCI8::SQLT_DAT] = OCI8::BindType::DateTime
|
292
|
+
#
|
293
|
+
# # Changes the mapping for TIMESTAMP
|
294
|
+
# OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::DateTime
|
295
|
+
#
|
296
|
+
# # Changes the mapping for TIMESTAMP WITH TIME ZONE
|
297
|
+
# OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::DateTime
|
298
|
+
#
|
299
|
+
# # Changes the mapping for TIMESTAMP WITH LOCAL TIME ZONE
|
300
|
+
# OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::DateTime
|
235
301
|
#
|
236
|
-
#
|
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.
|
302
|
+
# === Note for default time zone
|
242
303
|
#
|
243
|
-
#
|
304
|
+
# The retrieved value's time zone is determined by the session time zone
|
305
|
+
# if its data type is <tt>DATE</tt>, <tt>TIMESTAMP</tt> or <tt>TIMESTAMP
|
306
|
+
# WITH LOCAL TIME ZONE</tt>.
|
307
|
+
#
|
308
|
+
# The session time zone is same with local machine's by default.
|
309
|
+
# It is changed by the following SQL.
|
244
310
|
#
|
245
311
|
# ALTER SESSION SET TIME_ZONE='-05:00'
|
246
312
|
#
|
247
|
-
#
|
248
|
-
#
|
249
|
-
#
|
250
|
-
#
|
251
|
-
#
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
255
|
-
#
|
256
|
-
#
|
257
|
-
#
|
258
|
-
#
|
259
|
-
#
|
260
|
-
#
|
261
|
-
#
|
262
|
-
#
|
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
|
313
|
+
# === Note for Oracle 8.x client
|
314
|
+
#
|
315
|
+
# Timestamp data types and session time zone are new features in
|
316
|
+
# Oracle 9i. This class is available only to fetch or bind <tt>DATE</tt>
|
317
|
+
# when using Oracle 8.x client.
|
318
|
+
#
|
319
|
+
# The retrieved value's time zone is determined not by the session
|
320
|
+
# time zone, but by the OCI8::BindType.default_timezone
|
321
|
+
# The time zone can be changed as follows:
|
322
|
+
#
|
323
|
+
# OCI8::BindType.default_timezone = :local
|
324
|
+
# # or
|
325
|
+
# OCI8::BindType.default_timezone = :utc
|
326
|
+
#
|
327
|
+
# If you are in the regions where daylight saving time is adopted,
|
328
|
+
# you should use OCI8::BindType::Time.
|
304
329
|
#
|
305
330
|
class DateTime
|
306
331
|
if OCI8.oracle_client_version >= ORAVER_9_0
|
307
|
-
def self.create(con, val, param, max_array_size)
|
332
|
+
def self.create(con, val, param, max_array_size) # :nodoc:
|
308
333
|
if true # TODO: check Oracle server version
|
309
334
|
DateTimeViaOCITimestamp.new(con, val, param, max_array_size)
|
310
335
|
else
|
@@ -312,15 +337,78 @@ class OCI8
|
|
312
337
|
end
|
313
338
|
end
|
314
339
|
else
|
315
|
-
def self.create(con, val, param, max_array_size)
|
340
|
+
def self.create(con, val, param, max_array_size) # :nodoc:
|
316
341
|
DateTimeViaOCIDate.new(con, val, param, max_array_size)
|
317
342
|
end
|
318
343
|
end
|
319
344
|
end
|
320
345
|
|
346
|
+
#--
|
347
|
+
# OCI8::BindType::Time
|
348
|
+
#++
|
349
|
+
# This is a helper class to select or bind Oracle data types such as
|
350
|
+
# <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
|
351
|
+
# and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt>. The retrieved value
|
352
|
+
# is a \Time.
|
353
|
+
#
|
354
|
+
# === How to select \Time values.
|
355
|
+
#
|
356
|
+
# <tt>DATE</tt>, <tt>TIMESTAMP</tt>, <tt>TIMESTAMP WITH TIME ZONE</tt>
|
357
|
+
# and <tt>TIMESTAMP WITH LOCAL TIME ZONE</tt> are selected as a \Time
|
358
|
+
# by default. If the default behaviour is changed, you can select it
|
359
|
+
# as a \Time by explicitly calling OCI8::Cursor#define as follows:
|
360
|
+
#
|
361
|
+
# cursor = conn.parse("SELECT hiredate FROM emp")
|
362
|
+
# cursor.define(1, nil, Time)
|
363
|
+
# cursor.exec()
|
364
|
+
#
|
365
|
+
# === Note for ruby prior to 1.9.2
|
366
|
+
#
|
367
|
+
# If the retrieved value cannot be represented by \Time, it become
|
368
|
+
# a \DateTime. The fallback is done only when the ruby is before 1.9.2
|
369
|
+
# and one of the following conditions are met.
|
370
|
+
# - The timezone part is neither local nor utc.
|
371
|
+
# - The time is out of the time_t[http://en.wikipedia.org/wiki/Time_t].
|
372
|
+
#
|
373
|
+
# If the retrieved value has the precision of fractional second more
|
374
|
+
# than 6, the fractional second is truncated to microsecond, which
|
375
|
+
# is the precision of standard \Time class.
|
376
|
+
#
|
377
|
+
# To avoid this fractional second truncation:
|
378
|
+
# - Upgrade to ruby 1.9.2, whose \Time precision is nanosecond.
|
379
|
+
# - Otherwise, change the defalt mapping to use \DateTime as follows.
|
380
|
+
# OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::DateTime
|
381
|
+
# OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::DateTime
|
382
|
+
# OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::DateTime
|
383
|
+
#
|
384
|
+
# === Note for default time zone
|
385
|
+
#
|
386
|
+
# The retrieved value's time zone is determined by the session time zone
|
387
|
+
# if its data type is <tt>DATE</tt>, <tt>TIMESTAMP</tt> or <tt>TIMESTAMP
|
388
|
+
# WITH LOCAL TIME ZONE</tt>.
|
389
|
+
#
|
390
|
+
# The session time zone is same with local machine's by default.
|
391
|
+
# It is changed by the following SQL.
|
392
|
+
#
|
393
|
+
# ALTER SESSION SET TIME_ZONE='-05:00'
|
394
|
+
#
|
395
|
+
# === Note for Oracle 8.x client
|
396
|
+
#
|
397
|
+
# Timestamp data types and session time zone are new features in
|
398
|
+
# Oracle 9i. This class is available only to fetch or bind <tt>DATE</tt>
|
399
|
+
# when using Oracle 8.x client.
|
400
|
+
#
|
401
|
+
# The retrieved value's time zone is determined not by the session
|
402
|
+
# time zone, but by the OCI8::BindType.default_timezone
|
403
|
+
# The time zone can be changed as follows:
|
404
|
+
#
|
405
|
+
# OCI8::BindType.default_timezone = :local
|
406
|
+
# # or
|
407
|
+
# OCI8::BindType.default_timezone = :utc
|
408
|
+
#
|
321
409
|
class Time
|
322
410
|
if OCI8.oracle_client_version >= ORAVER_9_0
|
323
|
-
def self.create(con, val, param, max_array_size)
|
411
|
+
def self.create(con, val, param, max_array_size) # :nodoc:
|
324
412
|
if true # TODO: check Oracle server version
|
325
413
|
TimeViaOCITimestamp.new(con, val, param, max_array_size)
|
326
414
|
else
|
@@ -328,7 +416,7 @@ class OCI8
|
|
328
416
|
end
|
329
417
|
end
|
330
418
|
else
|
331
|
-
def self.create(con, val, param, max_array_size)
|
419
|
+
def self.create(con, val, param, max_array_size) # :nodoc:
|
332
420
|
TimeViaOCIDate.new(con, val, param, max_array_size)
|
333
421
|
end
|
334
422
|
end
|
@@ -339,20 +427,26 @@ class OCI8
|
|
339
427
|
# OCI8::BindType::IntervalYM
|
340
428
|
#++
|
341
429
|
#
|
342
|
-
# This is a helper class to bind
|
343
|
-
#
|
344
|
-
#
|
430
|
+
# This is a helper class to select or bind Oracle data type
|
431
|
+
# <tt>INTERVAL YEAR TO MONTH</tt>. The retrieved value is
|
432
|
+
# the number of months between two timestamps.
|
433
|
+
#
|
434
|
+
# The value can be applied to \DateTime#>> to shift months.
|
435
|
+
# It can be applied to \Time#months_since if activisupport has
|
436
|
+
# been loaded.
|
437
|
+
#
|
438
|
+
# === How to select <tt>INTERVAL YEAR TO MONTH</tt>
|
345
439
|
#
|
346
|
-
#
|
440
|
+
# <tt>INTERVAL YEAR TO MONTH</tt> is selected as an Integer.
|
347
441
|
#
|
348
|
-
#
|
349
|
-
#
|
350
|
-
#
|
442
|
+
# conn.exec("select (current_timestamp - hiredate) year to month from emp") do |hired_months|
|
443
|
+
# puts "hired_months = #{hired_months}"
|
444
|
+
# end
|
351
445
|
#
|
352
|
-
# ==
|
446
|
+
# == How to bind <tt>INTERVAL YEAR TO MONTH</tt>
|
353
447
|
#
|
354
|
-
# You cannot bind as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
|
355
|
-
# It must be bound explicitly
|
448
|
+
# You cannot bind a bind variable as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
|
449
|
+
# It must be bound explicitly by OCI8::Cursor#bind_param.
|
356
450
|
#
|
357
451
|
# # output bind variable
|
358
452
|
# cursor = conn.parse(<<-EOS)
|
@@ -399,51 +493,43 @@ class OCI8
|
|
399
493
|
# OCI8::BindType::IntervalDS
|
400
494
|
#++
|
401
495
|
#
|
402
|
-
#
|
403
|
-
# Rational[http://www.ruby-doc.org/core/classes/Rational.html]
|
404
|
-
# object as Oracle's <tt>INTERVAL DAY TO SECOND</tt> datatype.
|
496
|
+
# (new in 2.0)
|
405
497
|
#
|
406
|
-
#
|
498
|
+
# This is a helper class to select or bind Oracle data type
|
499
|
+
# <tt>INTERVAL DAY TO SECOND</tt>. The retrieved value is
|
500
|
+
# the number of seconds between two typestamps as a \Float.
|
407
501
|
#
|
408
|
-
#
|
409
|
-
# is
|
410
|
-
#
|
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]#-.
|
502
|
+
# Note that it is the number days as a \Rational if
|
503
|
+
# OCI8::BindType::IntervalDS.unit is :day or the ruby-oci8
|
504
|
+
# version is prior to 2.0.3.
|
414
505
|
#
|
415
|
-
# ==
|
506
|
+
# == How to bind <tt>INTERVAL DAY TO SECOND</tt>
|
416
507
|
#
|
417
|
-
# You cannot bind as <tt>INTERVAL
|
418
|
-
# It must be bound explicitly
|
508
|
+
# You cannot bind a bind variable as <tt>INTERVAL DAY TO SECOND</tt>
|
509
|
+
# implicitly. It must be bound explicitly by OCI8::Cursor#bind_param.
|
419
510
|
#
|
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')
|
511
|
+
# # output bind variable
|
423
512
|
# cursor = conn.parse(<<-EOS)
|
424
513
|
# BEGIN
|
425
|
-
# :
|
514
|
+
# :interval := (:ts1 - :ts2) DAY TO SECOND(9);
|
426
515
|
# END;
|
427
516
|
# EOS
|
428
|
-
# cursor.bind_param(:
|
429
|
-
# cursor.bind_param(:ts1,
|
430
|
-
# cursor.bind_param(:ts2,
|
517
|
+
# cursor.bind_param(:interval, nil, :interval_ds)
|
518
|
+
# cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
|
519
|
+
# cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
|
431
520
|
# cursor.exec
|
432
|
-
# cursor[:
|
521
|
+
# cursor[:interval] # => 10492615.0 seconds
|
433
522
|
# cursor.close
|
434
523
|
#
|
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
|
524
|
+
# # input bind variable
|
439
525
|
# cursor = conn.parse(<<-EOS)
|
440
526
|
# BEGIN
|
441
|
-
# :ts1 := :ts2 + :
|
527
|
+
# :ts1 := :ts2 + :interval;
|
442
528
|
# END;
|
443
529
|
# EOS
|
444
530
|
# cursor.bind_param(:ts1, nil, DateTime)
|
445
|
-
# cursor.bind_param(:ts2,
|
446
|
-
# cursor.bind_param(:
|
531
|
+
# cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
|
532
|
+
# cursor.bind_param(:interval, 10492615.0, :interval_ds)
|
447
533
|
# cursor.exec
|
448
534
|
# cursor[:ts1].strftime('%Y-%m-%d %H:%M:%S') # => 1969-11-19 06:54:35
|
449
535
|
# cursor.close
|
@@ -453,6 +539,32 @@ class OCI8
|
|
453
539
|
@@minute = @@hour / 60
|
454
540
|
@@sec = @@minute / 60
|
455
541
|
@@fsec = @@sec / 1000000000
|
542
|
+
@@unit = :second
|
543
|
+
|
544
|
+
# call-seq:
|
545
|
+
# OCI8::BindType::IntervalDS.unit -> :second or :day
|
546
|
+
#
|
547
|
+
# (new in 2.0.3)
|
548
|
+
#
|
549
|
+
# Retrieves the unit of interval.
|
550
|
+
def self.unit
|
551
|
+
@@unit
|
552
|
+
end
|
553
|
+
|
554
|
+
# call-seq:
|
555
|
+
# OCI8::BindType::IntervalDS.unit = :second or :day
|
556
|
+
#
|
557
|
+
# (new in 2.0.3)
|
558
|
+
#
|
559
|
+
# Changes the unit of interval. :second is the default.
|
560
|
+
def self.unit=(val)
|
561
|
+
case val
|
562
|
+
when :second, :day
|
563
|
+
@@unit = val
|
564
|
+
else
|
565
|
+
raise 'unit should be :second or :day'
|
566
|
+
end
|
567
|
+
end
|
456
568
|
|
457
569
|
def set(val) # :nodoc:
|
458
570
|
unless val.nil?
|
@@ -462,10 +574,17 @@ class OCI8
|
|
462
574
|
else
|
463
575
|
is_minus = false
|
464
576
|
end
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
577
|
+
if @@unit == :second
|
578
|
+
day, val = val.divmod 86400
|
579
|
+
hour, val = val.divmod 3600
|
580
|
+
minute, val = val.divmod 60
|
581
|
+
sec, val = val.divmod 1
|
582
|
+
else
|
583
|
+
day, val = val.divmod 1
|
584
|
+
hour, val = (val * 24).divmod 1
|
585
|
+
minute, val = (val * 60).divmod 1
|
586
|
+
sec, val = (val * 60).divmod 1
|
587
|
+
end
|
469
588
|
fsec, val = (val * 1000000000).divmod 1
|
470
589
|
if is_minus
|
471
590
|
day = - day
|
@@ -483,7 +602,12 @@ class OCI8
|
|
483
602
|
val = super()
|
484
603
|
return nil if val.nil?
|
485
604
|
day, hour, minute, sec, fsec = val
|
486
|
-
|
605
|
+
if @@unit == :second
|
606
|
+
fsec = fsec / 1000000000.0
|
607
|
+
day * 86400 + hour * 3600 + minute * 60 + sec + fsec
|
608
|
+
else
|
609
|
+
day + (hour * @@hour) + (minute * @@minute) + (sec * @@sec) + (fsec * @@fsec)
|
610
|
+
end
|
487
611
|
end
|
488
612
|
end # OCI8::BindType::IntervalDS
|
489
613
|
end
|