ruby-oci8 2.2.10-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +14 -0
  3. data/COPYING +30 -0
  4. data/COPYING_old +64 -0
  5. data/ChangeLog +3826 -0
  6. data/Makefile +92 -0
  7. data/NEWS +1209 -0
  8. data/README.md +66 -0
  9. data/dist-files +112 -0
  10. data/docs/bind-array-to-in_cond.md +38 -0
  11. data/docs/conflicts-local-connections-and-processes.md +98 -0
  12. data/docs/hanging-after-inactivity.md +63 -0
  13. data/docs/install-binary-package.md +44 -0
  14. data/docs/install-full-client.md +111 -0
  15. data/docs/install-instant-client.md +194 -0
  16. data/docs/install-on-osx.md +46 -0
  17. data/docs/ldap-auth-and-function-interposition.md +123 -0
  18. data/docs/number-type-mapping.md +79 -0
  19. data/docs/platform-specific-issues.md +164 -0
  20. data/docs/report-installation-issue.md +50 -0
  21. data/docs/timeout-parameters.md +94 -0
  22. data/lib/.document +1 -0
  23. data/lib/dbd/OCI8.rb +591 -0
  24. data/lib/oci8/.document +8 -0
  25. data/lib/oci8/bindtype.rb +333 -0
  26. data/lib/oci8/check_load_error.rb +146 -0
  27. data/lib/oci8/compat.rb +117 -0
  28. data/lib/oci8/connection_pool.rb +179 -0
  29. data/lib/oci8/cursor.rb +605 -0
  30. data/lib/oci8/datetime.rb +605 -0
  31. data/lib/oci8/encoding-init.rb +45 -0
  32. data/lib/oci8/encoding.yml +537 -0
  33. data/lib/oci8/metadata.rb +2148 -0
  34. data/lib/oci8/object.rb +641 -0
  35. data/lib/oci8/oci8.rb +756 -0
  36. data/lib/oci8/ocihandle.rb +591 -0
  37. data/lib/oci8/oracle_version.rb +153 -0
  38. data/lib/oci8/properties.rb +196 -0
  39. data/lib/oci8/version.rb +3 -0
  40. data/lib/oci8.rb +190 -0
  41. data/lib/oci8lib_310.so +0 -0
  42. data/lib/ruby-oci8.rb +1 -0
  43. data/metaconfig +142 -0
  44. data/pre-distclean.rb +7 -0
  45. data/ruby-oci8.gemspec +85 -0
  46. data/setup.rb +1342 -0
  47. data/test/README.md +37 -0
  48. data/test/config.rb +201 -0
  49. data/test/setup_test_object.sql +199 -0
  50. data/test/setup_test_package.sql +59 -0
  51. data/test/test_all.rb +56 -0
  52. data/test/test_appinfo.rb +62 -0
  53. data/test/test_array_dml.rb +332 -0
  54. data/test/test_bind_array.rb +70 -0
  55. data/test/test_bind_boolean.rb +99 -0
  56. data/test/test_bind_integer.rb +47 -0
  57. data/test/test_bind_raw.rb +45 -0
  58. data/test/test_bind_string.rb +105 -0
  59. data/test/test_bind_time.rb +177 -0
  60. data/test/test_break.rb +125 -0
  61. data/test/test_clob.rb +85 -0
  62. data/test/test_connection_pool.rb +124 -0
  63. data/test/test_connstr.rb +220 -0
  64. data/test/test_datetime.rb +585 -0
  65. data/test/test_dbi.rb +365 -0
  66. data/test/test_dbi_clob.rb +53 -0
  67. data/test/test_encoding.rb +103 -0
  68. data/test/test_error.rb +87 -0
  69. data/test/test_metadata.rb +2674 -0
  70. data/test/test_object.rb +546 -0
  71. data/test/test_oci8.rb +624 -0
  72. data/test/test_oracle_version.rb +68 -0
  73. data/test/test_oradate.rb +255 -0
  74. data/test/test_oranumber.rb +792 -0
  75. data/test/test_package_type.rb +981 -0
  76. data/test/test_properties.rb +17 -0
  77. data/test/test_rowid.rb +32 -0
  78. metadata +123 -0
