ruby-oci8 1.0.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/ChangeLog +1254 -390
  2. data/Makefile +10 -13
  3. data/README +56 -385
  4. data/VERSION +1 -1
  5. data/dist-files +26 -27
  6. data/ext/oci8/.document +1 -0
  7. data/ext/oci8/MANIFEST +0 -4
  8. data/ext/oci8/apiwrap.c.tmpl +172 -0
  9. data/ext/oci8/apiwrap.h.tmpl +61 -0
  10. data/ext/oci8/apiwrap.rb +91 -0
  11. data/ext/oci8/apiwrap.yml +1243 -0
  12. data/ext/oci8/attr.c +124 -384
  13. data/ext/oci8/bind.c +472 -164
  14. data/ext/oci8/encoding.c +196 -0
  15. data/ext/oci8/env.c +84 -253
  16. data/ext/oci8/error.c +196 -127
  17. data/ext/oci8/extconf.rb +82 -59
  18. data/ext/oci8/lob.c +710 -370
  19. data/ext/oci8/metadata.c +359 -0
  20. data/ext/oci8/object.c +622 -0
  21. data/ext/oci8/oci8.c +577 -161
  22. data/ext/oci8/oci8.h +354 -258
  23. data/ext/oci8/oci8lib.c +493 -0
  24. data/ext/oci8/ocidatetime.c +473 -0
  25. data/ext/oci8/ocinumber.c +1123 -24
  26. data/ext/oci8/oraconf.rb +72 -106
  27. data/ext/oci8/oradate.c +511 -321
  28. data/ext/oci8/stmt.c +752 -572
  29. data/ext/oci8/win32.c +131 -0
  30. data/ext/oci8/xmldb.c +383 -0
  31. data/lib/.document +2 -0
  32. data/lib/dbd/OCI8.rb +2 -17
  33. data/lib/oci8.rb.in +41 -1622
  34. data/lib/oci8/.document +5 -0
  35. data/lib/oci8/compat.rb +108 -0
  36. data/lib/oci8/datetime.rb +489 -0
  37. data/lib/oci8/encoding-init.rb +40 -0
  38. data/lib/oci8/encoding.yml +537 -0
  39. data/lib/oci8/metadata.rb +2077 -0
  40. data/lib/oci8/object.rb +548 -0
  41. data/lib/oci8/oci8.rb +773 -0
  42. data/lib/oci8/oracle_version.rb +144 -0
  43. data/metaconfig +3 -3
  44. data/ruby-oci8.gemspec +5 -5
  45. data/setup.rb +4 -4
  46. data/test/config.rb +64 -84
  47. data/test/test_all.rb +14 -21
  48. data/test/test_array_dml.rb +317 -0
  49. data/test/test_bind_raw.rb +18 -25
  50. data/test/test_bind_time.rb +78 -91
  51. data/test/test_break.rb +37 -35
  52. data/test/test_clob.rb +33 -89
  53. data/test/test_connstr.rb +5 -4
  54. data/test/test_datetime.rb +469 -0
  55. data/test/test_dbi.rb +99 -60
  56. data/test/test_dbi_clob.rb +3 -8
  57. data/test/test_metadata.rb +65 -51
  58. data/test/test_oci8.rb +151 -55
  59. data/test/test_oracle_version.rb +70 -0
  60. data/test/test_oradate.rb +76 -83
  61. data/test/test_oranumber.rb +405 -71
  62. data/test/test_rowid.rb +6 -11
  63. metadata +31 -32
  64. data/NEWS +0 -420
  65. data/ext/oci8/const.c +0 -165
  66. data/ext/oci8/define.c +0 -53
  67. data/ext/oci8/describe.c +0 -81
  68. data/ext/oci8/descriptor.c +0 -39
  69. data/ext/oci8/handle.c +0 -273
  70. data/ext/oci8/oranumber.c +0 -445
  71. data/ext/oci8/param.c +0 -37
  72. data/ext/oci8/server.c +0 -182
  73. data/ext/oci8/session.c +0 -99
  74. data/ext/oci8/svcctx.c +0 -238
  75. data/ruby-oci8.spec +0 -62
  76. data/support/README +0 -4
  77. data/support/runit/assert.rb +0 -281
  78. data/support/runit/cui/testrunner.rb +0 -101
  79. data/support/runit/error.rb +0 -4
  80. data/support/runit/method_mappable.rb +0 -20
  81. data/support/runit/robserver.rb +0 -25
  82. data/support/runit/setuppable.rb +0 -15
  83. data/support/runit/teardownable.rb +0 -16
  84. data/support/runit/testcase.rb +0 -113
  85. data/support/runit/testfailure.rb +0 -25
  86. data/support/runit/testresult.rb +0 -121
  87. data/support/runit/testsuite.rb +0 -43
  88. data/support/runit/version.rb +0 -3
  89. data/test/test_describe.rb +0 -137
