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
data/lib/oci8/oci8.rb ADDED
@@ -0,0 +1,756 @@
1
+ # oci8.rb -- OCI8
2
+ #
3
+ # Copyright (C) 2002-2015 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
+ # @return [OCIError]
30
+ attr_accessor :last_error
31
+
32
+ # @overload initialize(username, password, dbname = nil, privilege = nil)
33
+ #
34
+ # Connects to an Oracle database server by +username+ and +password+
35
+ # at +dbname+ as +privilege+.
36
+ #
37
+ # === connecting to the local server
38
+ #
39
+ # Set +username+ and +password+ or pass "username/password" as a
40
+ # single argument.
41
+ #
42
+ # OCI8.new('scott', 'tiger')
43
+ # or
44
+ # OCI8.new('scott/tiger')
45
+ #
46
+ # === connecting to a remote server
47
+ #
48
+ # Set +username+, +password+ and +dbname+ or pass
49
+ # "username/password@dbname" as a single argument.
50
+ #
51
+ # OCI8.new('scott', 'tiger', 'orcl.world')
52
+ # or
53
+ # OCI8.new('scott/tiger@orcl.world')
54
+ #
55
+ # The +dbname+ is a net service name or an easy connectection
56
+ # identifier. The former is a name listed in the file tnsnames.ora.
57
+ # Ask to your DBA if you don't know what it is. The latter has the
58
+ # syntax as "//host:port/service_name".
59
+ #
60
+ # OCI8.new('scott', 'tiger', '//remote-host:1521/XE')
61
+ # or
62
+ # OCI8.new('scott/tiger@//remote-host:1521/XE')
63
+ #
64
+ # === connecting as a privileged user
65
+ #
66
+ # Set :SYSDBA, :SYSOPER, :SYSASM, :SYSBACKUP, :SYSDG or :SYSKM
67
+ # to +privilege+, otherwise "username/password as sysdba",
68
+ # "username/password as sysoper", etc. as a single argument.
69
+ #
70
+ # OCI8.new('sys', 'change_on_install', nil, :SYSDBA)
71
+ # or
72
+ # OCI8.new('sys/change_on_install as sysdba')
73
+ #
74
+ # === external OS authentication
75
+ #
76
+ # Set nil to +username+ and +password+, or "/" as a single argument.
77
+ #
78
+ # OCI8.new(nil, nil)
79
+ # or
80
+ # OCI8.new('/')
81
+ #
82
+ # To connect to a remote host:
83
+ #
84
+ # OCI8.new(nil, nil, 'dbname')
85
+ # or
86
+ # OCI8.new('/@dbname')
87
+ #
88
+ # === proxy authentication
89
+ #
90
+ # Enclose end user's username with square brackets and add it at the
91
+ # end of proxy user's username.
92
+ #
93
+ # OCI8.new('proxy_user_name[end_user_name]', 'proxy_password')
94
+ # or
95
+ # OCI8.new('proxy_user_name[end_user_name]/proxy_password')
96
+ #
97
+ def initialize(*args)
98
+ if args.length == 1
99
+ username, password, dbname, privilege = parse_connect_string(args[0])
100
+ else
101
+ username, password, dbname, privilege = args
102
+ end
103
+
104
+ if username.nil? and password.nil?
105
+ cred = OCI_CRED_EXT
106
+ end
107
+ auth_mode = to_auth_mode(privilege)
108
+
109
+ stmt_cache_size = OCI8.properties[:statement_cache_size]
110
+ stmt_cache_size = nil if stmt_cache_size == 0
111
+
112
+ attach_mode = 0
113
+ if dbname.is_a? OCI8::ConnectionPool
114
+ @pool = dbname # to prevent GC from freeing the connection pool.
115
+ dbname = dbname.send(:pool_name)
116
+ attach_mode |= 0x0200 # OCI_CPOOL
117
+ else
118
+ tcp_connect_timeout = OCI8::properties[:tcp_connect_timeout]
119
+ connect_timeout = OCI8::properties[:connect_timeout]
120
+ tcp_keepalive = OCI8::properties[:tcp_keepalive]
121
+ if tcp_connect_timeout || connect_timeout || tcp_keepalive
122
+ dbname = to_connect_descriptor(dbname, tcp_connect_timeout, connect_timeout, tcp_keepalive)
123
+ end
124
+ end
125
+ if stmt_cache_size
126
+ # enable statement caching
127
+ attach_mode |= 0x0004 # OCI_STMT_CACHE
128
+ end
129
+
130
+ # logon by the OCI function OCISessionBegin().
131
+ allocate_handles()
132
+ @session_handle.send(:attr_set_string, OCI_ATTR_USERNAME, username) if username
133
+ @session_handle.send(:attr_set_string, OCI_ATTR_PASSWORD, password) if password
134
+ if @@oracle_client_version >= ORAVER_11_1
135
+ # Sets the driver name displayed in V$SESSION_CONNECT_INFO.CLIENT_DRIVER
136
+ # if both the client and the server are Oracle 11g or upper.
137
+ # Only the first 8 chracters "ruby-oci" are displayed when the Oracle
138
+ # server version is lower than 12.0.1.2.
139
+ # 424: OCI_ATTR_DRIVER_NAME
140
+ @session_handle.send(:attr_set_string, 424, "ruby-oci8 : #{OCI8::VERSION}")
141
+ end
142
+ server_attach(dbname, attach_mode)
143
+ if OCI8.oracle_client_version >= OCI8::ORAVER_11_1
144
+ self.send_timeout = OCI8::properties[:send_timeout] if OCI8::properties[:send_timeout]
145
+ self.recv_timeout = OCI8::properties[:recv_timeout] if OCI8::properties[:recv_timeout]
146
+ end
147
+ session_begin(cred ? cred : OCI_CRED_RDBMS, auth_mode)
148
+
149
+ if stmt_cache_size
150
+ # set statement cache size
151
+ attr_set_ub4(176, stmt_cache_size) # 176: OCI_ATTR_STMTCACHESIZE
152
+ end
153
+
154
+ @prefetch_rows = 100
155
+ @username = nil
156
+ end
157
+
158
+ # Returns a prepared SQL handle.
159
+ #
160
+ # @param [String] sql SQL statement
161
+ # @return [OCI8::Cursor]
162
+ def parse(sql)
163
+ @last_error = nil
164
+ parse_internal(sql)
165
+ end
166
+
167
+ # same with OCI8#parse except that this doesn't reset OCI8#last_error.
168
+ #
169
+ # @private
170
+ def parse_internal(sql)
171
+ cursor = OCI8::Cursor.new(self, sql)
172
+ cursor
173
+ end
174
+
175
+ # Executes the sql statement. The type of return value depends on
176
+ # the type of sql statement: select; insert, update and delete;
177
+ # create, alter and drop; and PL/SQL.
178
+ #
179
+ # When bindvars are specified, they are bound as bind variables
180
+ # before execution.
181
+ #
182
+ # == select statements without block
183
+ # It returns the instance of OCI8::Cursor.
184
+ #
185
+ # example:
186
+ # conn = OCI8.new('scott', 'tiger')
187
+ # cursor = conn.exec('SELECT * FROM emp')
188
+ # while r = cursor.fetch()
189
+ # puts r.join(',')
190
+ # end
191
+ # cursor.close
192
+ # conn.logoff
193
+ #
194
+ # == select statements with a block
195
+ # It acts as iterator and returns the processed row counts. Fetched
196
+ # data is passed to the block as array. NULL value becomes nil in ruby.
197
+ #
198
+ # example:
199
+ # conn = OCI8.new('scott', 'tiger')
200
+ # num_rows = conn.exec('SELECT * FROM emp') do |r|
201
+ # puts r.join(',')
202
+ # end
203
+ # puts num_rows.to_s + ' rows were processed.'
204
+ # conn.logoff
205
+ #
206
+ # == PL/SQL block (ruby-oci8 1.0)
207
+ # It returns the array of bind variables' values.
208
+ #
209
+ # example:
210
+ # conn = OCI8.new('scott', 'tiger')
211
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123)
212
+ # # => ["0123", 123]
213
+ # conn.logoff
214
+ #
215
+ # Above example uses two bind variables which names are :str
216
+ # and :num. These initial values are "the string whose width
217
+ # is 4 and whose value is 'ABCD'" and "the number whose value is
218
+ # 123". This method returns the array of these bind variables,
219
+ # which may modified by PL/SQL statement. The order of array is
220
+ # same with that of bind variables.
221
+ #
222
+ # If a block is given, it is ignored.
223
+ #
224
+ # == PL/SQL block (ruby-oci8 2.0)
225
+ # It returns the number of processed rows.
226
+ #
227
+ # example:
228
+ # conn = OCI8.new('scott', 'tiger')
229
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123)
230
+ # # => 1
231
+ # conn.logoff
232
+ #
233
+ # If a block is given, the bind variables' values are passed to the block after
234
+ # executed.
235
+ #
236
+ # conn = OCI8.new('scott', 'tiger')
237
+ # conn.exec("BEGIN :str := TO_CHAR(:num, 'FM0999'); END;", 'ABCD', 123) do |str, num|
238
+ # puts str # => '0123'
239
+ # puts num # => 123
240
+ # end
241
+ # conn.logoff
242
+ #
243
+ # FYI, the following code do same on ruby-oci8 1.0 and ruby-oci8 2.0.
244
+ # conn.exec(sql, *bindvars) { |*outvars| outvars }
245
+ #
246
+ # == Other SQL statements
247
+ # It returns the number of processed rows.
248
+ #
249
+ # example:
250
+ # conn = OCI8.new('scott', 'tiger')
251
+ # num_rows = conn.exec('UPDATE emp SET sal = sal * 1.1')
252
+ # puts num_rows.to_s + ' rows were updated.'
253
+ # conn.logoff
254
+ #
255
+ # example:
256
+ # conn = OCI8.new('scott', 'tiger')
257
+ # conn.exec('CREATE TABLE test (col1 CHAR(6))') # => 0
258
+ # conn.logoff
259
+ #
260
+ def exec(sql, *bindvars, &block)
261
+ @last_error = nil
262
+ exec_internal(sql, *bindvars, &block)
263
+ end
264
+
265
+ # same with OCI8#exec except that this doesn't reset OCI8#last_error.
266
+ #
267
+ # @private
268
+ def exec_internal(sql, *bindvars)
269
+ begin
270
+ cursor = parse(sql)
271
+ ret = cursor.exec(*bindvars)
272
+ case cursor.type
273
+ when :select_stmt
274
+ if block_given?
275
+ cursor.fetch { |row| yield(row) } # for each row
276
+ ret = cursor.row_count()
277
+ else
278
+ ret = cursor
279
+ cursor = nil # unset cursor to skip cursor.close in ensure block
280
+ ret
281
+ end
282
+ when :begin_stmt, :declare_stmt # PL/SQL block
283
+ if block_given?
284
+ ary = []
285
+ cursor.keys.sort.each do |key|
286
+ ary << cursor[key]
287
+ end
288
+ yield(*ary)
289
+ else
290
+ ret
291
+ end
292
+ else
293
+ ret # number of rows processed
294
+ end
295
+ ensure
296
+ cursor.nil? || cursor.close
297
+ end
298
+ end # exec
299
+
300
+ # Executes a SQL statement and fetches the first one row.
301
+ #
302
+ # @param [String] sql SQL statement
303
+ # @param [Object] bindvars bind variables
304
+ # @return [Array] an array of first row.
305
+ def select_one(sql, *bindvars)
306
+ cursor = self.parse(sql)
307
+ cursor.prefetch_rows = 1
308
+ begin
309
+ cursor.exec(*bindvars)
310
+ row = cursor.fetch
311
+ ensure
312
+ cursor.close
313
+ end
314
+ return row
315
+ end
316
+
317
+ def username
318
+ @username || begin
319
+ exec('select user from dual') do |row|
320
+ @username = row[0]
321
+ end
322
+ @username
323
+ end
324
+ end
325
+
326
+ # Sets the prefetch rows size. The default value is 100.
327
+ # When a select statement is executed, the OCI library allocate
328
+ # prefetch buffer to reduce the number of network round trips by
329
+ # retrieving specified number of rows in one round trip.
330
+ #
331
+ # Note: The default value had been 1 before ruby-oci8 2.2.0.
332
+ def prefetch_rows=(num)
333
+ @prefetch_rows = num
334
+ end
335
+
336
+ # @private
337
+ def inspect
338
+ "#<OCI8:#{username}>"
339
+ end
340
+
341
+ # Returns the Oracle server version.
342
+ #
343
+ # When the Oracle client version is 12c or earlier and
344
+ # the Oracle server version is 18c or later, this method
345
+ # doesn't return *full* version number such as '18.3.0.0.0'.
346
+ # It returns version number whose number components after
347
+ # the first dot are zeros such as '18.0.0.0.0'.
348
+ #
349
+ # @see OCI8.oracle_client_version
350
+ # @return [OCI8::OracleVersion]
351
+ def oracle_server_version
352
+ @oracle_server_version ||= OCI8::OracleVersion.new(oracle_server_vernum)
353
+ end
354
+
355
+ # Returns the Oracle database character set name such as AL32UTF8.
356
+ #
357
+ # @since 2.1.0
358
+ # @return [String] Oracle database character set name
359
+ def database_charset_name
360
+ charset_id2name(@server_handle.send(:attr_get_ub2, OCI_ATTR_CHARSET_ID))
361
+ end
362
+
363
+ # Returns the client-side Oracle character set name such as AL32UTF8.
364
+ #
365
+ # @since 2.1.0
366
+ # @return [String] client-side character set name
367
+ # @private
368
+ # @see OCI8.encoding
369
+ def self.client_charset_name
370
+ @@client_charset_name
371
+ end
372
+
373
+ if OCI8.oracle_client_version >= OCI8::ORAVER_11_1
374
+ # Returns send timeout in seconds.
375
+ # Zero means no timeout.
376
+ # This is equivalent to {http://docs.oracle.com/database/121/NETRF/sqlnet.htm#NETRF228 SQLNET.SEND_TIMEOUT} in client-side sqlnet.ora.
377
+ #
378
+ # @return [Float] seconds
379
+ # @see #recv_timeout
380
+ # @since 2.1.8 and Oracle 11.1
381
+ def send_timeout
382
+ # OCI_ATTR_SEND_TIMEOUT = 435
383
+ @server_handle.send(:attr_get_ub4, 435).to_f / 1000
384
+ end
385
+
386
+ # Sets send timeout in seconds.
387
+ # Zero means no timeout.
388
+ # This is equivalent to {http://docs.oracle.com/database/121/NETRF/sqlnet.htm#NETRF228 SQLNET.SEND_TIMEOUT} in client-side sqlnet.ora.
389
+ #
390
+ # If you need to set send timeout while establishing a connection, use {file:docs/timeout-parameters.md timeout parameters in OCI8::properties} instead.
391
+ #
392
+ # Note that the connection becomes unusable on timeout.
393
+ #
394
+ # If you have trouble by setting this, don't use it because it uses
395
+ # {http://blog.jiubao.org/2015/01/undocumented-oci-handle-attributes.html an undocumented OCI handle attribute}.
396
+ #
397
+ # @param [Float] timeout
398
+ # @return [void]
399
+ # @see #recv_timeout=
400
+ # @since 2.1.8 and Oracle 11.1
401
+ def send_timeout=(timeout)
402
+ # OCI_ATTR_SEND_TIMEOUT = 435
403
+ @server_handle.send(:attr_set_ub4, 435, timeout * 1000)
404
+ end
405
+
406
+ # Returns receive timeout in seconds.
407
+ # Zero means no timeout.
408
+ # This is equivalent to {http://docs.oracle.com/database/121/NETRF/sqlnet.htm#NETRF227 SQLNET.RECV_TIMEOUT} in client-side sqlnet.ora.
409
+ #
410
+ # @return [Float] seconds
411
+ # @see #send_timeout
412
+ # @since 2.1.8 and Oracle 11.1
413
+ def recv_timeout
414
+ # OCI_ATTR_RECEIVE_TIMEOUT = 436
415
+ @server_handle.send(:attr_get_ub4, 436).to_f / 1000
416
+ end
417
+
418
+ # Sets receive timeout in seconds.
419
+ # Zero means no timeout.
420
+ # This is equivalent to {http://docs.oracle.com/database/121/NETRF/sqlnet.htm#NETRF227 SQLNET.RECV_TIMEOUT} in client-side sqlnet.ora.
421
+ #
422
+ # If you need to set receive timeout while establishing a connection, use {file:docs/timeout-parameters.md timeout parameters in OCI8::properties} instead.
423
+ #
424
+ # Note that the connection becomes unusable on timeout.
425
+ #
426
+ # If you have trouble by setting this, don't use it because it uses
427
+ # {http://blog.jiubao.org/2015/01/undocumented-oci-handle-attributes.html an undocumented OCI handle attribute}.
428
+ #
429
+ # @param [Float] timeout
430
+ # @return [void]
431
+ # @see #send_timeout=
432
+ # @since 2.1.8 and Oracle 11.1
433
+ def recv_timeout=(timeout)
434
+ # OCI_ATTR_RECEIVE_TIMEOUT = 436
435
+ @server_handle.send(:attr_set_ub4, 436, timeout * 1000)
436
+ end
437
+ else
438
+ def send_timeout
439
+ raise NotImplementedError, 'send_timeout is unimplemented in this Oracle version'
440
+ end
441
+ def send_timeout=(timeout)
442
+ raise NotImplementedError, 'send_timeout= is unimplemented in this Oracle version'
443
+ end
444
+ def recv_timeout
445
+ raise NotImplementedError, 'recv_timeout is unimplemented in this Oracle version'
446
+ end
447
+ def recv_timeout=(timeout)
448
+ raise NotImplementedError, 'revc_timeout= is unimplemented in this Oracle version'
449
+ end
450
+ end
451
+
452
+ # A helper class to bind an array to paramters in IN-condition.
453
+ #
454
+ # See {file:docs/bind-array-to-in_cond.md Bind an Array to IN-condition}
455
+ class InCondBindHelper
456
+ def initialize(bind_name_prefix, array, type = nil, length = nil)
457
+ bind_name_prefix = bind_name_prefix.to_s
458
+ if bind_name_prefix !~ /^\w+$/
459
+ raise ArgumentError, "The first argument doesn't consist of alphanumeric characters and underscores."
460
+ end
461
+ if array.empty?
462
+ # This doesn't match anything.
463
+ # However in-condition requires at least one value.
464
+ @bind_names = ":#{bind_name_prefix}_0"
465
+ @bind_values = [[nil, type.nil? ? String : type, length]]
466
+ else
467
+ @bind_names = Array.new(array.length) do |index|
468
+ ":#{bind_name_prefix}_#{index}"
469
+ end.join(', ')
470
+ first_non_nil = array.find do |e|
471
+ !e.nil?
472
+ end
473
+ first_non_nil = '' if first_non_nil.nil?
474
+ @bind_values = array.collect do |elem|
475
+ if elem.nil? and type.nil?
476
+ [elem, first_non_nil.class]
477
+ else
478
+ [elem, type, length]
479
+ end
480
+ end
481
+ end
482
+ end
483
+
484
+ def names
485
+ @bind_names
486
+ end
487
+
488
+ def values
489
+ @bind_values
490
+ end
491
+ end
492
+
493
+ # Creates a helper object to bind an array to paramters in IN-condition.
494
+ #
495
+ # See {file:docs/bind-array-to-in_cond.md Bind an Array to IN-condition}
496
+ #
497
+ # @param [Symbol] bind_name_prefix prefix of the place holder name
498
+ # @param [Object] array an array of values to be bound.
499
+ # @param [Class] type data type. This is used as the third argument of {OCI8::Cursor#bind_param}.
500
+ # @param [Integer] length maximum bind length for string values. This is used as the fourth argument of {OCI8::Cursor#bind_param}.
501
+ # @return [OCI8::InCondBindHelper]
502
+ def self.in_cond(bind_name_prefix, array, type = nil, length = nil)
503
+ InCondBindHelper.new(bind_name_prefix, array, type, length)
504
+ end
505
+
506
+ private
507
+
508
+ # Converts the specified privilege name to the value passed to the
509
+ # fifth argument of OCISessionBegin().
510
+ #
511
+ # @private
512
+ def to_auth_mode(privilege)
513
+ case privilege
514
+ when :SYSDBA
515
+ 0x00000002 # OCI_SYSDBA in oci.h
516
+ when :SYSOPER
517
+ 0x00000004 # OCI_SYSOPER in oci.h
518
+ when :SYSASM
519
+ if OCI8.oracle_client_version < OCI8::ORAVER_11_1
520
+ raise "SYSASM is not supported on Oracle version #{OCI8.oracle_client_version}"
521
+ end
522
+ 0x00008000 # OCI_SYSASM in oci.h
523
+ when :SYSBACKUP
524
+ if OCI8.oracle_client_version < OCI8::ORAVER_12_1
525
+ raise "SYSBACKUP is not supported on Oracle version #{OCI8.oracle_client_version}"
526
+ end
527
+ 0x00020000 # OCI_SYSBKP in oci.h
528
+ when :SYSDG
529
+ if OCI8.oracle_client_version < OCI8::ORAVER_12_1
530
+ raise "SYSDG is not supported on Oracle version #{OCI8.oracle_client_version}"
531
+ end
532
+ 0x00040000 # OCI_SYSDGD in oci.h
533
+ when :SYSKM
534
+ if OCI8.oracle_client_version < OCI8::ORAVER_12_1
535
+ raise "SYSKM is not supported on Oracle version #{OCI8.oracle_client_version}"
536
+ end
537
+ 0x00080000 # OCI_SYSKMT in oci.h
538
+ when nil
539
+ 0 # OCI_DEFAULT
540
+ else
541
+ raise "unknown privilege type #{privilege}"
542
+ end
543
+ end
544
+
545
+ @@easy_connect_naming_regex = %r{
546
+ ^
547
+ (//)? # preceding double-slash($1)
548
+ (?:\[([\h:]+)\]|([^\s:/]+)) # IPv6 enclosed by square brackets($2) or hostname($3)
549
+ (?::(\d+))? # port($4)
550
+ (?:
551
+ /
552
+ ([^\s:/]+)? # service name($5)
553
+ (?::([^\s:/]+))? # server($6)
554
+ (?:/([^\s:/]+))? # instance name($7)
555
+ )?
556
+ $
557
+ }x
558
+
559
+ # Parse easy connect string as described in https://docs.oracle.com/database/121/NETAG/naming.htm
560
+ # and add TRANSPORT_CONNECT_TIMEOUT or CONNECT_TIMEOUT.
561
+ #
562
+ # @private
563
+ def to_connect_descriptor(database, tcp_connect_timeout, connect_timeout, tcp_keepalive)
564
+ if @@easy_connect_naming_regex =~ database && ($1 || $2 || $4 || $5 || $6 || $7)
565
+ connect_data = []
566
+ connect_data << "(SERVICE_NAME=#$5)"
567
+ connect_data << "(SERVER=#$6)" if $6
568
+ connect_data << "(INSTANCE_NAME=#$7)" if $7
569
+ desc = []
570
+ desc << "(CONNECT_DATA=#{connect_data.join})"
571
+ desc << "(ADDRESS=(PROTOCOL=TCP)(HOST=#{$2 || $3})(PORT=#{$4 || 1521}))"
572
+ if tcp_connect_timeout
573
+ desc << "(TRANSPORT_CONNECT_TIMEOUT=#{tcp_connect_timeout})"
574
+ end
575
+ if connect_timeout
576
+ desc << "(CONNECT_TIMEOUT=#{connect_timeout})"
577
+ end
578
+ if tcp_keepalive
579
+ desc << "(ENABLE=BROKEN)"
580
+ end
581
+ "(DESCRIPTION=#{desc.join})"
582
+ else
583
+ database
584
+ end
585
+ end
586
+ end
587
+
588
+ class OCIError
589
+
590
+ # @overload initialize(message, error_code = nil, sql_stmt = nil, parse_error_offset = nil)
591
+ # Creates a new OCIError object with specified parameters.
592
+ #
593
+ # @param [String] message error message
594
+ # @param [Integer] error_code Oracle error code
595
+ # @param [String] sql_stmt SQL statement
596
+ # @param [Integer] parse_error_offset
597
+ #
598
+ # @example
599
+ # OCIError.new("ORA-00001: unique constraint (%s.%s) violated", 1, 'insert into table_name values (1)', )
600
+ # # => #<OCIError: ORA-00001: unique constraint (%s.%s) violated>
601
+ # #<OCIError: ORA-00923: FROM keyword not found where expected>
602
+ # "select sysdate"
603
+ # 923
604
+ # 14
605
+ #
606
+ # @overload initialize(error_code, *params)
607
+ # Creates a new OCIError object with the error message which corresponds to the specified
608
+ # Oracle error code.
609
+ #
610
+ # @param [Integer] error_code Oracle error code
611
+ # @param [String, ...] params parameters which replace '%s'
612
+ #
613
+ # @example
614
+ # # without parameters
615
+ # OCIError.new(4043)
616
+ # # When NLS_LANG=american_america.AL32UTF8
617
+ # # => #<OCIError: ORA-04043: object %s does not exist>
618
+ # # When NLS_LANG=german_germany.AL32UTF8
619
+ # # => #<OCIError: ORA-04043: Objekt %s ist nicht vorhanden>
620
+ #
621
+ # # with one parameter
622
+ # OCIError.new(4043, 'table_name')
623
+ # # When NLS_LANG=american_america.AL32UTF8
624
+ # # => #<OCIError: ORA-04043: object table_name does not exist>
625
+ # # When NLS_LANG=german_germany.AL32UTF8
626
+ # # => #<OCIError: ORA-04043: Objekt table_name ist nicht vorhanden>
627
+ #
628
+ def initialize(*args)
629
+ if args.length > 0
630
+ if args[0].is_a? Integer
631
+ @code = args.shift
632
+ super(OCI8.error_message(@code).gsub('%s') {|s| args.empty? ? '%s' : args.shift})
633
+ @sql = nil
634
+ @parse_error_offset = nil
635
+ else
636
+ msg, @code, @sql, @parse_error_offset = args
637
+ super(msg)
638
+ end
639
+ else
640
+ super()
641
+ end
642
+ end
643
+ end
644
+
645
+ class OraDate
646
+
647
+ # Returns a Time object which denotes self.
648
+ def to_time
649
+ begin
650
+ Time.local(year, month, day, hour, minute, second)
651
+ rescue ArgumentError
652
+ 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)
653
+ raise RangeError.new(msg)
654
+ end
655
+ end
656
+
657
+ # Returns a Date object which denotes self.
658
+ def to_date
659
+ Date.new(year, month, day)
660
+ end
661
+
662
+ # timezone offset of the time the command started
663
+ # @private
664
+ @@tz_offset = Time.now.utc_offset.to_r/86400
665
+
666
+ # Returns a DateTime object which denotes self.
667
+ #
668
+ # Note that this is not daylight saving time aware.
669
+ # The Time zone offset is that of the time the command started.
670
+ def to_datetime
671
+ DateTime.new(year, month, day, hour, minute, second, @@tz_offset)
672
+ end
673
+
674
+ # @private
675
+ def yaml_initialize(type, val)
676
+ initialize(*val.split(/[ -\/:]+/).collect do |i| i.to_i end)
677
+ end
678
+
679
+ # @private
680
+ def to_yaml(opts = {})
681
+ YAML.quick_emit(object_id, opts) do |out|
682
+ out.scalar(taguri, self.to_s, :plain)
683
+ end
684
+ end
685
+
686
+ # @private
687
+ def to_json(options=nil)
688
+ to_datetime.to_json(options)
689
+ end
690
+ end
691
+
692
+ class OraNumber
693
+
694
+ if defined? Psych and YAML == Psych
695
+
696
+ yaml_tag '!ruby/object:OraNumber'
697
+
698
+ # @private
699
+ def encode_with coder
700
+ coder.scalar = self.to_s
701
+ end
702
+
703
+ # @private
704
+ def init_with coder
705
+ initialize(coder.scalar)
706
+ end
707
+
708
+ else
709
+
710
+ # @private
711
+ def yaml_initialize(type, val)
712
+ initialize(val)
713
+ end
714
+
715
+ # @private
716
+ def to_yaml(opts = {})
717
+ YAML.quick_emit(object_id, opts) do |out|
718
+ out.scalar(taguri, self.to_s, :plain)
719
+ end
720
+ end
721
+ end
722
+
723
+ # @private
724
+ def to_json(options=nil)
725
+ to_s
726
+ end
727
+ end
728
+
729
+ class Numeric
730
+ # Converts +self+ to {OraNumber}.
731
+ #
732
+ # @return [OraNumber]
733
+ def to_onum
734
+ OraNumber.new(self)
735
+ end
736
+ end
737
+
738
+ class String # :nodoc:
739
+
740
+ # Converts +self+ to {OraNumber}.
741
+ # Optional <i>format</i> and <i>nls_params</i> is used as
742
+ # {http://docs.oracle.com/cd/E11882_01/server.112/e17118/functions211.htm Oracle SQL function TO_NUMBER}
743
+ # does.
744
+ #
745
+ # @example
746
+ # '123456.789'.to_onum # => #<OraNumber:123456.789>
747
+ # '123,456.789'.to_onum('999,999,999.999') # => #<OraNumber:123456.789>
748
+ # '123.456,789'.to_onum('999G999G999D999', "NLS_NUMERIC_CHARACTERS = ',.'") # => #<OraNumber:123456.789>
749
+ #
750
+ # @param [String] format
751
+ # @param [String] nls_params
752
+ # @return [OraNumber]
753
+ def to_onum(format = nil, nls_params = nil)
754
+ OraNumber.new(self, format, nls_params)
755
+ end
756
+ end