@@ -0,0 +1,605 @@
1
+ # oci8.rb -- OCI8::Cursor
2
+ #
3
+ # Copyright (C) 2002-2012 KUBO Takehiro <kubo@jiubao.org>
4
+ #
5
+
6
+ #
7
+ class OCI8
8
+
9
+ # The instance of this class corresponds to cursor in the term of
10
+ # Oracle, which corresponds to java.sql.Statement of JDBC and statement
11
+ # handle $sth of Perl/DBI.
12
+ #
13
+ # Don't create the instance by calling 'new' method. Please create it by
14
+ # calling OCI8#exec or OCI8#parse.
15
+ class Cursor
16
+
17
+ # @note Don't use this constructor. Use {OCI8#parse} instead.
18
+ #
19
+ # @param [OCI8] conn connection
20
+ # @param [String] sql SQL statement
21
+ def initialize(conn, sql = nil)
22
+ @bind_handles = {}
23
+ @define_handles = []
24
+ @column_metadata = []
25
+ @names = nil
26
+ @con = conn
27
+ @max_array_size = nil
28
+ @fetch_array_size = nil
29
+ @rowbuf_size = 0
30
+ @rowbuf_index = 0
31
+ __initialize(conn, sql) # Initialize the internal C structure.
32
+ self.prefetch_rows = conn.instance_variable_get(:@prefetch_rows)
33
+ end
34
+
35
+ # explicitly indicate the date type of fetched value. run this
36
+ # method within parse and exec. pos starts from 1. lentgh is used
37
+ # when type is String.
38
+ #
39
+ # example:
40
+ # cursor = conn.parse("SELECT ename, hiredate FROM emp")
41
+ # cursor.define(1, String, 20) # fetch the first column as String.
42
+ # cursor.define(2, Time) # fetch the second column as Time.
43
+ # cursor.exec()
44
+ def define(pos, type, length = nil)
45
+ bindobj = make_bind_object({:type => type, :length => length}, @fetch_array_size || 1)
46
+ __define(pos, bindobj)
47
+ if old = @define_handles[pos - 1]
48
+ old.send(:free)
49
+ end
50
+ @define_handles[pos - 1] = bindobj
51
+ self
52
+ end
53
+
54
+ # Binds variables explicitly.
55
+ #
56
+ # When key is number, it binds by position, which starts from 1.
57
+ # When key is string, it binds by the name of placeholder.
58
+ #
59
+ # example:
60
+ # cursor = conn.parse("SELECT * FROM emp WHERE ename = :ename")
61
+ # cursor.bind_param(1, 'SMITH') # bind by position
62
+ # # ...or...
63
+ # cursor.bind_param(':ename', 'SMITH') # bind by name
64
+ #
65
+ # To bind as number, set the number intself to +val+. If its initial value
66
+ # is NULL, please set nil to +type+ and Integer, Float or OraNumber to +val+.
67
+ #
68
+ # example:
69
+ # cursor.bind_param(1, 1234) # bind as Integer, Initial value is 1234.
70
+ # cursor.bind_param(1, 1234.0) # bind as Float, Initial value is 1234.0.
71
+ # cursor.bind_param(1, nil, Integer) # bind as Integer, Initial value is NULL.
72
+ # cursor.bind_param(1, nil, Float) # bind as Float, Initial value is NULL.
73
+ # cursor.bind_param(1, OraNumber(1234)) # bind as OraNumber, Initial value is 1234.
74
+ # cursor.bind_param(1, nil, OraNumber) # bind as OraNumber, Initial value is NULL.
75
+ #
76
+ # In case of binding a string, set the string itself to
77
+ # +val+. When the bind variable is used as output, set the
78
+ # string whose length is enough to store or set the length.
79
+ #
80
+ # example:
81
+ # cursor = conn.parse("BEGIN :out := :in || '_OUT'; END;")
82
+ # cursor.bind_param(':in', 'DATA') # bind as String with width 4.
83
+ # cursor.bind_param(':out', nil, String, 7) # bind as String with width 7.
84
+ # cursor.exec()
85
+ # p cursor[':out'] # => 'DATA_OU'
86
+ # # Though the length of :out is 8 bytes in PL/SQL block, it is
87
+ # # bound as 7 bytes. So result is cut off at 7 byte.
88
+ #
89
+ # In case of binding a string as RAW, set OCI::RAW to +type+.
90
+ #
91
+ # example:
92
+ # cursor = conn.parse("INSERT INTO raw_table(raw_column) VALUE (:1)")
93
+ # cursor.bind_param(1, 'RAW_STRING', OCI8::RAW)
94
+ # cursor.exec()
95
+ # cursor.close()
96
+ def bind_param(key, param, type = nil, length = nil)
97
+ case param
98
+ when Hash
99
+ when Class
100
+ param = {:value => nil, :type => param, :length => length}
101
+ else
102
+ param = {:value => param, :type => type, :length => length}
103
+ end
104
+ bindobj = make_bind_object(param)
105
+ __bind(key, bindobj)
106
+ if old = @bind_handles[key]
107
+ old.send(:free)
108
+ end
109
+ @bind_handles[key] = bindobj
110
+ self
111
+ end
112
+
113
+ # Executes the SQL statement assigned the cursor. The type of
114
+ # return value depends on the type of sql statement: select;
115
+ # insert, update and delete; create, alter, drop and PL/SQL.
116
+ #
117
+ # In case of select statement, it returns the number of the
118
+ # select-list.
119
+ #
120
+ # In case of insert, update or delete statement, it returns the
121
+ # number of processed rows.
122
+ #
123
+ # In case of create, alter, drop and PL/SQL statement, it returns
124
+ # true. In contrast with OCI8#exec, it returns true even
125
+ # though PL/SQL. Use OCI8::Cursor#[] explicitly to get bind
126
+ # variables.
127
+ def exec(*bindvars)
128
+ bind_params(*bindvars)
129
+ case type
130
+ when :select_stmt
131
+ __execute(0)
132
+ define_columns() if @column_metadata.size == 0
133
+ @rowbuf_size = 0
134
+ @rowbuf_index = 0
135
+ @column_metadata.size
136
+ else
137
+ __execute(1)
138
+ row_count
139
+ end
140
+ end
141
+
142
+ # Gets fetched data as array. This is available for select
143
+ # statement only.
144
+ #
145
+ # @example
146
+ # conn = OCI8.new('scott', 'tiger')
147
+ # cursor = conn.exec('SELECT * FROM emp')
148
+ # while r = cursor.fetch()
149
+ # puts r.join(',')
150
+ # end
151
+ # cursor.close
152
+ # conn.logoff
153
+ #
154
+ # @return [Array]
155
+ def fetch
156
+ if block_given?
157
+ while row = fetch_one_row_as_array
158
+ yield row
159
+ end
160
+ self
161
+ else
162
+ fetch_one_row_as_array
163
+ end
164
+ end
165
+
166
+ # Gets fetched data as a Hash. The hash keys are column names.
167
+ # If a block is given, acts as an iterator.
168
+ #
169
+ # @return [Hash] the hash keys are column names and hash values are column values
170
+ def fetch_hash
171
+ if block_given?
172
+ while row = fetch_one_row_as_hash()
173
+ yield row
174
+ end
175
+ else
176
+ fetch_one_row_as_hash
177
+ end
178
+ end
179
+
180
+ # Gets the value of the bind variable.
181
+ #
182
+ # When bind variables are explicitly bound by {OCI8::Cursor#bind_param},
183
+ # the subscript +key+ must be same with the parameter +key+ passed to {OCI8::Cursor#bind_param}.
184
+ #
185
+ # When they are implicitly bound by {OCI8#exec} or {OCI8::Cursor#exec},
186
+ # the subscript +key+ is the position which starts from one.
187
+ #
188
+ # @example explicitly bind by name
189
+ # cursor = conn.parse("BEGIN :out := 'BAR'; END;")
190
+ # cursor.bind_param(:out, 'FOO') # bind by name
191
+ # p cursor[:out] # => 'FOO' - The subscript must be :out.
192
+ # cursor.exec()
193
+ # p cursor[:out] # => 'BAR'
194
+ #
195
+ # @example explicitly bind by position
196
+ # cursor = conn.parse("BEGIN :out := 'BAR'; END;")
197
+ # cursor.bind_param(1, 'FOO') # bind by position
198
+ # p cursor[1] # => 'FOO' - The subscript must be 1.
199
+ # cursor.exec()
200
+ # p cursor[1] # => 'BAR'
201
+ #
202
+ # @example implicitly bind
203
+ # cursor = conn.exec("BEGIN :out := 'BAR'; END;", 'FOO')
204
+ # # 1st bind variable is bound as String with width 3. Its initial value is 'FOO'
205
+ # # After execute, the value become 'BAR'.
206
+ # p cursor[1] # => 'BAR'
207
+ #
208
+ # @param [Object] key bind key
209
+ # @return [Object] the value of the bind variable
210
+ #
211
+ def [](key)
212
+ handle = @bind_handles[key]
213
+ handle && handle.send(:get_data)
214
+ end
215
+
216
+ # Changes the bind variable value.
217
+ #
218
+ # When bind variables are explicitly bound by {OCI8::Cursor#bind_param},
219
+ # the subscript +key+ must be same with the parameter +key+ passed to {OCI8::Cursor#bind_param}.
220
+ #
221
+ # When they are implicitly bound by {OCI8#exec} or {OCI8::Cursor#exec},
222
+ # the subscript +key+ is the position which starts from one.
223
+ #
224
+ # @example
225
+ # # Inserts three rows whose values are 'FOO', 'BAR' and 'BAZ.'
226
+ # cursor = conn.parse("INSERT INTO test(col1) VALUES(:1)")
227
+ # begin
228
+ # cursor.bind_params(1, nil, String, 3)
229
+ # ['FOO', 'BAR', 'BAZ'].each do |column_value|
230
+ # cursor[1] = column_value # Change the bind value
231
+ # cursor.exec # and insert it.
232
+ # end
233
+ # ensure
234
+ # cursor.close()
235
+ # end
236
+ # # This makes same result with the following but is more efficient.
237
+ # #
238
+ # # ['FOO', 'BAR', 'BAZ'].each do |column_value|
239
+ # # conn.exec("INSERT INTO test(col1) VALUES(:1)", column_value)
240
+ # # end
241
+ # #
242
+ #
243
+ # @param [Object] key bind key
244
+ # @param [Object] val bind value
245
+ #
246
+ def []=(key, val)
247
+ handle = @bind_handles[key]
248
+ return nil if handle.nil?
249
+
250
+ if val.is_a? Array
251
+ if @actual_array_size > 0 && val.length != @actual_array_size
252
+ raise RuntimeError, "all binding arrays hould be the same size"
253
+ end
254
+ if @actual_array_size == 0 && val.length <= @max_array_size
255
+ @actual_array_size = val.length
256
+ end
257
+ end
258
+ handle.send(:set_data, val)
259
+ val
260
+ end
261
+
262
+ # Set the maximum array size for bind_param_array
263
+ #
264
+ # All the binds will be clean from cursor if instance variable max_array_size is set before
265
+ #
266
+ # Instance variable actual_array_size holds the size of the arrays users actually binds through bind_param_array
267
+ # all the binding arrays are required to be the same size
268
+ def max_array_size=(size)
269
+ raise "expect positive number for max_array_size." if size.nil? && size <=0
270
+ free_bind_handles() if !@max_array_size.nil?
271
+ @max_array_size = size
272
+ @actual_array_size = nil
273
+ end
274
+
275
+ # Binds array explicitly
276
+ #
277
+ # When key is number, it binds by position, which starts from 1.
278
+ # When key is string, it binds by the name of placeholder.
279
+ #
280
+ # The max_array_size should be set before calling bind_param_array
281
+ #
282
+ # @example
283
+ # cursor = conn.parse("INSERT INTO test_table VALUES (:str)")
284
+ # cursor.max_array_size = 3
285
+ # cursor.bind_param_array(1, ['happy', 'new', 'year'], String, 30)
286
+ # cursor.exec_array
287
+ def bind_param_array(key, var_array, type = nil, max_item_length = nil)
288
+ raise "please call max_array_size= first." if @max_array_size.nil?
289
+ raise "expect array as input param for bind_param_array." if !var_array.nil? && !(var_array.is_a? Array)
290
+ raise "the size of var_array should not be greater than max_array_size." if !var_array.nil? && var_array.size > @max_array_size
291
+
292
+ if var_array.nil?
293
+ raise "all binding arrays should be the same size." unless @actual_array_size.nil? || @actual_array_size == 0
294
+ @actual_array_size = 0
295
+ else
296
+ raise "all binding arrays should be the same size." unless @actual_array_size.nil? || var_array.size == @actual_array_size
297
+ @actual_array_size = var_array.size if @actual_array_size.nil?
298
+ end
299
+
300
+ param = {:value => var_array, :type => type, :length => max_item_length, :max_array_size => @max_array_size}
301
+ first_non_nil_elem = var_array.nil? ? nil : var_array.find{|x| x!= nil}
302
+
303
+ if type.nil?
304
+ if first_non_nil_elem.nil?
305
+ raise "bind type is not given."
306
+ else
307
+ type = first_non_nil_elem.class
308
+ end
309
+ end
310
+
311
+ bindclass = OCI8::BindType::Mapping[type]
312
+ if bindclass.nil? and type.is_a? Class
313
+ bindclass = OCI8::BindType::Mapping[type.to_s]
314
+ OCI8::BindType::Mapping[type] = bindclass if bindclass
315
+ end
316
+ raise "unsupported dataType: #{type}" if bindclass.nil?
317
+ bindobj = bindclass.create(@con, var_array, param, @max_array_size)
318
+ __bind(key, bindobj)
319
+ #
320
+ if old = @bind_handles[key]
321
+ old.send(:free)
322
+ end
323
+ @bind_handles[key] = bindobj
324
+ self
325
+ end
326
+
327
+ # Executes the SQL statement assigned the cursor with array binding
328
+ def exec_array
329
+ raise "please call max_array_size= first." if @max_array_size.nil?
330
+
331
+ if !@actual_array_size.nil? && @actual_array_size > 0
332
+ __execute(@actual_array_size)
333
+ else
334
+ raise "please set non-nil values to array binding parameters"
335
+ end
336
+
337
+ case type
338
+ when :update_stmt, :delete_stmt, :insert_stmt
339
+ row_count
340
+ else
341
+ true
342
+ end
343
+ end
344
+
345
+ # Gets the names of select-list as array. Please use this
346
+ # method after exec.
347
+ def get_col_names
348
+ @names ||= @column_metadata.collect { |md| md.name }
349
+ end
350
+
351
+ # Gets an array of OCI8::Metadata::Column of a select statement.
352
+ #
353
+ # @example
354
+ # cursor = conn.exec('select * from tab')
355
+ # puts ' Name Type'
356
+ # puts ' ----------------------------------------- ----------------------------'
357
+ # cursor.column_metadata.each do |colinfo|
358
+ # puts format(' %-41s %s',
359
+ # colinfo.name,
360
+ # colinfo.type_string)
361
+ # end
362
+ #
363
+ # @return [Array of OCI8::Metadata::Column]
364
+ #
365
+ # @since 1.0.0
366
+ def column_metadata
367
+ @column_metadata
368
+ end
369
+
370
+ # close the cursor.
371
+ def close
372
+ free()
373
+ @names = nil
374
+ @column_metadata = nil
375
+ end
376
+
377
+ # Returns the keys of bind variables.
378
+ #
379
+ # @return [Array] bind variable keys
380
+ def keys
381
+ @bind_handles.keys
382
+ end
383
+
384
+ # Set the number of rows to be prefetched.
385
+ # This can reduce the number of network round trips when fetching
386
+ # many rows. The default value is one.
387
+ #
388
+ # FYI: Rails oracle adaptor uses 100 by default.
389
+ #
390
+ # @param [Integer] rows The number of rows to be prefetched
391
+ def prefetch_rows=(rows)
392
+ attr_set_ub4(11, rows) # OCI_ATTR_PREFETCH_ROWS(11)
393
+ @prefetch_rows = rows
394
+ end
395
+
396
+ if OCI8::oracle_client_version >= ORAVER_12_1
397
+ # Returns the number of processed rows.
398
+ #
399
+ # @return [Integer]
400
+ def row_count
401
+ # https://docs.oracle.com/database/121/LNOCI/ociaahan.htm#sthref5774
402
+ attr_get_ub8(457) # OCI_ATTR_UB8_ROW_COUNT(457)
403
+ end
404
+ else
405
+ def row_count
406
+ # http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5498
407
+ attr_get_ub4(9) # OCI_ATTR_ROW_COUNT(9)
408
+ end
409
+ end
410
+
411
+ # Returns the text of the SQL statement prepared in the cursor.
412
+ #
413
+ # @note
414
+ # When {http://docs.oracle.com/cd/E11882_01/server.112/e10729/ch7progrunicode.htm#CACHHIFE
415
+ # NCHAR String Literal Replacement} is turned on, it returns the modified SQL text,
416
+ # instead of the original SQL text.
417
+ #
418
+ # @example
419
+ # cursor = conn.parse("select * from country where country_code = 'ja'")
420
+ # cursor.statement # => "select * from country where country_code = 'ja'"
421
+ #
422
+ # @return [String] prepared SQL statement
423
+ #
424
+ # @since 2.1.3
425
+ #
426
+ def statement
427
+ # The magic number 144 is OCI_ATTR_STATEMENT.
428
+ # See http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5503
429
+ attr_get_string(144)
430
+ end
431
+
432
+ # gets the type of SQL statement as follows.
433
+ # * OCI8::STMT_SELECT
434
+ # * OCI8::STMT_UPDATE
435
+ # * OCI8::STMT_DELETE
436
+ # * OCI8::STMT_INSERT
437
+ # * OCI8::STMT_CREATE
438
+ # * OCI8::STMT_DROP
439
+ # * OCI8::STMT_ALTER
440
+ # * OCI8::STMT_BEGIN (PL/SQL block which starts with a BEGIN keyword)
441
+ # * OCI8::STMT_DECLARE (PL/SQL block which starts with a DECLARE keyword)
442
+ # * Other Integer value undocumented in Oracle manuals.
443
+ #
444
+ # <em>Changes between ruby-oci8 1.0 and 2.0.</em>
445
+ #
446
+ # [ruby-oci8 2.0] OCI8::STMT_* are Symbols. (:select_stmt, :update_stmt, etc.)
447
+ # [ruby-oci8 1.0] OCI8::STMT_* are Integers. (1, 2, 3, etc.)
448
+ #
449
+ def type
450
+ # http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5506
451
+ stmt_type = attr_get_ub2(24) # OCI_ATTR_STMT_TYPE(24)
452
+ case stmt_type
453
+ when 1 # OCI_STMT_SELECT
454
+ :select_stmt
455
+ when 2 # OCI_STMT_UPDATE
456
+ :update_stmt
457
+ when 3 # OCI_STMT_DELETE
458
+ :delete_stmt
459
+ when 4 # OCI_STMT_INSERT
460
+ :insert_stmt
461
+ when 5 # OCI_STMT_CREATE
462
+ :create_stmt
463
+ when 6 # OCI_STMT_DROP
464
+ :drop_stmt
465
+ when 7 # OCI_STMT_ALTER
466
+ :alter_stmt
467
+ when 8 # OCI_STMT_BEGIN
468
+ :begin_stmt
469
+ when 9 # OCI_STMT_DECLARE
470
+ :declare_stmt
471
+ else
472
+ stmt_type
473
+ end
474
+ end
475
+
476
+ private
477
+
478
+ def make_bind_object(param, fetch_array_size = nil)
479
+ case param
480
+ when Hash
481
+ key = param[:type]
482
+ val = param[:value]
483
+ max_array_size = param[:max_array_size]
484
+
485
+ if key.nil?
486
+ if val.nil?
487
+ raise "bind type is not given."
488
+ elsif val.is_a? OCI8::Object::Base
489
+ key = :named_type
490
+ param = @con.get_tdo_by_class(val.class)
491
+ else
492
+ key = val.class
493
+ end
494
+ elsif key.class == Class && key < OCI8::Object::Base
495
+ param = @con.get_tdo_by_class(key)
496
+ key = :named_type
497
+ elsif key == :named_type
498
+ param = @con.get_tdo_by_typename(param[:length])
499
+ end
500
+ when OCI8::Metadata::Base
501
+ key = param.data_type
502
+ case key
503
+ when :named_type
504
+ if param.type_name == 'XMLTYPE'
505
+ key = :xmltype
506
+ else
507
+ param = @con.get_tdo_by_metadata(param.type_metadata)
508
+ end
509
+ end
510
+ else
511
+ raise "unknown param #{param.intern}"
512
+ end
513
+
514
+ bindclass = OCI8::BindType::Mapping[key]
515
+ if bindclass.nil? and key.is_a? Class
516
+ bindclass = OCI8::BindType::Mapping[key.to_s]
517
+ OCI8::BindType::Mapping[key] = bindclass if bindclass
518
+ end
519
+ raise "unsupported datatype: #{key}" if bindclass.nil?
520
+ bindclass.create(@con, val, param, fetch_array_size || max_array_size)
521
+ end
522
+
523
+ @@use_array_fetch = false
524
+
525
+ def define_columns
526
+ # http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5494
527
+ num_cols = attr_get_ub4(18) # OCI_ATTR_PARAM_COUNT(18)
528
+ @column_metadata = 1.upto(num_cols).collect do |i|
529
+ __paramGet(i)
530
+ end
531
+ if @define_handles.size == 0
532
+ use_array_fetch = @@use_array_fetch
533
+ @column_metadata.each do |md|
534
+ case md.data_type
535
+ when :clob, :blob, :bfile
536
+ # Rows prefetching doesn't work for CLOB, BLOB and BFILE.
537
+ # Use array fetching to get more than one row in a network round trip.
538
+ use_array_fetch = true
539
+ end
540
+ end
541
+ @fetch_array_size = @prefetch_rows if use_array_fetch
542
+ end
543
+ @column_metadata.each_with_index do |md, i|
544
+ define_one_column(i + 1, md) unless @define_handles[i]
545
+ end
546
+ num_cols
547
+ end
548
+
549
+ def define_one_column(pos, param)
550
+ bindobj = make_bind_object(param, @fetch_array_size || 1)
551
+ __define(pos, bindobj)
552
+ @define_handles[pos - 1] = bindobj
553
+ end
554
+
555
+ def bind_params(*bindvars)
556
+ bindvars.each_with_index do |val, i|
557
+ if val.is_a? Array
558
+ bind_param(i + 1, val[0], val[1], val[2])
559
+ else
560
+ bind_param(i + 1, val)
561
+ end
562
+ end
563
+ end
564
+
565
+ def fetch_row_internal
566
+ if @rowbuf_size && @rowbuf_size == @rowbuf_index
567
+ @rowbuf_size = __fetch(@con, @fetch_array_size || 1)
568
+ @rowbuf_index = 0
569
+ end
570
+ @rowbuf_size
571
+ end
572
+
573
+ def fetch_one_row_as_array
574
+ if fetch_row_internal
575
+ ret = @define_handles.collect do |handle|
576
+ handle.send(:get_data, @rowbuf_index)
577
+ end
578
+ @rowbuf_index += 1
579
+ ret
580
+ else
581
+ nil
582
+ end
583
+ end
584
+
585
+ def fetch_one_row_as_hash
586
+ if fetch_row_internal
587
+ ret = {}
588
+ get_col_names.each_with_index do |name, idx|
589
+ ret[name] = @define_handles[idx].send(:get_data, @rowbuf_index)
590
+ end
591
+ @rowbuf_index += 1
592
+ ret
593
+ else
594
+ nil
595
+ end
596
+ end
597
+
598
+ def free_bind_handles
599
+ @bind_handles.each_value do |val|
600
+ val.send(:free)
601
+ end
602
+ @bind_handles.clear
603
+ end
604
+ end
605
+ end