@@ -0,0 +1,773 @@
1
+ # --*- ruby -*--
2
+ # This is based on yoshidam's oracle.rb.
3
+
4
+ require 'date'
5
+
6
+ # The database connection class.
7
+ class OCI8
8
+ # Executes the sql statement. The type of return value depends on
9
+ # the type of sql statement: select; insert, update and delete;
10
+ # create, alter and drop; and PL/SQL.
11
+ #
12
+ # When bindvars are specified, they are bound as bind variables
13
+ # before execution.
14
+ #
15
+ # == select statements without block
16
+ # It returns the instance of OCI8::Cursor.
17
+ #
18
+ # example:
19
+ # conn = OCI8.new('scott', 'tiger')
20
+ # cursor = conn.exec('SELECT * FROM emp')
21
+ # while r = cursor.fetch()
22
+ # puts r.join(',')
23
+ # end
24
+ # cursor.close
25
+ # conn.logoff
26
+ #
27
+ # == select statements with a block
28
+ # It acts as iterator and returns the processed row counts. Fetched
29
+ # data is passed to the block as array. NULL value becomes nil in ruby.
30
+ #
31
+ # example:
32
+ # conn = OCI8.new('scott', 'tiger')
33
+ # num_rows = conn.exec('SELECT * FROM emp') do |r|
34
+ # puts r.join(',')
35
+ # end
36
+ # puts num_rows.to_s + ' rows were processed.'
37
+ # conn.logoff
38
+ #
39
+ # == PL/SQL block (ruby-oci8 1.0)
40
+ # It returns the array of bind variables' values.
41
+ #
42
+ # example:
43
+ # conn = OCI8.new('scott', 'tiger')
44
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123)
45
+ # # => ["0123", 123]
46
+ # conn.logoff
47
+ #
48
+ # Above example uses two bind variables which names are :str
49
+ # and :num. These initial values are "the string whose width
50
+ # is 4 and whose value is 'ABCD'" and "the number whose value is
51
+ # 123". This method returns the array of these bind variables,
52
+ # which may modified by PL/SQL statement. The order of array is
53
+ # same with that of bind variables.
54
+ #
55
+ # If a block is given, it is ignored.
56
+ #
57
+ # == PL/SQL block (ruby-oci8 2.0)
58
+ # It returns the number of processed rows.
59
+ #
60
+ # example:
61
+ # conn = OCI8.new('scott', 'tiger')
62
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123)
63
+ # # => 1
64
+ # conn.logoff
65
+ #
66
+ # If a block is given, the bind variables' values are passed to the block after
67
+ # executed.
68
+ #
69
+ # conn = OCI8.new('scott', 'tiger')
70
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123) do |str, num|
71
+ # puts str # => '0123'
72
+ # puts num # => 123
73
+ # end
74
+ # conn.logoff
75
+ #
76
+ # FYI, the following code do same on ruby-oci8 1.0 and ruby-oci8 2.0.
77
+ # conn.exec(sql, *bindvars) { |*outvars| outvars }
78
+ #
79
+ # == Other SQL statements
80
+ # It returns the number of processed rows.
81
+ #
82
+ # example:
83
+ # conn = OCI8.new('scott', 'tiger')
84
+ # num_rows = conn.exec('UPDATE emp SET sal = sal * 1.1')
85
+ # puts num_rows.to_s + ' rows were updated.'
86
+ # conn.logoff
87
+ #
88
+ # example:
89
+ # conn = OCI8.new('scott', 'tiger')
90
+ # conn.exec('CREATE TABLE test (col1 CHAR(6))') # => 0
91
+ # conn.logoff
92
+ #
93
+ def exec(sql, *bindvars)
94
+ begin
95
+ cursor = parse(sql)
96
+ ret = cursor.exec(*bindvars)
97
+ case cursor.type
98
+ when :select_stmt
99
+ if block_given?
100
+ cursor.fetch { |row| yield(row) } # for each row
101
+ ret = cursor.row_count()
102
+ else
103
+ ret = cursor
104
+ cursor = nil # unset cursor to skip cursor.close in ensure block
105
+ ret
106
+ end
107
+ when :begin_stmt, :declare_stmt # PL/SQL block
108
+ if block_given?
109
+ ary = []
110
+ cursor.keys.sort.each do |key|
111
+ ary << cursor[key]
112
+ end
113
+ yield(*ary)
114
+ else
115
+ ret
116
+ end
117
+ else
118
+ ret # number of rows processed
119
+ end
120
+ ensure
121
+ cursor.nil? || cursor.close
122
+ end
123
+ end # exec
124
+
125
+ def username
126
+ @username || begin
127
+ exec('select user from dual') do |row|
128
+ @username = row[0]
129
+ end
130
+ @username
131
+ end
132
+ end
133
+
134
+ def inspect
135
+ "#<OCI8:#{username}>"
136
+ end
137
+
138
+ module BindType
139
+ Mapping = {}
140
+
141
+ class Base
142
+ def self.create(con, val, param, max_array_size)
143
+ self.new(con, val, param, max_array_size)
144
+ end
145
+ end
146
+
147
+ # get/set Date
148
+ class Date < OCI8::BindType::OraDate
149
+ def set(val)
150
+ super(val && ::OraDate.new(val.year, val.mon, val.mday))
151
+ end
152
+ def get()
153
+ (val = super()) && val.to_date
154
+ end
155
+ end
156
+
157
+ # get/set Number (for OCI8::SQLT_NUM)
158
+ class Number
159
+ def self.create(con, val, param, max_array_size)
160
+ if param.is_a? OCI8::Metadata::Base
161
+ precision = param.precision
162
+ scale = param.scale
163
+ end
164
+ if scale == -127
165
+ if precision == 0
166
+ # NUMBER declared without its scale and precision. (Oracle 9.2.0.3 or above)
167
+ klass = OCI8::BindType::Mapping[:number_no_prec_setting]
168
+ else
169
+ # FLOAT or FLOAT(p)
170
+ klass = OCI8::BindType::Float
171
+ end
172
+ elsif scale == 0
173
+ if precision == 0
174
+ # NUMBER whose scale and precision is unknown
175
+ # or
176
+ # NUMBER declared without its scale and precision. (Oracle 9.2.0.2 or below)
177
+ klass = OCI8::BindType::Mapping[:number_unknown_prec]
178
+ else
179
+ # NUMBER(p, 0)
180
+ klass = OCI8::BindType::Integer
181
+ end
182
+ else
183
+ # NUMBER(p, s)
184
+ if precision < 15 # the precision of double.
185
+ klass = OCI8::BindType::Float
186
+ else
187
+ # use BigDecimal instead?
188
+ klass = OCI8::BindType::OraNumber
189
+ end
190
+ end
191
+ klass.new(con, val, nil, max_array_size)
192
+ end
193
+ end
194
+
195
+ class String
196
+ def self.create(con, val, param, max_array_size)
197
+ case param
198
+ when Hash
199
+ # 1333 = ceil(4000 (max size of char) / 3 (NLS ratio of UTF8))
200
+ length = 1333 # default length
201
+ if param[:length]
202
+ length = param[:length]
203
+ elsif val.respond_to? :to_str and val.to_str.size > length
204
+ length = val.to_str.size
205
+ end
206
+ when OCI8::Metadata::Base
207
+ case param.data_type
208
+ when :char, :varchar2
209
+ length = param.data_size
210
+ # character size may become large on character set conversion.
211
+ # The length of a Japanese half-width kana is one in Shift_JIS,
212
+ # two in EUC-JP, three in UTF-8.
213
+ length *= 3 unless param.char_used?
214
+ when :raw
215
+ # HEX needs twice space.
216
+ length = param.data_size * 2
217
+ else
218
+ length = 100
219
+ end
220
+ end
221
+ self.new(con, val, length, max_array_size)
222
+ end
223
+ end
224
+
225
+ class RAW
226
+ def self.create(con, val, param, max_array_size)
227
+ case param
228
+ when Hash
229
+ length = 400 # default length
230
+ if param[:length]
231
+ length = param[:length]
232
+ elsif val.respond_to? :to_str and val.to_str.size > length
233
+ length = val.to_str.size
234
+ end
235
+ when OCI8::Metadata::Base
236
+ length = param.data_size
237
+ end
238
+ self.new(con, val, length, max_array_size)
239
+ end
240
+ end
241
+
242
+ class Long < OCI8::BindType::String
243
+ def self.create(con, val, param, max_array_size)
244
+ self.new(con, val, con.long_read_len, max_array_size)
245
+ end
246
+ end
247
+
248
+ class LongRaw < OCI8::BindType::RAW
249
+ def self.create(con, val, param, max_array_size)
250
+ self.new(con, val, con.long_read_len, max_array_size)
251
+ end
252
+ end
253
+
254
+ class CLOB
255
+ def self.create(con, val, param, max_array_size)
256
+ if param.is_a? OCI8::Metadata::Base and param.charset_form == :nchar
257
+ OCI8::BindType::NCLOB.new(con, val, nil, max_array_size)
258
+ else
259
+ OCI8::BindType::CLOB.new(con, val, nil, max_array_size)
260
+ end
261
+ end
262
+ end
263
+ end # BindType
264
+
265
+ # The instance of this class corresponds to cursor in the term of
266
+ # Oracle, which corresponds to java.sql.Statement of JDBC and statement
267
+ # handle $sth of Perl/DBI.
268
+ #
269
+ # Don't create the instance by calling 'new' method. Please create it by
270
+ # calling OCI8#exec or OCI8#parse.
271
+ class Cursor
272
+
273
+ # explicitly indicate the date type of fetched value. run this
274
+ # method within parse and exec. pos starts from 1. lentgh is used
275
+ # when type is String.
276
+ #
277
+ # example:
278
+ # cursor = conn.parse("SELECT ename, hiredate FROM emp")
279
+ # cursor.define(1, String, 20) # fetch the first column as String.
280
+ # cursor.define(2, Time) # fetch the second column as Time.
281
+ # cursor.exec()
282
+ def define(pos, type, length = nil)
283
+ __define(pos, make_bind_object(:type => type, :length => length))
284
+ self
285
+ end # define
286
+
287
+ # Binds variables explicitly.
288
+ #
289
+ # When key is number, it binds by position, which starts from 1.
290
+ # When key is string, it binds by the name of placeholder.
291
+ #
292
+ # example:
293
+ # cursor = conn.parse("SELECT * FROM emp WHERE ename = :ename")
294
+ # cursor.bind_param(1, 'SMITH') # bind by position
295
+ # ...or...
296
+ # cursor.bind_param(':ename', 'SMITH') # bind by name
297
+ #
298
+ # To bind as number, Fixnum and Float are available, but Bignum is
299
+ # not supported. If its initial value is NULL, please set nil to
300
+ # +type+ and Fixnum or Float to +val+.
301
+ #
302
+ # example:
303
+ # cursor.bind_param(1, 1234) # bind as Fixnum, Initial value is 1234.
304
+ # cursor.bind_param(1, 1234.0) # bind as Float, Initial value is 1234.0.
305
+ # cursor.bind_param(1, nil, Fixnum) # bind as Fixnum, Initial value is NULL.
306
+ # cursor.bind_param(1, nil, Float) # bind as Float, Initial value is NULL.
307
+ #
308
+ # In case of binding a string, set the string itself to
309
+ # +val+. When the bind variable is used as output, set the
310
+ # string whose length is enough to store or set the length.
311
+ #
312
+ # example:
313
+ # cursor = conn.parse("BEGIN :out := :in || '_OUT'; END;")
314
+ # cursor.bind_param(':in', 'DATA') # bind as String with width 4.
315
+ # cursor.bind_param(':out', nil, String, 7) # bind as String with width 7.
316
+ # cursor.exec()
317
+ # p cursor[':out'] # => 'DATA_OU'
318
+ # # Though the length of :out is 8 bytes in PL/SQL block, it is
319
+ # # bound as 7 bytes. So result is cut off at 7 byte.
320
+ #
321
+ # In case of binding a string as RAW, set OCI::RAW to +type+.
322
+ #
323
+ # example:
324
+ # cursor = conn.parse("INSERT INTO raw_table(raw_column) VALUE (:1)")
325
+ # cursor.bind_param(1, 'RAW_STRING', OCI8::RAW)
326
+ # cursor.exec()
327
+ # cursor.close()
328
+ def bind_param(key, param, type = nil, length = nil)
329
+ case param
330
+ when Hash
331
+ when Class
332
+ param = {:value => nil, :type => param, :length => length}
333
+ else
334
+ param = {:value => param, :type => type, :length => length}
335
+ end
336
+ __bind(key, make_bind_object(param))
337
+ self
338
+ end # bind_param
339
+
340
+ # Executes the SQL statement assigned the cursor. The type of
341
+ # return value depends on the type of sql statement: select;
342
+ # insert, update and delete; create, alter, drop and PL/SQL.
343
+ #
344
+ # In case of select statement, it returns the number of the
345
+ # select-list.
346
+ #
347
+ # In case of insert, update or delete statement, it returns the
348
+ # number of processed rows.
349
+ #
350
+ # In case of create, alter, drop and PL/SQL statement, it returns
351
+ # true. In contrast with OCI8#exec, it returns true even
352
+ # though PL/SQL. Use OCI8::Cursor#[] explicitly to get bind
353
+ # variables.
354
+ def exec(*bindvars)
355
+ bind_params(*bindvars)
356
+ __execute(nil) # Pass a nil to specify the statement isn't an Array DML
357
+ case type
358
+ when :select_stmt
359
+ define_columns()
360
+ else
361
+ row_count
362
+ end
363
+ end # exec
364
+
365
+ # Set the maximum array size for bind_param_array
366
+ #
367
+ # All the binds will be clean from cursor if instance variable max_array_size is set before
368
+ #
369
+ # Instance variable actual_array_size holds the size of the arrays users actually binds through bind_param_array
370
+ # all the binding arrays are required to be the same size
371
+ def max_array_size=(size)
372
+ raise "expect positive number for max_array_size." if size.nil? && size <=0
373
+ __clearBinds if !@max_array_size.nil?
374
+ @max_array_size = size
375
+ @actual_array_size = nil
376
+ end # max_array_size=
377
+
378
+ # Bind array explicitly
379
+ #
380
+ # When key is number, it binds by position, which starts from 1.
381
+ # When key is string, it binds by the name of placeholder.
382
+ #
383
+ # The max_array_size should be set before calling bind_param_array
384
+ #
385
+ # example:
386
+ # cursor = conn.parse("INSERT INTO test_table VALUES (:str)")
387
+ # cursor.max_array_size = 3
388
+ # cursor.bind_param_array(1, ['happy', 'new', 'year'], String, 30)
389
+ # cursor.exec_array
390
+ def bind_param_array(key, var_array, type = nil, max_item_length = nil)
391
+ raise "please call max_array_size= first." if @max_array_size.nil?
392
+ raise "expect array as input param for bind_param_array." if !var_array.nil? && !(var_array.is_a? Array)
393
+ raise "the size of var_array should not be greater than max_array_size." if !var_array.nil? && var_array.size > @max_array_size
394
+
395
+ if var_array.nil?
396
+ raise "all binding arrays should be the same size." unless @actual_array_size.nil? || @actual_array_size == 0
397
+ @actual_array_size = 0
398
+ else
399
+ raise "all binding arrays should be the same size." unless @actual_array_size.nil? || var_array.size == @actual_array_size
400
+ @actual_array_size = var_array.size if @actual_array_size.nil?
401
+ end
402
+
403
+ param = {:value => var_array, :type => type, :length => max_item_length, :max_array_size => @max_array_size}
404
+ first_non_nil_elem = var_array.nil? ? nil : var_array.find{|x| x!= nil}
405
+
406
+ if type.nil?
407
+ if first_non_nil_elem.nil?
408
+ raise "bind type is not given."
409
+ else
410
+ type = first_non_nil_elem.class
411
+ end
412
+ end
413
+
414
+ bindclass = OCI8::BindType::Mapping[type]
415
+ raise "unsupported dataType: #{type}" if bindclass.nil?
416
+ bindobj = bindclass.create(@con, var_array, param, @max_array_size)
417
+ __bind(key, bindobj)
418
+ self
419
+ end # bind_param_array
420
+
421
+ # Executes the SQL statement assigned the cursor with array binding
422
+ def exec_array
423
+ raise "please call max_array_size= first." if @max_array_size.nil?
424
+
425
+ if !@actual_array_size.nil? && @actual_array_size > 0
426
+ __execute(@actual_array_size)
427
+ else
428
+ raise "please set non-nil values to array binding parameters"
429
+ end
430
+
431
+ case type
432
+ when :update_stmt, :delete_stmt, :insert_stmt
433
+ row_count
434
+ else
435
+ true
436
+ end
437
+ end # exec_array
438
+
439
+ # Gets the names of select-list as array. Please use this
440
+ # method after exec.
441
+ def get_col_names
442
+ @names ||= @column_metadata.collect { |md| md.name }
443
+ end # get_col_names
444
+
445
+ # call-seq:
446
+ # column_metadata -> column information
447
+ #
448
+ # (new in 1.0.0 and 2.0)
449
+ #
450
+ # Gets an array of OCI8::Metadata::Column of a select statement.
451
+ #
452
+ # example:
453
+ # cursor = conn.exec('select * from tab')
454
+ # puts ' Name Type'
455
+ # puts ' ----------------------------------------- ----------------------------'
456
+ # cursor.column_metadata.each do |colinfo|
457
+ # puts format(' %-41s %s',
458
+ # colinfo.name,
459
+ # colinfo.type_string)
460
+ # end
461
+ def column_metadata
462
+ @column_metadata
463
+ end
464
+
465
+ # call-seq:
466
+ # fetch_hash
467
+ #
468
+ # get fetched data as a Hash. The hash keys are column names.
469
+ # If a block is given, acts as an iterator.
470
+ def fetch_hash
471
+ if iterator?
472
+ while ret = fetch_a_hash_row()
473
+ yield(ret)
474
+ end
475
+ else
476
+ fetch_a_hash_row
477
+ end
478
+ end # fetch_hash
479
+
480
+ # close the cursor.
481
+ def close
482
+ free()
483
+ @names = nil
484
+ @column_metadata = nil
485
+ end # close
486
+
487
+ private
488
+
489
+ def make_bind_object(param)
490
+ case param
491
+ when Hash
492
+ key = param[:type]
493
+ val = param[:value]
494
+ max_array_size = param[:max_array_size]
495
+
496
+ if key.nil?
497
+ if val.nil?
498
+ raise "bind type is not given."
499
+ elsif val.is_a? OCI8::Object::Base
500
+ key = :named_type
501
+ param = @con.get_tdo_by_class(val.class)
502
+ else
503
+ key = val.class
504
+ end
505
+ elsif key.class == Class && key < OCI8::Object::Base
506
+ param = @con.get_tdo_by_class(key)
507
+ key = :named_type
508
+ end
509
+ when OCI8::Metadata::Base
510
+ key = param.data_type
511
+ case key
512
+ when :named_type
513
+ if param.type_name == 'XMLTYPE'
514
+ key = :xmltype
515
+ else
516
+ param = @con.get_tdo_by_metadata(param.type_metadata)
517
+ end
518
+ end
519
+ else
520
+ raise "unknown param #{param.intern}"
521
+ end
522
+
523
+ bindclass = OCI8::BindType::Mapping[key]
524
+ raise "unsupported datatype: #{key}" if bindclass.nil?
525
+ bindclass.create(@con, val, param, max_array_size)
526
+ end
527
+
528
+ def define_columns
529
+ num_cols = __param_count
530
+ 1.upto(num_cols) do |i|
531
+ parm = __paramGet(i)
532
+ define_one_column(i, parm) unless __defined?(i)
533
+ @column_metadata[i - 1] = parm
534
+ end
535
+ num_cols
536
+ end # define_columns
537
+
538
+ def define_one_column(pos, param)
539
+ __define(pos, make_bind_object(param))
540
+ end # define_one_column
541
+
542
+ def bind_params(*bindvars)
543
+ bindvars.each_with_index do |val, i|
544
+ if val.is_a? Array
545
+ bind_param(i + 1, val[0], val[1], val[2])
546
+ else
547
+ bind_param(i + 1, val)
548
+ end
549
+ end
550
+ end # bind_params
551
+
552
+ def fetch_a_hash_row
553
+ if rs = fetch()
554
+ ret = {}
555
+ get_col_names.each do |name|
556
+ ret[name] = rs.shift
557
+ end
558
+ ret
559
+ else
560
+ nil
561
+ end
562
+ end # fetch_a_hash_row
563
+
564
+ end # OCI8::Cursor
565
+ end # OCI8
566
+
567
+ class OraDate
568
+ def to_time
569
+ begin
570
+ Time.local(year, month, day, hour, minute, second)
571
+ rescue ArgumentError
572
+ msg = format("out of range of Time (expect between 1970-01-01 00:00:00 UTC and 2037-12-31 23:59:59, but %04d-%02d-%02d %02d:%02d:%02d %s)", year, month, day, hour, minute, second, Time.at(0).zone)
573
+ raise RangeError.new(msg)
574
+ end
575
+ end
576
+
577
+ def to_date
578
+ Date.new(year, month, day)
579
+ end
580
+
581
+ if defined? DateTime # ruby 1.8.0 or upper
582
+
583
+ # get timezone offset.
584
+ @@tz_offset = Time.now.utc_offset.to_r/86400
585
+
586
+ def to_datetime
587
+ DateTime.new(year, month, day, hour, minute, second, @@tz_offset)
588
+ end
589
+ end
590
+
591
+ def yaml_initialize(type, val) # :nodoc:
592
+ initialize(*val.split(/[ -\/:]+/).collect do |i| i.to_i end)
593
+ end
594
+
595
+ def to_yaml(opts = {}) # :nodoc:
596
+ YAML.quick_emit(object_id, opts) do |out|
597
+ out.scalar(taguri, self.to_s, :plain)
598
+ end
599
+ end
600
+
601
+ def to_json(options=nil) # :nodoc:
602
+ to_datetime.to_json(options)
603
+ end
604
+ end
605
+
606
+ class OraNumber
607
+ def yaml_initialize(type, val) # :nodoc:
608
+ initialize(val)
609
+ end
610
+
611
+ def to_yaml(opts = {}) # :nodoc:
612
+ YAML.quick_emit(object_id, opts) do |out|
613
+ out.scalar(taguri, self.to_s, :plain)
614
+ end
615
+ end
616
+
617
+ def to_json(options=nil) # :nodoc:
618
+ to_s
619
+ end
620
+ end
621
+
622
+ class Numeric
623
+ def to_onum
624
+ OraNumber.new(self)
625
+ end
626
+ end
627
+
628
+ class String
629
+ def to_onum(format = nil, nls_params = nil)
630
+ OraNumber.new(self, format, nls_params)
631
+ end
632
+ end
633
+
634
+ # bind or explicitly define
635
+ OCI8::BindType::Mapping[String] = OCI8::BindType::String
636
+ OCI8::BindType::Mapping[OraNumber] = OCI8::BindType::OraNumber
637
+ OCI8::BindType::Mapping[Fixnum] = OCI8::BindType::Integer
638
+ OCI8::BindType::Mapping[Float] = OCI8::BindType::Float
639
+ OCI8::BindType::Mapping[Integer] = OCI8::BindType::Integer
640
+ OCI8::BindType::Mapping[Bignum] = OCI8::BindType::Integer
641
+ OCI8::BindType::Mapping[OraDate] = OCI8::BindType::OraDate
642
+ OCI8::BindType::Mapping[Time] = OCI8::BindType::Time
643
+ OCI8::BindType::Mapping[Date] = OCI8::BindType::Date
644
+ OCI8::BindType::Mapping[DateTime] = OCI8::BindType::DateTime
645
+ OCI8::BindType::Mapping[OCI8::CLOB] = OCI8::BindType::CLOB
646
+ OCI8::BindType::Mapping[OCI8::NCLOB] = OCI8::BindType::NCLOB
647
+ OCI8::BindType::Mapping[OCI8::BLOB] = OCI8::BindType::BLOB
648
+ OCI8::BindType::Mapping[OCI8::BFILE] = OCI8::BindType::BFILE
649
+ OCI8::BindType::Mapping[OCI8::Cursor] = OCI8::BindType::Cursor
650
+
651
+ # implicitly define
652
+
653
+ # datatype type size prec scale
654
+ # -------------------------------------------------
655
+ # CHAR(1) SQLT_AFC 1 0 0
656
+ # CHAR(10) SQLT_AFC 10 0 0
657
+ OCI8::BindType::Mapping[:char] = OCI8::BindType::String
658
+
659
+ # datatype type size prec scale
660
+ # -------------------------------------------------
661
+ # VARCHAR(1) SQLT_CHR 1 0 0
662
+ # VARCHAR(10) SQLT_CHR 10 0 0
663
+ # VARCHAR2(1) SQLT_CHR 1 0 0
664
+ # VARCHAR2(10) SQLT_CHR 10 0 0
665
+ OCI8::BindType::Mapping[:varchar2] = OCI8::BindType::String
666
+
667
+ # datatype type size prec scale
668
+ # -------------------------------------------------
669
+ # RAW(1) SQLT_BIN 1 0 0
670
+ # RAW(10) SQLT_BIN 10 0 0
671
+ OCI8::BindType::Mapping[:raw] = OCI8::BindType::RAW
672
+
673
+ # datatype type size prec scale
674
+ # -------------------------------------------------
675
+ # LONG SQLT_LNG 0 0 0
676
+ OCI8::BindType::Mapping[:long] = OCI8::BindType::Long
677
+
678
+ # datatype type size prec scale
679
+ # -------------------------------------------------
680
+ # LONG RAW SQLT_LBI 0 0 0
681
+ OCI8::BindType::Mapping[:long_raw] = OCI8::BindType::LongRaw
682
+
683
+ # datatype type size prec scale
684
+ # -------------------------------------------------
685
+ # CLOB SQLT_CLOB 4000 0 0
686
+ OCI8::BindType::Mapping[:clob] = OCI8::BindType::CLOB
687
+ OCI8::BindType::Mapping[:nclob] = OCI8::BindType::NCLOB
688
+
689
+ # datatype type size prec scale
690
+ # -------------------------------------------------
691
+ # BLOB SQLT_BLOB 4000 0 0
692
+ OCI8::BindType::Mapping[:blob] = OCI8::BindType::BLOB
693
+
694
+ # datatype type size prec scale
695
+ # -------------------------------------------------
696
+ # BFILE SQLT_BFILE 4000 0 0
697
+ OCI8::BindType::Mapping[:bfile] = OCI8::BindType::BFILE
698
+
699
+ # datatype type size prec scale
700
+ # -------------------------------------------------
701
+ # DATE SQLT_DAT 7 0 0
702
+ OCI8::BindType::Mapping[:date] = OCI8::BindType::Time
703
+
704
+ if OCI8.oracle_client_version >= OCI8::ORAVER_9_0
705
+ OCI8::BindType::Mapping[:timestamp] = OCI8::BindType::Time
706
+ OCI8::BindType::Mapping[:timestamp_tz] = OCI8::BindType::DateTime
707
+ OCI8::BindType::Mapping[:timestamp_ltz] = OCI8::BindType::Time
708
+ OCI8::BindType::Mapping[:interval_ym] = OCI8::BindType::IntervalYM
709
+ OCI8::BindType::Mapping[:interval_ds] = OCI8::BindType::IntervalDS
710
+ end
711
+
712
+ # datatype type size prec scale
713
+ # -------------------------------------------------
714
+ # ROWID SQLT_RDD 4 0 0
715
+ OCI8::BindType::Mapping[:rowid] = OCI8::BindType::String
716
+
717
+ # datatype type size prec scale
718
+ # -----------------------------------------------------
719
+ # FLOAT SQLT_NUM 22 126 -127
720
+ # FLOAT(1) SQLT_NUM 22 1 -127
721
+ # FLOAT(126) SQLT_NUM 22 126 -127
722
+ # DOUBLE PRECISION SQLT_NUM 22 126 -127
723
+ # REAL SQLT_NUM 22 63 -127
724
+ # NUMBER SQLT_NUM 22 0 0
725
+ # NUMBER(1) SQLT_NUM 22 1 0
726
+ # NUMBER(38) SQLT_NUM 22 38 0
727
+ # NUMBER(1, 0) SQLT_NUM 22 1 0
728
+ # NUMBER(38, 0) SQLT_NUM 22 38 0
729
+ # NUMERIC SQLT_NUM 22 38 0
730
+ # INT SQLT_NUM 22 38 0
731
+ # INTEGER SQLT_NUM 22 38 0
732
+ # SMALLINT SQLT_NUM 22 38 0
733
+ OCI8::BindType::Mapping[:number] = OCI8::BindType::Number
734
+
735
+ # mapping for calculated number values.
736
+ #
737
+ # for example:
738
+ # select col1 * 1.1 from tab1;
739
+ #
740
+ # For Oracle 9.2.0.2 or below, this is also used for NUMBER
741
+ # datatypes that have no explicit setting of their precision
742
+ # and scale.
743
+ #
744
+ # The default mapping is Float for ruby-oci8 1.0. It is OraNumber
745
+ # for ruby-oci8 2.0.
746
+ OCI8::BindType::Mapping[:number_unknown_prec] = OCI8::BindType::OraNumber
747
+
748
+ # mapping for number without precision and scale.
749
+ #
750
+ # for example:
751
+ # create table tab1 (col1 number);
752
+ # select col1 from tab1;
753
+ #
754
+ # note: This is available only on Oracle 9.2.0.3 or above.
755
+ # see: Oracle 9.2.0.x Patch Set Notes.
756
+ #
757
+ # The default mapping is Float for ruby-oci8 1.0. It is OraNumber
758
+ # for ruby-oci8 2.0.
759
+ OCI8::BindType::Mapping[:number_no_prec_setting] = OCI8::BindType::OraNumber
760
+
761
+ if defined? OCI8::BindType::BinaryDouble
762
+ OCI8::BindType::Mapping[:binary_float] = OCI8::BindType::BinaryDouble
763
+ OCI8::BindType::Mapping[:binary_double] = OCI8::BindType::BinaryDouble
764
+ else
765
+ OCI8::BindType::Mapping[:binary_float] = OCI8::BindType::Float
766
+ OCI8::BindType::Mapping[:binary_double] = OCI8::BindType::Float
767
+ end
768
+
769
+ # Cursor
770
+ OCI8::BindType::Mapping[:cursor] = OCI8::BindType::Cursor
771
+
772
+ # XMLType (This mapping will be changed before release.)
773
+ OCI8::BindType::Mapping[:xmltype] = OCI8::BindType::Long