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.
- checksums.yaml +7 -0
- data/.yardopts +17 -0
- data/COPYING +30 -0
- data/COPYING_old +64 -0
- data/ChangeLog +2779 -0
- data/Makefile +92 -0
- data/NEWS +660 -0
- data/README.md +43 -0
- data/VERSION +1 -0
- data/dist-files +91 -0
- data/docs/install-binary-package.md +40 -0
- data/docs/install-full-client.md +116 -0
- data/docs/install-instant-client.md +167 -0
- data/docs/platform-specific-issues.md +197 -0
- data/docs/report-installation-issue.md +50 -0
- data/lib/.document +1 -0
- data/lib/dbd/OCI8.rb +591 -0
- data/lib/oci8.rb +147 -0
- data/lib/oci8.rb.in +147 -0
- data/lib/oci8/.document +8 -0
- data/lib/oci8/bindtype.rb +350 -0
- data/lib/oci8/compat.rb +113 -0
- data/lib/oci8/connection_pool.rb +108 -0
- data/lib/oci8/cursor.rb +564 -0
- data/lib/oci8/datetime.rb +605 -0
- data/lib/oci8/encoding-init.rb +79 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2092 -0
- data/lib/oci8/object.rb +605 -0
- data/lib/oci8/oci8.rb +560 -0
- data/lib/oci8/ocihandle.rb +607 -0
- data/lib/oci8/oracle_version.rb +143 -0
- data/lib/oci8/properties.rb +134 -0
- data/lib/oci8lib_200.so +0 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-oci8.gemspec +80 -0
- data/setup.rb +1333 -0
- data/test/README +42 -0
- data/test/config.rb +184 -0
- data/test/setup_test_object.sql +171 -0
- data/test/test_all.rb +54 -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_string.rb +106 -0
- data/test/test_bind_time.rb +178 -0
- data/test/test_break.rb +124 -0
- data/test/test_clob.rb +98 -0
- data/test/test_connection_pool.rb +125 -0
- data/test/test_connstr.rb +81 -0
- data/test/test_datetime.rb +581 -0
- data/test/test_dbi.rb +366 -0
- data/test/test_dbi_clob.rb +53 -0
- data/test/test_encoding.rb +104 -0
- data/test/test_error.rb +88 -0
- data/test/test_metadata.rb +1485 -0
- data/test/test_object.rb +462 -0
- data/test/test_oci8.rb +489 -0
- data/test/test_oracle_version.rb +70 -0
- data/test/test_oradate.rb +256 -0
- data/test/test_oranumber.rb +787 -0
- data/test/test_rowid.rb +33 -0
- metadata +109 -0
data/lib/oci8/object.rb
ADDED
@@ -0,0 +1,605 @@
|
|
1
|
+
#
|
2
|
+
# OCI8::NamedType
|
3
|
+
#
|
4
|
+
require 'oci8/metadata.rb'
|
5
|
+
|
6
|
+
class OCI8
|
7
|
+
|
8
|
+
# Returns the type descriptor object which correspond to the given class.
|
9
|
+
#
|
10
|
+
# @param [class of an OCI8::Object::Base's subclass] klass
|
11
|
+
# @return [OCI8::TDO]
|
12
|
+
#
|
13
|
+
# @private
|
14
|
+
def get_tdo_by_class(klass)
|
15
|
+
@id_to_tdo ||= {}
|
16
|
+
@name_to_tdo ||= {}
|
17
|
+
tdo = @name_to_tdo[klass.typename]
|
18
|
+
return tdo if tdo # found in the cache.
|
19
|
+
|
20
|
+
metadata = describe_any(klass.typename)
|
21
|
+
if metadata.is_a? OCI8::Metadata::Synonym
|
22
|
+
metadata = describe_any(metadata.translated_name)
|
23
|
+
end
|
24
|
+
unless metadata.is_a? OCI8::Metadata::Type
|
25
|
+
raise "unknown typename #{klass.typename}"
|
26
|
+
end
|
27
|
+
OCI8::TDO.new(self, metadata, klass)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the type descriptor object which correspond to the given metadata.
|
31
|
+
#
|
32
|
+
# @param [OCI8::Metadata::Base's subclass] metadata
|
33
|
+
# @return [OCI8::TDO]
|
34
|
+
#
|
35
|
+
# @private
|
36
|
+
def get_tdo_by_metadata(metadata)
|
37
|
+
@id_to_tdo ||= {}
|
38
|
+
@name_to_tdo ||= {}
|
39
|
+
tdo = @id_to_tdo[metadata.tdo_id]
|
40
|
+
return tdo if tdo
|
41
|
+
|
42
|
+
schema_name = metadata.schema_name
|
43
|
+
name = metadata.name
|
44
|
+
full_name = schema_name + '.' + name
|
45
|
+
|
46
|
+
klass = OCI8::Object::Base.get_class_by_typename(full_name)
|
47
|
+
klass = OCI8::Object::Base.get_class_by_typename(name) if klass.nil?
|
48
|
+
if klass.nil?
|
49
|
+
if schema_name == username
|
50
|
+
eval <<EOS
|
51
|
+
module Object
|
52
|
+
class #{name.downcase.gsub(/(^|_)(.)/) { $2.upcase }} < OCI8::Object::Base
|
53
|
+
set_typename('#{name}')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
EOS
|
57
|
+
klass = OCI8::Object::Base.get_class_by_typename(name)
|
58
|
+
else
|
59
|
+
eval <<EOS
|
60
|
+
module Object
|
61
|
+
module #{schema_name.downcase.gsub(/(^|_)(.)/) { $2.upcase }}
|
62
|
+
class #{name.downcase.gsub(/(^|_)(.)/) { $2.upcase }} < OCI8::Object::Base
|
63
|
+
set_typename('#{full_name}')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
EOS
|
68
|
+
klass = OCI8::Object::Base.get_class_by_typename(full_name)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
OCI8::TDO.new(self, metadata, klass)
|
72
|
+
end
|
73
|
+
|
74
|
+
# A helper class to bind arguments.
|
75
|
+
#
|
76
|
+
# @private
|
77
|
+
class BindArgumentHelper
|
78
|
+
attr_reader :arg_str
|
79
|
+
def initialize(*args)
|
80
|
+
if args.length == 1 and args[0].is_a? Hash
|
81
|
+
@arg_str = args[0].keys.collect do |key| "#{key}=>:#{key}"; end.join(', ')
|
82
|
+
@bind_vars = args[0]
|
83
|
+
else
|
84
|
+
ary = []
|
85
|
+
@bind_vars = {}
|
86
|
+
args.each_with_index do |obj, idx|
|
87
|
+
key = ':' + (idx + 1).to_s
|
88
|
+
ary << key
|
89
|
+
@bind_vars[key] = obj
|
90
|
+
end
|
91
|
+
@arg_str = ary.join(', ')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def exec(con, csr)
|
96
|
+
@bind_vars.each do |key, val|
|
97
|
+
if val.is_a? OCI8::Object::Base
|
98
|
+
tdo = con.get_tdo_by_class(val.class)
|
99
|
+
csr.bind_param(key, nil, :named_type_internal, tdo)
|
100
|
+
csr[key].attributes = val
|
101
|
+
else
|
102
|
+
csr.bind_param(key, val ? val : '')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
csr.exec
|
106
|
+
@bind_vars.each do |key, val|
|
107
|
+
if val.is_a? OCI8::Object::Base
|
108
|
+
val.instance_variable_set(:@attributes, csr[key].attributes)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
module Object
|
115
|
+
class Base
|
116
|
+
@@class_to_name = {}
|
117
|
+
@@name_to_class = {}
|
118
|
+
@@default_connection = nil
|
119
|
+
|
120
|
+
# @private
|
121
|
+
def self.inherited(klass)
|
122
|
+
name = klass.to_s.gsub(/^.*::/, '').gsub(/([a-z\d])([A-Z])/,'\1_\2').upcase
|
123
|
+
@@class_to_name[klass] = name
|
124
|
+
@@name_to_class[name] = klass
|
125
|
+
end
|
126
|
+
|
127
|
+
# @private
|
128
|
+
def self.get_class_by_typename(name)
|
129
|
+
@@name_to_class[name]
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.typename
|
133
|
+
@@class_to_name[self]
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.set_typename(name)
|
137
|
+
# delete an old name-to-class mapping.
|
138
|
+
@@name_to_class[@@class_to_name[self]] = nil
|
139
|
+
# set a new name-to-class mapping.
|
140
|
+
name = name.upcase
|
141
|
+
@@class_to_name[self] = name
|
142
|
+
@@name_to_class[name] = self
|
143
|
+
end
|
144
|
+
|
145
|
+
# @deprecated
|
146
|
+
def self.default_connection=(con)
|
147
|
+
@@default_connection = con
|
148
|
+
end
|
149
|
+
|
150
|
+
def initialize(*args)
|
151
|
+
@attributes = {}
|
152
|
+
if args[0].is_a? OCI8
|
153
|
+
@con = args.shift
|
154
|
+
else
|
155
|
+
@con = @@default_connection
|
156
|
+
end
|
157
|
+
return if args.empty?
|
158
|
+
raise "no connection is specified." if @con.nil?
|
159
|
+
# setup a TDO object.
|
160
|
+
tdo = @con.get_tdo_by_class(self.class)
|
161
|
+
# call constructor.
|
162
|
+
bind_arg_helper = BindArgumentHelper.new(*args)
|
163
|
+
sql = <<EOS
|
164
|
+
BEGIN
|
165
|
+
:self := #{tdo.typename}(#{bind_arg_helper.arg_str});
|
166
|
+
END;
|
167
|
+
EOS
|
168
|
+
csr = @con.parse_internal(sql)
|
169
|
+
begin
|
170
|
+
csr.bind_param(:self, nil, :named_type_internal, tdo)
|
171
|
+
bind_arg_helper.exec(@con, csr)
|
172
|
+
@attributes = csr[:self].attributes
|
173
|
+
ensure
|
174
|
+
csr.close
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# class method
|
179
|
+
|
180
|
+
# @private
|
181
|
+
def self.method_missing(method_id, *args)
|
182
|
+
if args[0].is_a? OCI8
|
183
|
+
con = args.shift
|
184
|
+
else
|
185
|
+
con = @@default_connection
|
186
|
+
end
|
187
|
+
tdo = con.get_tdo_by_class(self)
|
188
|
+
return_type = tdo.class_methods[method_id]
|
189
|
+
if return_type == :none
|
190
|
+
# procedure
|
191
|
+
bind_arg_helper = BindArgumentHelper.new(*args)
|
192
|
+
sql = <<EOS
|
193
|
+
BEGIN
|
194
|
+
#{tdo.typename}.#{method_id}(#{bind_arg_helper.arg_str});
|
195
|
+
END;
|
196
|
+
EOS
|
197
|
+
csr = con.parse_internal(sql)
|
198
|
+
begin
|
199
|
+
bind_arg_helper.exec(con, csr)
|
200
|
+
ensure
|
201
|
+
csr.close
|
202
|
+
end
|
203
|
+
return nil
|
204
|
+
elsif return_type
|
205
|
+
# function
|
206
|
+
return_type = tdo.class_methods[method_id]
|
207
|
+
bind_arg_helper = BindArgumentHelper.new(*args)
|
208
|
+
sql = <<EOS
|
209
|
+
BEGIN
|
210
|
+
:rv := #{tdo.typename}.#{method_id}(#{bind_arg_helper.arg_str});
|
211
|
+
END;
|
212
|
+
EOS
|
213
|
+
csr = con.parse_internal(sql)
|
214
|
+
begin
|
215
|
+
csr.bind_param(:rv, nil, return_type)
|
216
|
+
bind_arg_helper.exec(con, csr)
|
217
|
+
rv = csr[:rv]
|
218
|
+
ensure
|
219
|
+
csr.close
|
220
|
+
end
|
221
|
+
return rv
|
222
|
+
end
|
223
|
+
super # The method is not found.
|
224
|
+
end
|
225
|
+
|
226
|
+
# instance method
|
227
|
+
|
228
|
+
# @private
|
229
|
+
def method_missing(method_id, *args)
|
230
|
+
if @attributes.is_a? Array
|
231
|
+
return @attributes if method_id == :to_ary
|
232
|
+
super
|
233
|
+
end
|
234
|
+
# getter func
|
235
|
+
if @attributes.has_key?(method_id)
|
236
|
+
if args.length != 0
|
237
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 0)"
|
238
|
+
end
|
239
|
+
return @attributes[method_id]
|
240
|
+
end
|
241
|
+
# setter func
|
242
|
+
method_name = method_id.to_s
|
243
|
+
if method_name[-1] == ?=
|
244
|
+
attr = method_name[0...-1].intern
|
245
|
+
if @attributes.has_key?(attr)
|
246
|
+
if args.length != 1
|
247
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)"
|
248
|
+
end
|
249
|
+
return @attributes[attr] = args[0]
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
super if @con.nil?
|
254
|
+
|
255
|
+
tdo = @con.get_tdo_by_class(self.class)
|
256
|
+
return_type = tdo.instance_methods[method_id]
|
257
|
+
if return_type == :none
|
258
|
+
# procedure
|
259
|
+
bind_arg_helper = BindArgumentHelper.new(*args)
|
260
|
+
sql = <<EOS
|
261
|
+
DECLARE
|
262
|
+
val #{tdo.typename} := :self;
|
263
|
+
BEGIN
|
264
|
+
val.#{method_id}(#{bind_arg_helper.arg_str});
|
265
|
+
:self := val;
|
266
|
+
END;
|
267
|
+
EOS
|
268
|
+
csr = @con.parse_internal(sql)
|
269
|
+
begin
|
270
|
+
csr.bind_param(:self, nil, :named_type_internal, tdo)
|
271
|
+
csr[:self].attributes = self
|
272
|
+
bind_arg_helper.exec(@con, csr)
|
273
|
+
@attributes = csr[:self].attributes
|
274
|
+
ensure
|
275
|
+
csr.close
|
276
|
+
end
|
277
|
+
return nil
|
278
|
+
elsif return_type
|
279
|
+
# function
|
280
|
+
bind_arg_helper = BindArgumentHelper.new(*args)
|
281
|
+
sql = <<EOS
|
282
|
+
DECLARE
|
283
|
+
val #{tdo.typename} := :self;
|
284
|
+
BEGIN
|
285
|
+
:rv := val.#{method_id}(#{bind_arg_helper.arg_str});
|
286
|
+
:self := val;
|
287
|
+
END;
|
288
|
+
EOS
|
289
|
+
csr = @con.parse_internal(sql)
|
290
|
+
begin
|
291
|
+
csr.bind_param(:self, nil, :named_type_internal, tdo)
|
292
|
+
csr.bind_param(:rv, nil, return_type)
|
293
|
+
csr[:self].attributes = self
|
294
|
+
bind_arg_helper.exec(@con, csr)
|
295
|
+
@attributes = csr[:self].attributes
|
296
|
+
rv = csr[:rv]
|
297
|
+
ensure
|
298
|
+
csr.close
|
299
|
+
end
|
300
|
+
return rv
|
301
|
+
end
|
302
|
+
# The method is not found.
|
303
|
+
super
|
304
|
+
end # method_missing
|
305
|
+
end # OCI8::Object::Base
|
306
|
+
end # OCI8::Object
|
307
|
+
|
308
|
+
# @private
|
309
|
+
class TDO
|
310
|
+
# full-qualified object type name.
|
311
|
+
# e.g.
|
312
|
+
# MDSYS.SDO_GEOMETRY
|
313
|
+
attr_reader :typename
|
314
|
+
|
315
|
+
# a subclass of OCI8::Object::Base
|
316
|
+
attr_reader :ruby_class
|
317
|
+
|
318
|
+
attr_reader :val_size
|
319
|
+
attr_reader :ind_size
|
320
|
+
attr_reader :alignment
|
321
|
+
|
322
|
+
attr_reader :attributes
|
323
|
+
attr_reader :coll_attr
|
324
|
+
attr_reader :attr_getters
|
325
|
+
attr_reader :attr_setters
|
326
|
+
|
327
|
+
# mapping between class method's ids and their return types.
|
328
|
+
# :none means a procedure.
|
329
|
+
# CREATE OR REPLACE TYPE foo AS OBJECT (
|
330
|
+
# STATIC FUNCTION bar RETURN INTEGER,
|
331
|
+
# STATIC PROCEDURE baz,
|
332
|
+
# );
|
333
|
+
# => {:bar => Integer, :baz => :none}
|
334
|
+
|
335
|
+
attr_reader :class_methods
|
336
|
+
# mapping between instance method's ids and their return types.
|
337
|
+
# :none means a procedure.
|
338
|
+
# CREATE OR REPLACE TYPE foo AS OBJECT (
|
339
|
+
# MEMBER FUNCTION bar RETURN INTEGER,
|
340
|
+
# MEMBER PROCEDURE baz,
|
341
|
+
# );
|
342
|
+
# => {:bar => Integer, :baz => :none}
|
343
|
+
attr_reader :instance_methods
|
344
|
+
|
345
|
+
def is_collection?
|
346
|
+
@coll_attr ? true : false
|
347
|
+
end
|
348
|
+
|
349
|
+
def initialize(con, metadata, klass)
|
350
|
+
@ruby_class = klass
|
351
|
+
@typename = metadata.schema_name + '.' + metadata.name
|
352
|
+
|
353
|
+
setup(con, metadata)
|
354
|
+
con.instance_variable_get(:@id_to_tdo)[metadata.tdo_id] = self
|
355
|
+
con.instance_variable_get(:@name_to_tdo)[@typename] = self
|
356
|
+
con.instance_variable_get(:@name_to_tdo)[klass.typename] = self
|
357
|
+
if metadata.schema_name == con.username
|
358
|
+
con.instance_variable_get(:@name_to_tdo)[metadata.name] = self
|
359
|
+
end
|
360
|
+
|
361
|
+
case metadata.typecode
|
362
|
+
when :named_type
|
363
|
+
initialize_named_type(con, metadata)
|
364
|
+
when :named_collection
|
365
|
+
initialize_named_collection(con, metadata)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def initialize_named_type(con, metadata)
|
370
|
+
@val_size = 0
|
371
|
+
@ind_size = 2
|
372
|
+
@alignment = 1
|
373
|
+
@attributes = metadata.type_attrs.collect do |type_attr|
|
374
|
+
attr = Attr.new(con, type_attr, @val_size, @ind_size)
|
375
|
+
@val_size, @ind_size = attr.next_offset
|
376
|
+
if @alignment < attr.alignment
|
377
|
+
@alignment = attr.alignment
|
378
|
+
end
|
379
|
+
attr
|
380
|
+
end
|
381
|
+
# fix alignment
|
382
|
+
@val_size = (@val_size + @alignment - 1) & ~(@alignment - 1)
|
383
|
+
|
384
|
+
# setup attr_getters and attr_setters
|
385
|
+
@attr_getters = {}
|
386
|
+
@attr_setters = {}
|
387
|
+
@attributes.each do |attr|
|
388
|
+
@attr_getters[attr.name] = attr
|
389
|
+
@attr_setters[(attr.name.to_s + '=').intern] = attr
|
390
|
+
end
|
391
|
+
|
392
|
+
# set class_methods and instance_methods
|
393
|
+
@class_methods = {}
|
394
|
+
@instance_methods = {}
|
395
|
+
metadata.type_methods.each_with_index do |type_method, i|
|
396
|
+
next if type_method.is_constructor? or type_method.is_destructor?
|
397
|
+
|
398
|
+
result_type = nil
|
399
|
+
if type_method.has_result?
|
400
|
+
# function
|
401
|
+
con.exec_internal("select result_type_owner, result_type_name from all_method_results where OWNER = :1 and TYPE_NAME = :2 and METHOD_NO = :3", metadata.schema_name, metadata.name, i + 1) do |r|
|
402
|
+
if r[0].nil?
|
403
|
+
result_type = @@result_type_to_bindtype[r[1]]
|
404
|
+
else
|
405
|
+
result_type = con.get_tdo_by_metadata(con.describe_type("#{r[0]}.#{r[1]}"))
|
406
|
+
end
|
407
|
+
end
|
408
|
+
else
|
409
|
+
# procedure
|
410
|
+
result_type = :none
|
411
|
+
end
|
412
|
+
if result_type
|
413
|
+
if type_method.is_selfish?
|
414
|
+
@instance_methods[type_method.name.downcase.intern] = result_type
|
415
|
+
else
|
416
|
+
@class_methods[type_method.name.downcase.intern] = result_type
|
417
|
+
end
|
418
|
+
else
|
419
|
+
warn "unsupported return type (#{metadata.schema_name}.#{metadata.name}.#{type_method.name})" if $VERBOSE
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
private :initialize_named_type
|
424
|
+
|
425
|
+
def initialize_named_collection(con, metadata)
|
426
|
+
@val_size = SIZE_OF_POINTER
|
427
|
+
@ind_size = 2
|
428
|
+
@alignment = ALIGNMENT_OF_POINTER
|
429
|
+
@coll_attr = Attr.new(con, metadata.collection_element, 0, 0)
|
430
|
+
end
|
431
|
+
private :initialize_named_collection
|
432
|
+
|
433
|
+
def inspect
|
434
|
+
"#<#{self.class}:#@typename>"
|
435
|
+
end
|
436
|
+
|
437
|
+
@@result_type_to_bindtype = {
|
438
|
+
'FLOAT' => Float,
|
439
|
+
'INTEGER' => Integer,
|
440
|
+
'NUMBER' => OraNumber,
|
441
|
+
'BINARY_FLOAT' => :binary_float,
|
442
|
+
'BINARY_DOUBLE' => :binary_double,
|
443
|
+
'TIMESTAMP' => :timestamp,
|
444
|
+
'TIMESTAMP WITH TZ' => :timestamp_tz,
|
445
|
+
'TIMESTAMP WITH LOCAL TZ' => :timestamp_ltz,
|
446
|
+
'INTERVAL YEAR TO MONTH' => :interval_ym,
|
447
|
+
'INTERVAL DAY TO SECOND' => :interval_ds,
|
448
|
+
}
|
449
|
+
|
450
|
+
# to use datetime_to_array and array_to_datetime
|
451
|
+
extend OCI8::BindType::Util
|
452
|
+
|
453
|
+
def self.check_metadata(con, metadata)
|
454
|
+
case metadata.typecode
|
455
|
+
when :char, :varchar, :varchar2
|
456
|
+
[ATTR_STRING, nil, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
457
|
+
when :raw
|
458
|
+
[ATTR_RAW, nil, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
459
|
+
when :number, :decimal
|
460
|
+
[ATTR_OCINUMBER, nil, SIZE_OF_OCINUMBER, 2, ALIGNMENT_OF_OCINUMBER]
|
461
|
+
when :integer, :smallint
|
462
|
+
[ATTR_INTEGER, nil, SIZE_OF_OCINUMBER, 2, ALIGNMENT_OF_OCINUMBER]
|
463
|
+
when :real, :double, :float
|
464
|
+
[ATTR_FLOAT, nil, SIZE_OF_OCINUMBER, 2, ALIGNMENT_OF_OCINUMBER]
|
465
|
+
when :date
|
466
|
+
[ATTR_OCIDATE, nil, SIZE_OF_OCIDATE, 2, ALIGNMENT_OF_OCIDATE,
|
467
|
+
Proc.new do |val| datetime_to_array(val, :date) end, # set_proc
|
468
|
+
Proc.new do |val| array_to_time(val, :local) end, # get_proc
|
469
|
+
]
|
470
|
+
when :binary_double
|
471
|
+
[ATTR_BINARY_DOUBLE, nil, SIZE_OF_DOUBLE, 2, ALIGNMENT_OF_DOUBLE]
|
472
|
+
when :binary_float
|
473
|
+
[ATTR_BINARY_FLOAT, nil, SIZE_OF_FLOAT, 2, ALIGNMENT_OF_FLOAT]
|
474
|
+
when :named_type
|
475
|
+
tdo = con.get_tdo_by_metadata(metadata.type_metadata)
|
476
|
+
[ATTR_NAMED_TYPE, tdo, tdo.val_size, tdo.ind_size, tdo.alignment]
|
477
|
+
when :named_collection
|
478
|
+
#datatype, typeinfo, = OCI8::TDO.check_metadata(con, metadata.type_metadata.collection_element)
|
479
|
+
#[ATTR_NAMED_COLLECTION, [datatype, typeinfo], SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
480
|
+
tdo = con.get_tdo_by_metadata(metadata.type_metadata)
|
481
|
+
[ATTR_NAMED_COLLECTION, tdo, tdo.val_size, tdo.ind_size, tdo.alignment]
|
482
|
+
when :clob
|
483
|
+
if metadata.charset_form != :nchar
|
484
|
+
[ATTR_CLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
485
|
+
else
|
486
|
+
[ATTR_NCLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
487
|
+
end
|
488
|
+
when :blob
|
489
|
+
[ATTR_BLOB, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
490
|
+
when :bfile
|
491
|
+
[ATTR_BFILE, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER]
|
492
|
+
else
|
493
|
+
raise "unsupported typecode #{metadata.typecode}"
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
class Attr
|
498
|
+
attr_reader :name
|
499
|
+
attr_reader :val_offset
|
500
|
+
attr_reader :ind_offset
|
501
|
+
attr_reader :alignment
|
502
|
+
attr_reader :datatype
|
503
|
+
attr_reader :typeinfo
|
504
|
+
attr_reader :set_proc
|
505
|
+
attr_reader :get_proc
|
506
|
+
def initialize(con, metadata, val_offset, ind_offset)
|
507
|
+
if metadata.respond_to? :name
|
508
|
+
@name = metadata.name.downcase.intern
|
509
|
+
end
|
510
|
+
@datatype, @typeinfo, @val_size, @ind_size, @alignment, @set_proc, @get_proc, = OCI8::TDO.check_metadata(con, metadata)
|
511
|
+
@val_offset = (val_offset + @alignment - 1) & ~(@alignment - 1)
|
512
|
+
@ind_offset = ind_offset
|
513
|
+
end
|
514
|
+
def next_offset
|
515
|
+
[@val_offset + @val_size, @ind_offset + @ind_size]
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
# @private
|
521
|
+
class NamedType
|
522
|
+
def to_value
|
523
|
+
return nil if self.null?
|
524
|
+
obj = tdo.ruby_class.new
|
525
|
+
obj.instance_variable_set(:@attributes, self.attributes)
|
526
|
+
obj
|
527
|
+
end
|
528
|
+
|
529
|
+
def attributes
|
530
|
+
attrs = {}
|
531
|
+
tdo.attributes.each do |attr|
|
532
|
+
attr_val = get_attribute(attr.datatype, attr.typeinfo, attr.val_offset, attr.ind_offset)
|
533
|
+
attr_val = attr.get_proc.call(attr_val) if attr.get_proc
|
534
|
+
attrs[attr.name] = attr_val
|
535
|
+
end
|
536
|
+
attrs
|
537
|
+
end
|
538
|
+
|
539
|
+
def attributes=(obj)
|
540
|
+
if obj.nil?
|
541
|
+
self.null = true
|
542
|
+
else
|
543
|
+
obj = obj.instance_variable_get(:@attributes) unless obj.is_a? Hash
|
544
|
+
tdo.attributes.each do |attr|
|
545
|
+
attr_val = obj[attr.name]
|
546
|
+
attr_val = attr.set_proc.call(attr_val) if attr.set_proc
|
547
|
+
set_attribute(attr.datatype, attr.typeinfo, attr.val_offset, attr.ind_offset, attr_val)
|
548
|
+
end
|
549
|
+
self.null = false
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
# @private
|
555
|
+
class NamedCollection
|
556
|
+
def to_value
|
557
|
+
attr = self.attributes
|
558
|
+
if attr
|
559
|
+
obj = tdo.ruby_class.new
|
560
|
+
obj.instance_variable_set(:@attributes, attr)
|
561
|
+
obj
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
def attributes
|
566
|
+
attr = tdo.coll_attr
|
567
|
+
get_coll_element(attr.datatype, attr.typeinfo)
|
568
|
+
end
|
569
|
+
|
570
|
+
def attributes=(obj)
|
571
|
+
attr = tdo.coll_attr
|
572
|
+
set_coll_element(attr.datatype, attr.typeinfo, obj.to_ary)
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
class OCI8
|
578
|
+
module BindType
|
579
|
+
|
580
|
+
class NamedType
|
581
|
+
def self.create(con, val, param, max_array_size)
|
582
|
+
case param
|
583
|
+
when Hash
|
584
|
+
self.new(con, val, param[:length], max_array_size)
|
585
|
+
else
|
586
|
+
self.new(con, val, param, max_array_size)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
class Object < OCI8::BindType::NamedType
|
592
|
+
alias :get_orig get
|
593
|
+
def set(val)
|
594
|
+
get_orig.attributes = val
|
595
|
+
nil
|
596
|
+
end
|
597
|
+
def get()
|
598
|
+
(obj = super()) && obj.to_value
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
OCI8::BindType::Mapping[:named_type] = OCI8::BindType::Object
|
605
|
+
OCI8::BindType::Mapping[:named_type_internal] = OCI8::BindType::NamedType
|