ruby-oci8-master 2.0.7

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 (84) hide show
  1. data/ChangeLog +2321 -0
  2. data/Makefile +88 -0
  3. data/NEWS +303 -0
  4. data/README +76 -0
  5. data/VERSION +1 -0
  6. data/dist-files +83 -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/ext/oci8/.document +18 -0
  13. data/ext/oci8/MANIFEST +18 -0
  14. data/ext/oci8/apiwrap.c.tmpl +182 -0
  15. data/ext/oci8/apiwrap.h.tmpl +61 -0
  16. data/ext/oci8/apiwrap.rb +91 -0
  17. data/ext/oci8/apiwrap.yml +1455 -0
  18. data/ext/oci8/attr.c +105 -0
  19. data/ext/oci8/bind.c +366 -0
  20. data/ext/oci8/connection_pool.c +199 -0
  21. data/ext/oci8/encoding.c +289 -0
  22. data/ext/oci8/env.c +178 -0
  23. data/ext/oci8/error.c +378 -0
  24. data/ext/oci8/extconf.rb +179 -0
  25. data/ext/oci8/lob.c +805 -0
  26. data/ext/oci8/metadata.c +232 -0
  27. data/ext/oci8/object.c +727 -0
  28. data/ext/oci8/oci8.c +1156 -0
  29. data/ext/oci8/oci8.h +574 -0
  30. data/ext/oci8/oci8lib.c +527 -0
  31. data/ext/oci8/ocidatetime.c +484 -0
  32. data/ext/oci8/ocihandle.c +751 -0
  33. data/ext/oci8/ocinumber.c +1612 -0
  34. data/ext/oci8/oraconf.rb +1119 -0
  35. data/ext/oci8/oradate.c +611 -0
  36. data/ext/oci8/oranumber_util.c +352 -0
  37. data/ext/oci8/oranumber_util.h +24 -0
  38. data/ext/oci8/post-config.rb +5 -0
  39. data/ext/oci8/stmt.c +673 -0
  40. data/ext/oci8/thread_util.c +85 -0
  41. data/ext/oci8/thread_util.h +30 -0
  42. data/ext/oci8/win32.c +137 -0
  43. data/lib/.document +1 -0
  44. data/lib/dbd/OCI8.rb +591 -0
  45. data/lib/oci8.rb.in +94 -0
  46. data/lib/oci8/.document +8 -0
  47. data/lib/oci8/bindtype.rb +349 -0
  48. data/lib/oci8/compat.rb +113 -0
  49. data/lib/oci8/connection_pool.rb +99 -0
  50. data/lib/oci8/datetime.rb +611 -0
  51. data/lib/oci8/encoding-init.rb +74 -0
  52. data/lib/oci8/encoding.yml +537 -0
  53. data/lib/oci8/metadata.rb +2132 -0
  54. data/lib/oci8/object.rb +581 -0
  55. data/lib/oci8/oci8.rb +721 -0
  56. data/lib/oci8/ocihandle.rb +425 -0
  57. data/lib/oci8/oracle_version.rb +144 -0
  58. data/lib/oci8/properties.rb +73 -0
  59. data/metaconfig +142 -0
  60. data/pre-distclean.rb +7 -0
  61. data/ruby-oci8.gemspec +63 -0
  62. data/setup.rb +1331 -0
  63. data/test/README +4 -0
  64. data/test/config.rb +122 -0
  65. data/test/test_all.rb +51 -0
  66. data/test/test_appinfo.rb +63 -0
  67. data/test/test_array_dml.rb +333 -0
  68. data/test/test_bind_raw.rb +46 -0
  69. data/test/test_bind_time.rb +178 -0
  70. data/test/test_break.rb +96 -0
  71. data/test/test_clob.rb +82 -0
  72. data/test/test_connstr.rb +81 -0
  73. data/test/test_datetime.rb +582 -0
  74. data/test/test_dbi.rb +366 -0
  75. data/test/test_dbi_clob.rb +53 -0
  76. data/test/test_encoding.rb +100 -0
  77. data/test/test_error.rb +88 -0
  78. data/test/test_metadata.rb +1399 -0
  79. data/test/test_oci8.rb +434 -0
  80. data/test/test_oracle_version.rb +70 -0
  81. data/test/test_oradate.rb +256 -0
  82. data/test/test_oranumber.rb +746 -0
  83. data/test/test_rowid.rb +33 -0
  84. metadata +137 -0
