ruby-oci8 2.0.4-x86-mingw32

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