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.
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