@@ -0,0 +1,721 @@
1
+ # oci8.rb -- implements OCI8 and OCI8::Cursor
2
+ #
3
+ # Copyright (C) 2002-2010 KUBO Takehiro <kubo@jiubao.org>
4
+ #
5
+ # Original Copyright is:
6
+ # Oracle module for Ruby
7
+ # 1998-2000 by yoshidam
8
+ #
9
+
10
+ require 'date'
11
+ require 'yaml'
12
+
13
+ # A connection to a Oracle database server.
14
+ #
15
+ # example:
16
+ # # output the emp table's content as CSV format.
17
+ # conn = OCI8.new(username, password)
18
+ # conn.exec('select * from emp') do |row|
19
+ # puts row.join(',')
20
+ # end
21
+ #
22
+ # # execute PL/SQL block with bind variables.
23
+ # conn = OCI8.new(username, password)
24
+ # conn.exec('BEGIN procedure_name(:1, :2); END;',
25
+ # value_for_the_first_parameter,
26
+ # value_for_the_second_parameter)
27
+ class OCI8
28
+
29
+ # call-seq:
30
+ # new(username, password, dbname = nil, privilege = nil)
31
+ #
32
+ # Connects to an Oracle database server by +username+ and +password+
33
+ # at +dbname+ as +privilege+.
34
+ #
35
+ # === connecting to the local server
36
+ #
37
+ # Set +username+ and +password+ or pass "username/password" as a
38
+ # single argument.
39
+ #
40
+ # OCI8.new('scott', 'tiger')
41
+ # or
42
+ # OCI8.new('scott/tiger')
43
+ #
44
+ # === connecting to a remote server
45
+ #
46
+ # Set +username+, +password+ and +dbname+ or pass
47
+ # "username/password@dbname" as a single argument.
48
+ #
49
+ # OCI8.new('scott', 'tiger', 'orcl.world')
50
+ # or
51
+ # OCI8.new('scott/tiger@orcl.world')
52
+ #
53
+ # The +dbname+ is a net service name or an easy connectection
54
+ # identifier. The former is a name listed in the file tnsnames.ora.
55
+ # Ask to your DBA if you don't know what it is. The latter has the
56
+ # syntax as "//host:port/service_name".
57
+ #
58
+ # OCI8.new('scott', 'tiger', '//remote-host:1521/XE')
59
+ # or
60
+ # OCI8.new('scott/tiger@//remote-host:1521/XE')
61
+ #
62
+ # === connecting as a privileged user
63
+ #
64
+ # Set :SYSDBA or :SYSOPER to +privilege+, otherwise
65
+ # "username/password as sysdba" or "username/password as sysoper"
66
+ # as a single argument.
67
+ #
68
+ # OCI8.new('sys', 'change_on_install', nil, :SYSDBA)
69
+ # or
70
+ # OCI8.new('sys/change_on_install as sysdba')
71
+ #
72
+ # === external OS authentication
73
+ #
74
+ # Set nil to +username+ and +password+, or "/" as a single argument.
75
+ #
76
+ # OCI8.new(nil, nil)
77
+ # or
78
+ # OCI8.new('/')
79
+ #
80
+ # To connect to a remote host:
81
+ #
82
+ # OCI8.new(nil, nil, 'dbname')
83
+ # or
84
+ # OCI8.new('/@dbname')
85
+ #
86
+ # === proxy authentication
87
+ #
88
+ # Enclose end user's username with square brackets and add it at the
89
+ # end of proxy user's username.
90
+ #
91
+ # OCI8.new('proxy_user_name[end_user_name]', 'proxy_password')
92
+ # or
93
+ # OCI8.new('proxy_user_name[end_user_name]/proxy_password')
94
+ #
95
+ def initialize(*args)
96
+ if args.length == 1
97
+ username, password, dbname, mode = parse_connect_string(args[0])
98
+ else
99
+ username, password, dbname, mode = args
100
+ end
101
+
102
+ if username.nil? and password.nil?
103
+ cred = OCI_CRED_EXT
104
+ end
105
+ case mode
106
+ when :SYSDBA
107
+ mode = OCI_SYSDBA
108
+ when :SYSOPER
109
+ mode = OCI_SYSOPER
110
+ when nil
111
+ # do nothing
112
+ else
113
+ raise "unknown privilege type #{mode}"
114
+ end
115
+
116
+ if mode.nil? and cred.nil? and (not dbname.is_a? OCI8::ConnectionPool)
117
+ # logon by the OCI function OCILogon().
118
+ logon(username, password, dbname)
119
+ else
120
+ # logon by the OCI function OCISessionBegin().
121
+ if dbname.is_a? OCI8::ConnectionPool
122
+ @pool = dbname # to prevent GC from freeing the connection pool.
123
+ attach_mode = OCI_CPOOL
124
+ dbname = dbname.send(:pool_name)
125
+ else
126
+ attach_mode = OCI_DEFAULT
127
+ end
128
+
129
+ allocate_handles()
130
+ session_handle.send(:attr_set_string, OCI_ATTR_USERNAME, username) if username
131
+ session_handle.send(:attr_set_string, OCI_ATTR_PASSWORD, password) if password
132
+ server_attach(dbname, attach_mode)
133
+ session_begin(cred ? cred : OCI_CRED_RDBMS, mode ? mode : OCI_DEFAULT)
134
+ end
135
+
136
+ @prefetch_rows = nil
137
+ @username = nil
138
+ end
139
+
140
+ # call-seq:
141
+ # parse(sql_text) -> an OCI8::Cursor
142
+ #
143
+ # Returns a prepared SQL handle.
144
+ def parse(sql)
145
+ @last_error = nil
146
+ parse_internal(sql)
147
+ end
148
+
149
+ # same with OCI8#parse except that this doesn't reset OCI8#last_error.
150
+ def parse_internal(sql)
151
+ cursor = OCI8::Cursor.new(self, sql)
152
+ cursor.prefetch_rows = @prefetch_rows if @prefetch_rows
153
+ cursor
154
+ end
155
+
156
+ # Executes the sql statement. The type of return value depends on
157
+ # the type of sql statement: select; insert, update and delete;
158
+ # create, alter and drop; and PL/SQL.
159
+ #
160
+ # When bindvars are specified, they are bound as bind variables
161
+ # before execution.
162
+ #
163
+ # == select statements without block
164
+ # It returns the instance of OCI8::Cursor.
165
+ #
166
+ # example:
167
+ # conn = OCI8.new('scott', 'tiger')
168
+ # cursor = conn.exec('SELECT * FROM emp')
169
+ # while r = cursor.fetch()
170
+ # puts r.join(',')
171
+ # end
172
+ # cursor.close
173
+ # conn.logoff
174
+ #
175
+ # == select statements with a block
176
+ # It acts as iterator and returns the processed row counts. Fetched
177
+ # data is passed to the block as array. NULL value becomes nil in ruby.
178
+ #
179
+ # example:
180
+ # conn = OCI8.new('scott', 'tiger')
181
+ # num_rows = conn.exec('SELECT * FROM emp') do |r|
182
+ # puts r.join(',')
183
+ # end
184
+ # puts num_rows.to_s + ' rows were processed.'
185
+ # conn.logoff
186
+ #
187
+ # == PL/SQL block (ruby-oci8 1.0)
188
+ # It returns the array of bind variables' values.
189
+ #
190
+ # example:
191
+ # conn = OCI8.new('scott', 'tiger')
192
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123)
193
+ # # => ["0123", 123]
194
+ # conn.logoff
195
+ #
196
+ # Above example uses two bind variables which names are :str
197
+ # and :num. These initial values are "the string whose width
198
+ # is 4 and whose value is 'ABCD'" and "the number whose value is
199
+ # 123". This method returns the array of these bind variables,
200
+ # which may modified by PL/SQL statement. The order of array is
201
+ # same with that of bind variables.
202
+ #
203
+ # If a block is given, it is ignored.
204
+ #
205
+ # == PL/SQL block (ruby-oci8 2.0)
206
+ # It returns the number of processed rows.
207
+ #
208
+ # example:
209
+ # conn = OCI8.new('scott', 'tiger')
210
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123)
211
+ # # => 1
212
+ # conn.logoff
213
+ #
214
+ # If a block is given, the bind variables' values are passed to the block after
215
+ # executed.
216
+ #
217
+ # conn = OCI8.new('scott', 'tiger')
218
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123) do |str, num|
219
+ # puts str # => '0123'
220
+ # puts num # => 123
221
+ # end
222
+ # conn.logoff
223
+ #
224
+ # FYI, the following code do same on ruby-oci8 1.0 and ruby-oci8 2.0.
225
+ # conn.exec(sql, *bindvars) { |*outvars| outvars }
226
+ #
227
+ # == Other SQL statements
228
+ # It returns the number of processed rows.
229
+ #
230
+ # example:
231
+ # conn = OCI8.new('scott', 'tiger')
232
+ # num_rows = conn.exec('UPDATE emp SET sal = sal * 1.1')
233
+ # puts num_rows.to_s + ' rows were updated.'
234
+ # conn.logoff
235
+ #
236
+ # example:
237
+ # conn = OCI8.new('scott', 'tiger')
238
+ # conn.exec('CREATE TABLE test (col1 CHAR(6))') # => 0
239
+ # conn.logoff
240
+ #
241
+ def exec(sql, *bindvars, &block)
242
+ @last_error = nil
243
+ exec_internal(sql, *bindvars, &block)
244
+ end
245
+
246
+ # same with OCI8#exec except that this doesn't reset OCI8#last_error.
247
+ def exec_internal(sql, *bindvars)
248
+ begin
249
+ cursor = parse(sql)
250
+ ret = cursor.exec(*bindvars)
251
+ case cursor.type
252
+ when :select_stmt
253
+ if block_given?
254
+ cursor.fetch { |row| yield(row) } # for each row
255
+ ret = cursor.row_count()
256
+ else
257
+ ret = cursor
258
+ cursor = nil # unset cursor to skip cursor.close in ensure block
259
+ ret
260
+ end
261
+ when :begin_stmt, :declare_stmt # PL/SQL block
262
+ if block_given?
263
+ ary = []
264
+ cursor.keys.sort.each do |key|
265
+ ary << cursor[key]
266
+ end
267
+ yield(*ary)
268
+ else
269
+ ret
270
+ end
271
+ else
272
+ ret # number of rows processed
273
+ end
274
+ ensure
275
+ cursor.nil? || cursor.close
276
+ end
277
+ end # exec
278
+
279
+ # :call-seq:
280
+ # select_one(sql, *bindvars) -> first_one_row
281
+ #
282
+ def select_one(sql, *bindvars)
283
+ cursor = self.parse(sql)
284
+ begin
285
+ cursor.exec(*bindvars)
286
+ row = cursor.fetch
287
+ ensure
288
+ cursor.close
289
+ end
290
+ return row
291
+ end
292
+
293
+ def username
294
+ @username || begin
295
+ exec('select user from dual') do |row|
296
+ @username = row[0]
297
+ end
298
+ @username
299
+ end
300
+ end
301
+
302
+ def inspect
303
+ "#<OCI8:#{username}>"
304
+ end
305
+
306
+ # :call-seq:
307
+ # oracle_server_version -> oraver
308
+ #
309
+ # Returns an OCI8::OracleVersion of the Oracle server version.
310
+ #
311
+ # See also: OCI8.oracle_client_version
312
+ def oracle_server_version
313
+ unless defined? @oracle_server_version
314
+ if vernum = oracle_server_vernum
315
+ # If the Oracle client is Oracle 9i or upper,
316
+ # get the server version from the OCI function OCIServerRelease.
317
+ @oracle_server_version = OCI8::OracleVersion.new(vernum)
318
+ else
319
+ # Otherwise, get it from v$version.
320
+ self.exec('select banner from v$version') do |row|
321
+ if /^Oracle.*?(\d+\.\d+\.\d+\.\d+\.\d+)/ =~ row[0]
322
+ @oracle_server_version = OCI8::OracleVersion.new($1)
323
+ break
324
+ end
325
+ end
326
+ end
327
+ end
328
+ @oracle_server_version
329
+ end
330
+
331
+ # The instance of this class corresponds to cursor in the term of
332
+ # Oracle, which corresponds to java.sql.Statement of JDBC and statement
333
+ # handle $sth of Perl/DBI.
334
+ #
335
+ # Don't create the instance by calling 'new' method. Please create it by
336
+ # calling OCI8#exec or OCI8#parse.
337
+ class Cursor
338
+
339
+ # explicitly indicate the date type of fetched value. run this
340
+ # method within parse and exec. pos starts from 1. lentgh is used
341
+ # when type is String.
342
+ #
343
+ # example:
344
+ # cursor = conn.parse("SELECT ename, hiredate FROM emp")
345
+ # cursor.define(1, String, 20) # fetch the first column as String.
346
+ # cursor.define(2, Time) # fetch the second column as Time.
347
+ # cursor.exec()
348
+ def define(pos, type, length = nil)
349
+ __define(pos, make_bind_object(:type => type, :length => length))
350
+ self
351
+ end # define
352
+
353
+ # Binds variables explicitly.
354
+ #
355
+ # When key is number, it binds by position, which starts from 1.
356
+ # When key is string, it binds by the name of placeholder.
357
+ #
358
+ # example:
359
+ # cursor = conn.parse("SELECT * FROM emp WHERE ename = :ename")
360
+ # cursor.bind_param(1, 'SMITH') # bind by position
361
+ # ...or...
362
+ # cursor.bind_param(':ename', 'SMITH') # bind by name
363
+ #
364
+ # To bind as number, Fixnum and Float are available, but Bignum is
365
+ # not supported. If its initial value is NULL, please set nil to
366
+ # +type+ and Fixnum or Float to +val+.
367
+ #
368
+ # example:
369
+ # cursor.bind_param(1, 1234) # bind as Fixnum, Initial value is 1234.
370
+ # cursor.bind_param(1, 1234.0) # bind as Float, Initial value is 1234.0.
371
+ # cursor.bind_param(1, nil, Fixnum) # bind as Fixnum, Initial value is NULL.
372
+ # cursor.bind_param(1, nil, Float) # bind as Float, Initial value is NULL.
373
+ #
374
+ # In case of binding a string, set the string itself to
375
+ # +val+. When the bind variable is used as output, set the
376
+ # string whose length is enough to store or set the length.
377
+ #
378
+ # example:
379
+ # cursor = conn.parse("BEGIN :out := :in || '_OUT'; END;")
380
+ # cursor.bind_param(':in', 'DATA') # bind as String with width 4.
381
+ # cursor.bind_param(':out', nil, String, 7) # bind as String with width 7.
382
+ # cursor.exec()
383
+ # p cursor[':out'] # => 'DATA_OU'
384
+ # # Though the length of :out is 8 bytes in PL/SQL block, it is
385
+ # # bound as 7 bytes. So result is cut off at 7 byte.
386
+ #
387
+ # In case of binding a string as RAW, set OCI::RAW to +type+.
388
+ #
389
+ # example:
390
+ # cursor = conn.parse("INSERT INTO raw_table(raw_column) VALUE (:1)")
391
+ # cursor.bind_param(1, 'RAW_STRING', OCI8::RAW)
392
+ # cursor.exec()
393
+ # cursor.close()
394
+ def bind_param(key, param, type = nil, length = nil)
395
+ case param
396
+ when Hash
397
+ when Class
398
+ param = {:value => nil, :type => param, :length => length}
399
+ else
400
+ param = {:value => param, :type => type, :length => length}
401
+ end
402
+ __bind(key, make_bind_object(param))
403
+ self
404
+ end # bind_param
405
+
406
+ # Executes the SQL statement assigned the cursor. The type of
407
+ # return value depends on the type of sql statement: select;
408
+ # insert, update and delete; create, alter, drop and PL/SQL.
409
+ #
410
+ # In case of select statement, it returns the number of the
411
+ # select-list.
412
+ #
413
+ # In case of insert, update or delete statement, it returns the
414
+ # number of processed rows.
415
+ #
416
+ # In case of create, alter, drop and PL/SQL statement, it returns
417
+ # true. In contrast with OCI8#exec, it returns true even
418
+ # though PL/SQL. Use OCI8::Cursor#[] explicitly to get bind
419
+ # variables.
420
+ def exec(*bindvars)
421
+ bind_params(*bindvars)
422
+ __execute(nil) # Pass a nil to specify the statement isn't an Array DML
423
+ case type
424
+ when :select_stmt
425
+ define_columns()
426
+ else
427
+ row_count
428
+ end
429
+ end # exec
430
+
431
+ # Set the maximum array size for bind_param_array
432
+ #
433
+ # All the binds will be clean from cursor if instance variable max_array_size is set before
434
+ #
435
+ # Instance variable actual_array_size holds the size of the arrays users actually binds through bind_param_array
436
+ # all the binding arrays are required to be the same size
437
+ def max_array_size=(size)
438
+ raise "expect positive number for max_array_size." if size.nil? && size <=0
439
+ __clearBinds if !@max_array_size.nil?
440
+ @max_array_size = size
441
+ @actual_array_size = nil
442
+ end # max_array_size=
443
+
444
+ # Bind array explicitly
445
+ #
446
+ # When key is number, it binds by position, which starts from 1.
447
+ # When key is string, it binds by the name of placeholder.
448
+ #
449
+ # The max_array_size should be set before calling bind_param_array
450
+ #
451
+ # example:
452
+ # cursor = conn.parse("INSERT INTO test_table VALUES (:str)")
453
+ # cursor.max_array_size = 3
454
+ # cursor.bind_param_array(1, ['happy', 'new', 'year'], String, 30)
455
+ # cursor.exec_array
456
+ def bind_param_array(key, var_array, type = nil, max_item_length = nil)
457
+ raise "please call max_array_size= first." if @max_array_size.nil?
458
+ raise "expect array as input param for bind_param_array." if !var_array.nil? && !(var_array.is_a? Array)
459
+ raise "the size of var_array should not be greater than max_array_size." if !var_array.nil? && var_array.size > @max_array_size
460
+
461
+ if var_array.nil?
462
+ raise "all binding arrays should be the same size." unless @actual_array_size.nil? || @actual_array_size == 0
463
+ @actual_array_size = 0
464
+ else
465
+ raise "all binding arrays should be the same size." unless @actual_array_size.nil? || var_array.size == @actual_array_size
466
+ @actual_array_size = var_array.size if @actual_array_size.nil?
467
+ end
468
+
469
+ param = {:value => var_array, :type => type, :length => max_item_length, :max_array_size => @max_array_size}
470
+ first_non_nil_elem = var_array.nil? ? nil : var_array.find{|x| x!= nil}
471
+
472
+ if type.nil?
473
+ if first_non_nil_elem.nil?
474
+ raise "bind type is not given."
475
+ else
476
+ type = first_non_nil_elem.class
477
+ end
478
+ end
479
+
480
+ bindclass = OCI8::BindType::Mapping[type]
481
+ if bindclass.nil? and type.is_a? Class
482
+ bindclass = OCI8::BindType::Mapping[type.to_s]
483
+ OCI8::BindType::Mapping[type] = bindclass if bindclass
484
+ end
485
+ raise "unsupported dataType: #{type}" if bindclass.nil?
486
+ bindobj = bindclass.create(@con, var_array, param, @max_array_size)
487
+ __bind(key, bindobj)
488
+ self
489
+ end # bind_param_array
490
+
491
+ # Executes the SQL statement assigned the cursor with array binding
492
+ def exec_array
493
+ raise "please call max_array_size= first." if @max_array_size.nil?
494
+
495
+ if !@actual_array_size.nil? && @actual_array_size > 0
496
+ __execute(@actual_array_size)
497
+ else
498
+ raise "please set non-nil values to array binding parameters"
499
+ end
500
+
501
+ case type
502
+ when :update_stmt, :delete_stmt, :insert_stmt
503
+ row_count
504
+ else
505
+ true
506
+ end
507
+ end # exec_array
508
+
509
+ # Gets the names of select-list as array. Please use this
510
+ # method after exec.
511
+ def get_col_names
512
+ @names ||= @column_metadata.collect { |md| md.name }
513
+ end # get_col_names
514
+
515
+ # call-seq:
516
+ # column_metadata -> column information
517
+ #
518
+ # (new in 1.0.0 and 2.0)
519
+ #
520
+ # Gets an array of OCI8::Metadata::Column of a select statement.
521
+ #
522
+ # example:
523
+ # cursor = conn.exec('select * from tab')
524
+ # puts ' Name Type'
525
+ # puts ' ----------------------------------------- ----------------------------'
526
+ # cursor.column_metadata.each do |colinfo|
527
+ # puts format(' %-41s %s',
528
+ # colinfo.name,
529
+ # colinfo.type_string)
530
+ # end
531
+ def column_metadata
532
+ @column_metadata
533
+ end
534
+
535
+ # call-seq:
536
+ # fetch_hash
537
+ #
538
+ # get fetched data as a Hash. The hash keys are column names.
539
+ # If a block is given, acts as an iterator.
540
+ def fetch_hash
541
+ if iterator?
542
+ while ret = fetch_a_hash_row()
543
+ yield(ret)
544
+ end
545
+ else
546
+ fetch_a_hash_row
547
+ end
548
+ end # fetch_hash
549
+
550
+ # close the cursor.
551
+ def close
552
+ free()
553
+ @names = nil
554
+ @column_metadata = nil
555
+ end # close
556
+
557
+ private
558
+
559
+ def make_bind_object(param)
560
+ case param
561
+ when Hash
562
+ key = param[:type]
563
+ val = param[:value]
564
+ max_array_size = param[:max_array_size]
565
+
566
+ if key.nil?
567
+ if val.nil?
568
+ raise "bind type is not given."
569
+ elsif val.is_a? OCI8::Object::Base
570
+ key = :named_type
571
+ param = @con.get_tdo_by_class(val.class)
572
+ else
573
+ key = val.class
574
+ end
575
+ elsif key.class == Class && key < OCI8::Object::Base
576
+ param = @con.get_tdo_by_class(key)
577
+ key = :named_type
578
+ end
579
+ when OCI8::Metadata::Base
580
+ key = param.data_type
581
+ case key
582
+ when :named_type
583
+ if param.type_name == 'XMLTYPE'
584
+ key = :xmltype
585
+ else
586
+ param = @con.get_tdo_by_metadata(param.type_metadata)
587
+ end
588
+ end
589
+ else
590
+ raise "unknown param #{param.intern}"
591
+ end
592
+
593
+ bindclass = OCI8::BindType::Mapping[key]
594
+ if bindclass.nil? and key.is_a? Class
595
+ bindclass = OCI8::BindType::Mapping[key.to_s]
596
+ OCI8::BindType::Mapping[key] = bindclass if bindclass
597
+ end
598
+ raise "unsupported datatype: #{key}" if bindclass.nil?
599
+ bindclass.create(@con, val, param, max_array_size)
600
+ end
601
+
602
+ def define_columns
603
+ num_cols = __param_count
604
+ 1.upto(num_cols) do |i|
605
+ parm = __paramGet(i)
606
+ define_one_column(i, parm) unless __defined?(i)
607
+ @column_metadata[i - 1] = parm
608
+ end
609
+ num_cols
610
+ end # define_columns
611
+
612
+ def define_one_column(pos, param)
613
+ __define(pos, make_bind_object(param))
614
+ end # define_one_column
615
+
616
+ def bind_params(*bindvars)
617
+ bindvars.each_with_index do |val, i|
618
+ if val.is_a? Array
619
+ bind_param(i + 1, val[0], val[1], val[2])
620
+ else
621
+ bind_param(i + 1, val)
622
+ end
623
+ end
624
+ end # bind_params
625
+
626
+ def fetch_a_hash_row
627
+ if rs = fetch()
628
+ ret = {}
629
+ get_col_names.each do |name|
630
+ ret[name] = rs.shift
631
+ end
632
+ ret
633
+ else
634
+ nil
635
+ end
636
+ end # fetch_a_hash_row
637
+
638
+ end # OCI8::Cursor
639
+ end # OCI8
640
+
641
+ class OraDate
642
+ def to_time
643
+ begin
644
+ Time.local(year, month, day, hour, minute, second)
645
+ rescue ArgumentError
646
+ 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)
647
+ raise RangeError.new(msg)
648
+ end
649
+ end
650
+
651
+ def to_date
652
+ Date.new(year, month, day)
653
+ end
654
+
655
+ if defined? DateTime # ruby 1.8.0 or upper
656
+
657
+ # get timezone offset.
658
+ @@tz_offset = Time.now.utc_offset.to_r/86400
659
+
660
+ def to_datetime
661
+ DateTime.new(year, month, day, hour, minute, second, @@tz_offset)
662
+ end
663
+ end
664
+
665
+ def yaml_initialize(type, val) # :nodoc:
666
+ initialize(*val.split(/[ -\/:]+/).collect do |i| i.to_i end)
667
+ end
668
+
669
+ def to_yaml(opts = {}) # :nodoc:
670
+ YAML.quick_emit(object_id, opts) do |out|
671
+ out.scalar(taguri, self.to_s, :plain)
672
+ end
673
+ end
674
+
675
+ def to_json(options=nil) # :nodoc:
676
+ to_datetime.to_json(options)
677
+ end
678
+ end
679
+
680
+ class OraNumber
681
+
682
+ if defined? Psych and YAML == Psych
683
+
684
+ yaml_tag '!ruby/object:OraNumber'
685
+ def encode_with coder # :nodoc:
686
+ coder.scalar = self.to_s
687
+ end
688
+
689
+ def init_with coder # :nodoc:
690
+ initialize(coder.scalar)
691
+ end
692
+
693
+ else
694
+
695
+ def yaml_initialize(type, val) # :nodoc:
696
+ initialize(val)
697
+ end
698
+
699
+ def to_yaml(opts = {}) # :nodoc:
700
+ YAML.quick_emit(object_id, opts) do |out|
701
+ out.scalar(taguri, self.to_s, :plain)
702
+ end
703
+ end
704
+ end
705
+
706
+ def to_json(options=nil) # :nodoc:
707
+ to_s
708
+ end
709
+ end
710
+
711
+ class Numeric
712
+ def to_onum
713
+ OraNumber.new(self)
714
+ end
715
+ end
716
+
717
+ class String
718
+ def to_onum(format = nil, nls_params = nil)
719
+ OraNumber.new(self, format, nls_params)
720
+ end
721
+ end