ruby-oci8 2.1.5.1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +17 -0
  3. data/COPYING +30 -0
  4. data/COPYING_old +64 -0
  5. data/ChangeLog +2779 -0
  6. data/Makefile +92 -0
  7. data/NEWS +660 -0
  8. data/README.md +43 -0
  9. data/VERSION +1 -0
  10. data/dist-files +91 -0
  11. data/docs/install-binary-package.md +40 -0
  12. data/docs/install-full-client.md +116 -0
  13. data/docs/install-instant-client.md +167 -0
  14. data/docs/platform-specific-issues.md +197 -0
  15. data/docs/report-installation-issue.md +50 -0
  16. data/lib/.document +1 -0
  17. data/lib/dbd/OCI8.rb +591 -0
  18. data/lib/oci8.rb +147 -0
  19. data/lib/oci8.rb.in +147 -0
  20. data/lib/oci8/.document +8 -0
  21. data/lib/oci8/bindtype.rb +350 -0
  22. data/lib/oci8/compat.rb +113 -0
  23. data/lib/oci8/connection_pool.rb +108 -0
  24. data/lib/oci8/cursor.rb +564 -0
  25. data/lib/oci8/datetime.rb +605 -0
  26. data/lib/oci8/encoding-init.rb +79 -0
  27. data/lib/oci8/encoding.yml +537 -0
  28. data/lib/oci8/metadata.rb +2092 -0
  29. data/lib/oci8/object.rb +605 -0
  30. data/lib/oci8/oci8.rb +560 -0
  31. data/lib/oci8/ocihandle.rb +607 -0
  32. data/lib/oci8/oracle_version.rb +143 -0
  33. data/lib/oci8/properties.rb +134 -0
  34. data/lib/oci8lib_200.so +0 -0
  35. data/metaconfig +142 -0
  36. data/pre-distclean.rb +7 -0
  37. data/ruby-oci8.gemspec +80 -0
  38. data/setup.rb +1333 -0
  39. data/test/README +42 -0
  40. data/test/config.rb +184 -0
  41. data/test/setup_test_object.sql +171 -0
  42. data/test/test_all.rb +54 -0
  43. data/test/test_appinfo.rb +63 -0
  44. data/test/test_array_dml.rb +333 -0
  45. data/test/test_bind_raw.rb +46 -0
  46. data/test/test_bind_string.rb +106 -0
  47. data/test/test_bind_time.rb +178 -0
  48. data/test/test_break.rb +124 -0
  49. data/test/test_clob.rb +98 -0
  50. data/test/test_connection_pool.rb +125 -0
  51. data/test/test_connstr.rb +81 -0
  52. data/test/test_datetime.rb +581 -0
  53. data/test/test_dbi.rb +366 -0
  54. data/test/test_dbi_clob.rb +53 -0
  55. data/test/test_encoding.rb +104 -0
  56. data/test/test_error.rb +88 -0
  57. data/test/test_metadata.rb +1485 -0
  58. data/test/test_object.rb +462 -0
  59. data/test/test_oci8.rb +489 -0
  60. data/test/test_oracle_version.rb +70 -0
  61. data/test/test_oradate.rb +256 -0
  62. data/test/test_oranumber.rb +787 -0
  63. data/test/test_rowid.rb +33 -0
  64. metadata +109 -0
@@ -0,0 +1,605 @@
1
+ #
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