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,2 @@
1
+ oci8
2
+ oci8.rb
@@ -402,21 +402,6 @@ class Statement < DBI::BaseStatement
402
402
  end
403
403
  end
404
404
 
405
- # DBI_STMT_NEW_ARGS is DBI::StatementHandle.new's arguments except +handle+.
406
- #
407
- # FYI: DBI::StatementHandle.new method signatures are follows:
408
- # 0.2.2: handle, fetchable=false, prepared=true
409
- # 0.4.0: handle, fetchable=false, prepared=true, convert_types=true
410
- # 0.4.1: handle, fetchable=false, prepared=true, convert_types=true, executed=false
411
- begin
412
- DBI::StatementHandle.new(nil, false, true, true, true)
413
- # dbi 0.4.1
414
- DBI_STMT_NEW_ARGS = [true, true, true, true] # :nodoc:
415
- rescue ArgumentError
416
- # dbi 0.4.0 or lower
417
- DBI_STMT_NEW_ARGS = [true] # :nodoc:
418
- end
419
-
420
405
  if defined? ::OCI8::BindType::Base
421
406
  ##
422
407
  ## ruby-oci8 2.0 bind classes.
@@ -506,7 +491,7 @@ if defined? ::OCI8::BindType::Base
506
491
  val = super
507
492
  return nil if val.nil?
508
493
  stmt = DBI::DBD::OCI8::Statement.new(val)
509
- DBI::StatementHandle.new(stmt, *DBI_STMT_NEW_ARGS)
494
+ DBI::StatementHandle.new(stmt, true, false)
510
495
  end
511
496
  end
512
497
  end # BindType
@@ -575,7 +560,7 @@ else
575
560
  return val if val.nil?
576
561
  cur = ::OCI8::Cursor.new(@env, @svc, @ctx, val)
577
562
  stmt = DBI::DBD::OCI8::Statement.new(cur)
578
- DBI::StatementHandle.new(stmt, *DBI_STMT_NEW_ARGS)
563
+ DBI::StatementHandle.new(stmt, true, false)
579
564
  end
580
565
  end
581
566
  end
@@ -1,3 +1,4 @@
1
+
1
2
  # --*- ruby -*--
2
3
  # This is based on yoshidam's oracle.rb.
3
4
  #
@@ -18,1638 +19,56 @@ if RUBY_PLATFORM =~ /cygwin/
18
19
  end
19
20
 
20
21
  require 'oci8lib'
21
- require 'date'
22
- require 'thread'
23
-
24
- class OCIBreak < OCIException
25
- def initialize(errstr = "Canceled by user request.")
26
- super(errstr)
27
- end
28
- end
29
22
 
30
- class OCIDefine # :nodoc:
31
- # define handle of OCILobLocator needs @env and @svc.
32
- def set_handle(env, svc, ctx)
33
- @env = env
34
- @svc = svc
35
- @ctx = ctx
23
+ if OCI8.respond_to? :encoding
24
+ if defined? DEFAULT_OCI8_ENCODING
25
+ OCI8.encoding = DEFAULT_OCI8_ENCODING
26
+ else
27
+ load 'oci8/encoding-init.rb'
36
28
  end
37
29
  end
38
30
 
39
- class OCIBind # :nodoc:
40
- # define handle of OCILobLocator needs @env and @svc.
41
- def set_handle(env, svc, ctx)
42
- @env = env
43
- @svc = svc
44
- @ctx = ctx
45
- end
46
- end
31
+ require 'oci8/oracle_version.rb'
47
32
 
48
33
  class OCI8
49
- @@error_in_initialization = nil
50
- begin
51
- OCIEnv.initialise(OCI_OBJECT)
52
- @@env = OCIEnv.init()
53
- rescue OCIError
54
- # don't raise this error at this time.
55
- @@error_in_initialization = $!
56
- end
57
-
58
- VERSION = '@@OCI8_MODULE_VERSION@@'
59
- CLIENT_VERSION = '@@OCI8_CLIENT_VERSION@@'
60
- # :stopdoc:
61
- RAW = OCI_TYPECODE_RAW
62
- STMT_SELECT = OCI_STMT_SELECT
63
- STMT_UPDATE = OCI_STMT_UPDATE
64
- STMT_DELETE = OCI_STMT_DELETE
65
- STMT_INSERT = OCI_STMT_INSERT
66
- STMT_CREATE = OCI_STMT_CREATE
67
- STMT_DROP = OCI_STMT_DROP
68
- STMT_ALTER = OCI_STMT_ALTER
69
- STMT_BEGIN = OCI_STMT_BEGIN
70
- STMT_DECLARE = OCI_STMT_DECLARE
71
- # :startdoc:
72
-
73
- # sql type (varchar, varchar2)
74
- SQLT_CHR = 1
75
- # sql type (number, double precision, float, real, numeric, int, integer, smallint)
76
- SQLT_NUM = 2
77
- # sql type (long)
78
- SQLT_LNG = 8
79
- # sql type (date)
80
- SQLT_DAT = 12
81
- # sql type (raw)
82
- SQLT_BIN = 23
83
- # sql type (long raw)
84
- SQLT_LBI = 24
85
- # sql type (char)
86
- SQLT_AFC = 96
87
- # sql type (binary_float)
88
- SQLT_IBFLOAT = 100
89
- # sql type (binary_double)
90
- SQLT_IBDOUBLE = 101
91
- # sql type (rowid)
92
- SQLT_RDD = 104
93
- # sql type (clob)
94
- SQLT_CLOB = 112
95
- # sql type (blob)
96
- SQLT_BLOB = 113
97
- # sql type (bfile)
98
- SQLT_BFILE = 114
99
- # sql type (result set)
100
- SQLT_RSET = 116
101
- # sql type (timestamp), not supported yet.
34
+ ORAVER_8_0 = OCI8::OracleVersion.new(8, 0)
35
+ ORAVER_8_1 = OCI8::OracleVersion.new(8, 1)
36
+ ORAVER_9_0 = OCI8::OracleVersion.new(9, 0)
37
+ ORAVER_9_2 = OCI8::OracleVersion.new(9, 2)
38
+ ORAVER_10_1 = OCI8::OracleVersion.new(10, 1)
39
+ ORAVER_10_2 = OCI8::OracleVersion.new(10, 2)
40
+ ORAVER_11_1 = OCI8::OracleVersion.new(11, 1)
41
+
42
+ @@oracle_client_version = OCI8::OracleVersion.new(self.oracle_client_vernum)
43
+
44
+ # :call-seq:
45
+ # OCI8.oracle_client_version -> oraver
102
46
  #
103
- # If you want to fetch a timestamp before native timestamp data type
104
- # will be supported, fetch data as an OraDate by adding the following
105
- # code to your code.
106
- # OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::OraDate
107
- SQLT_TIMESTAMP = 187
108
- # sql type (timestamp with time zone), not supported yet
109
- SQLT_TIMESTAMP_TZ = 188
110
- # sql type (interval year to month), not supported yet
111
- SQLT_INTERVAL_YM = 189
112
- # sql type (interval day to second), not supported yet
113
- SQLT_INTERVAL_DS = 190
114
- # sql type (timestamp with local time zone), not supported yet
115
- SQLT_TIMESTAMP_LTZ = 232
116
-
117
- # charset form
118
- SQLCS_IMPLICIT = 1
119
- SQLCS_NCHAR = 2
120
-
121
- # mapping of sql type number to sql type name.
122
- SQLT_NAMES = {}
123
- constants.each do |name|
124
- next if name.index("SQLT_") != 0
125
- val = const_get name.intern
126
- if val.is_a? Fixnum
127
- SQLT_NAMES[val] = name
128
- end
129
- end
130
-
131
- module Util # :nodoc:
132
- CTX_EXECFLAG = 0
133
- CTX_MUTEX = 1
134
- CTX_THREAD = 2
135
- CTX_LONG_READ_LEN = 3
136
-
137
- def do_ocicall(ctx)
138
- sleep_time = 0.01
139
- ctx[CTX_MUTEX].lock
140
- ctx[CTX_THREAD] = Thread.current
141
- begin
142
- yield
143
- rescue OCIStillExecuting # non-blocking mode
144
- ctx[CTX_MUTEX].unlock
145
- sleep(sleep_time)
146
- ctx[CTX_MUTEX].lock
147
- if ctx[CTX_THREAD].nil?
148
- raise OCIBreak
149
- end
150
- # expand sleep time to prevent busy loop.
151
- sleep_time *= 2 if sleep_time < 0.5
152
- retry
153
- ensure
154
- ctx[CTX_THREAD] = nil
155
- ctx[CTX_MUTEX].unlock
156
- end
157
- end # do_ocicall
158
- end
159
- include Util
160
-
161
- def parse_connect_string(connstr)
162
- if connstr !~ /^([^(\s|\@)]*)\/([^(\s|\@)]*)(?:\@(\S+))?(?:\s+as\s+(\S*)\s*)?$/i
163
- raise ArgumentError, %Q{invalid connect string "#{connstr}" (expect "username/password[@(tns_name|//host[:port]/service_name)][ as (sysdba|sysoper)]")}
164
- end
165
- uid, pswd, conn, privilege = $1, $2, $3, $4
166
- case privilege.upcase
167
- when 'SYSDBA'
168
- privilege = :SYSDBA
169
- when 'SYSOPER'
170
- privilege = :SYSOPER
171
- end if privilege
172
- if uid.length == 0 && pswd.length == 0
173
- # external credential
174
- uid = nil
175
- pswd = nil
176
- end
177
- return uid, pswd, conn, privilege
178
- end
179
- private :parse_connect_string
180
-
181
- def initialize(*args)
182
- raise @@error_in_initialization if @@error_in_initialization
183
- case args.length
184
- when 1
185
- uid, pswd, conn, privilege = parse_connect_string(args[0])
186
- when 2, 3, 4
187
- uid, pswd, conn, privilege = *args
188
- else
189
- raise ArgumentError, "wrong number of arguments (#{args.length} for 1..4)"
190
- end
191
- case privilege
192
- when nil
193
- @privilege = nil
194
- when :SYSDBA
195
- @privilege = OCI_SYSDBA
196
- when :SYSOPER
197
- @privilege = OCI_SYSOPER
198
- else
199
- raise ArgumentError, "invalid privilege name #{privilege} (expect :SYSDBA, :SYSOPER or nil)"
200
- end
201
-
202
- @prefetch_rows = nil
203
- @ctx = [0, Mutex.new, nil, 65535]
204
- if @privilege or (uid.nil? and pswd.nil?)
205
- @svc = @@env.alloc(OCISvcCtx)
206
- @srv = @@env.alloc(OCIServer)
207
- @auth = @@env.alloc(OCISession)
208
- @privilege ||= OCI_DEFAULT
209
-
210
- if uid.nil? and pswd.nil?
211
- # external credential
212
- cred = OCI_CRED_EXT
213
- else
214
- # RDBMS credential
215
- cred = OCI_CRED_RDBMS
216
- @auth.attrSet(OCI_ATTR_USERNAME, uid)
217
- @auth.attrSet(OCI_ATTR_PASSWORD, pswd)
218
- end
219
- do_ocicall(@ctx) { @srv.attach(conn) }
220
- begin
221
- @svc.attrSet(OCI_ATTR_SERVER, @srv)
222
- do_ocicall(@ctx) { @auth.begin(@svc, cred, @privilege) }
223
- @svc.attrSet(OCI_ATTR_SESSION, @auth)
224
- rescue
225
- @srv.detach()
226
- raise
227
- end
228
- else
229
- @svc = @@env.logon(uid, pswd, conn)
230
- end
231
- @svc.instance_variable_set(:@env, @@env)
232
- end # initialize
233
-
234
- def logoff
235
- rollback()
236
- if @privilege
237
- do_ocicall(@ctx) { @auth.end(@svc) }
238
- do_ocicall(@ctx) { @srv.detach() }
239
- else
240
- @svc.logoff
241
- end
242
- @svc.free()
243
- true
244
- end # logoff
245
-
246
- def exec(sql, *bindvars)
247
- cursor = OCI8::Cursor.new(@@env, @svc, @ctx)
248
- cursor.prefetch_rows = @prefetch_rows if @prefetch_rows
249
- cursor.parse(sql)
250
- if cursor.type == OCI_STMT_SELECT && ! block_given?
251
- cursor.exec(*bindvars)
252
- cursor
253
- else
254
- begin
255
- ret = cursor.exec(*bindvars)
256
- case cursor.type
257
- when OCI_STMT_SELECT
258
- cursor.fetch { |row| yield(row) } # for each row
259
- cursor.row_count()
260
- when OCI_STMT_BEGIN, OCI_STMT_DECLARE # PL/SQL block
261
- ary = []
262
- cursor.keys.sort.each do |key|
263
- ary << cursor[key]
264
- end
265
- ary
266
- else
267
- ret
268
- end
269
- ensure
270
- cursor.close
271
- end
272
- end
273
- end # exec
274
-
275
- def parse(sql)
276
- cursor = OCI8::Cursor.new(@@env, @svc, @ctx)
277
- cursor.prefetch_rows = @prefetch_rows if @prefetch_rows
278
- cursor.parse(sql)
279
- cursor
280
- end # parse
281
-
282
- def commit
283
- do_ocicall(@ctx) { @svc.commit }
284
- self
285
- end # commit
286
-
287
- def rollback
288
- do_ocicall(@ctx) { @svc.rollback }
289
- self
290
- end # rollback
291
-
292
- def autocommit?
293
- (@ctx[CTX_EXECFLAG] & OCI_COMMIT_ON_SUCCESS) == OCI_COMMIT_ON_SUCCESS
294
- end # autocommit?
295
-
296
- # add alias compatible with 'Oracle7 Module for Ruby'.
297
- alias autocommit autocommit?
298
-
299
- def autocommit=(ac)
300
- if ac
301
- commit()
302
- @ctx[CTX_EXECFLAG] |= OCI_COMMIT_ON_SUCCESS
303
- else
304
- @ctx[CTX_EXECFLAG] &= ~OCI_COMMIT_ON_SUCCESS
305
- end
306
- ac
307
- end # autocommit=
308
-
309
- def prefetch_rows=(rows)
310
- @prefetch_rows = rows
311
- end
312
-
313
- def non_blocking?
314
- @svc.attrGet(OCI_ATTR_NONBLOCKING_MODE)
315
- end # non_blocking?
316
-
317
- def non_blocking=(nb)
318
- if (nb ? true : false) != non_blocking?
319
- # If the argument and the current status are different,
320
- # toggle blocking / non-blocking.
321
- @srv = @svc.attrGet(OCI_ATTR_SERVER) unless @srv
322
- @srv.attrSet(OCI_ATTR_NONBLOCKING_MODE, nil)
323
- end
324
- end # non_blocking=
325
-
326
- def break
327
- @ctx[CTX_MUTEX].synchronize do
328
- @svc.break()
329
- unless @ctx[CTX_THREAD].nil?
330
- @ctx[CTX_THREAD].wakeup()
331
- @ctx[CTX_THREAD] = nil
332
- if @svc.respond_to?("reset")
333
- begin
334
- @svc.reset()
335
- rescue OCIError
336
- raise if $!.code != 1013 # ORA-01013
337
- end
338
- end
339
- end
340
- end
341
- end # break
342
-
343
- def long_read_len
344
- @ctx[OCI8::Util::CTX_LONG_READ_LEN]
345
- end
346
-
347
- def long_read_len=(len)
348
- @ctx[OCI8::Util::CTX_LONG_READ_LEN] = len
349
- end
350
-
351
- def describe_table(table_name)
352
- desc = @@env.alloc(OCIDescribe)
353
- desc.attrSet(OCI_ATTR_DESC_PUBLIC, -1)
354
- do_ocicall(@ctx) { desc.describeAny(@svc, table_name.to_s, OCI_PTYPE_UNK) }
355
- param = desc.attrGet(OCI_ATTR_PARAM)
356
-
357
- case param.attrGet(OCI_ATTR_PTYPE)
358
- when OCI_PTYPE_TABLE
359
- OCI8::Metadata::Table.new(param)
360
- when OCI_PTYPE_VIEW
361
- OCI8::Metadata::View.new(param)
362
- when OCI_PTYPE_SYN
363
- schema_name = param.attrGet(OCI_ATTR_SCHEMA_NAME)
364
- name = param.attrGet(OCI_ATTR_NAME)
365
- link = param.attrGet(OCI_ATTR_LINK)
366
- if link.length != 0
367
- translated_name = schema_name + '.' + name + '@' + link
368
- else
369
- translated_name = schema_name + '.' + name
370
- end
371
- describe_table(translated_name)
372
- else
373
- raise OCIError.new("ORA-04043: object #{table_name} does not exist", 4043)
374
- end
375
- end
376
-
377
- module BindType
378
- # get/set String
379
- String = Object.new
380
- class << String
381
- def fix_type(env, val, length, precision, scale)
382
- [OCI8::SQLT_CHR, val, length || (val.nil? ? nil : val.length)]
383
- end
384
- end
385
-
386
- # get/set RAW
387
- RAW = Object.new
388
- class << RAW
389
- def fix_type(env, val, length, precision, scale)
390
- [OCI8::SQLT_BIN, val, length || (val.nil? ? nil : val.length)]
391
- end
392
- end
393
-
394
- # get/set OraDate
395
- OraDate = Object.new
396
- class << OraDate
397
- def fix_type(env, val, length, precision, scale)
398
- [OCI8::SQLT_DAT, val, nil]
399
- end
400
- end
401
-
402
- # get/set Time
403
- Time = Object.new
404
- class << Time
405
- def fix_type(env, val, length, precision, scale)
406
- [OCI8::SQLT_DAT, val, nil]
407
- end
408
- def decorate(b)
409
- def b.set(val)
410
- super(val && ::OraDate.new(val.year, val.mon, val.mday, val.hour, val.min, val.sec))
411
- end
412
- def b.get()
413
- (val = super()) && val.to_time
414
- end
415
- end
416
- end
417
-
418
- # get/set Date
419
- Date = Object.new
420
- class << Date
421
- def fix_type(env, val, length, precision, scale)
422
- [OCI8::SQLT_DAT, val, nil]
423
- end
424
- def decorate(b)
425
- def b.set(val)
426
- super(val && ::OraDate.new(val.year, val.mon, val.mday))
427
- end
428
- def b.get()
429
- (val = super()) && val.to_date
430
- end
431
- end
432
- end
433
-
434
- if defined? ::DateTime # ruby 1.8.0 or upper
435
- # get/set DateTime
436
- DateTime = Object.new
437
- class << DateTime
438
- def fix_type(env, val, length, precision, scale)
439
- [OCI8::SQLT_DAT, val, nil]
440
- end
441
- def decorate(b)
442
- def b.set(val)
443
- super(val && ::OraDate.new(val.year, val.mon, val.mday, val.hour, val.min, val.sec))
444
- end
445
- def b.get()
446
- (val = super()) && val.to_datetime
447
- end
448
- end
449
- end
450
- end
451
-
452
- # get/set Float
453
- Float = Object.new
454
- class << Float
455
- def fix_type(env, val, length, precision, scale)
456
- [::Float, val, nil]
457
- end
458
- end
459
-
460
- if defined? OCI_TYPECODE_BDOUBLE
461
- BinaryDouble = Object.new
462
- class << BinaryDouble
463
- def fix_type(env, val, length, precision, scale)
464
- [SQLT_IBDOUBLE, val, nil]
465
- end
466
- end
467
- end
468
-
469
- # get/set Fixnum
470
- Fixnum = Object.new
471
- class << Fixnum
472
- def fix_type(env, val, length, precision, scale)
473
- [::Fixnum, val, nil]
474
- end
475
- end
476
-
477
- # get/set Integer
478
- Integer = Object.new
479
- class << Integer
480
- def fix_type(env, val, length, precision, scale)
481
- [::Integer, val, nil]
482
- end
483
- end
484
-
485
- # get/set OraNumber
486
- OraNumber = Object.new
487
- class << OraNumber
488
- def fix_type(env, val, length, precision, scale)
489
- [::OraNumber, val, nil]
490
- end
491
- end
492
-
493
- # get/set Number (for OCI8::SQLT_NUM)
494
- Number = Object.new
495
- class << Number
496
- def fix_type(env, val, length, precision, scale)
497
- if scale == -127
498
- if precision == 0
499
- # NUMBER declared without its scale and precision. (Oracle 9.2.0.3 or above)
500
- ::OCI8::BindType::Mapping[:number_no_prec_setting].fix_type(env, val, length, precision, scale)
501
- else
502
- # FLOAT or FLOAT(p)
503
- [::Float, val, nil]
504
- end
505
- elsif scale == 0
506
- if precision == 0
507
- # NUMBER whose scale and precision is unknown
508
- # or
509
- # NUMBER declared without its scale and precision. (Oracle 9.2.0.2 or below)
510
- ::OCI8::BindType::Mapping[:number_unknown_prec].fix_type(env, val, length, precision, scale)
511
- elsif precision <= 9
512
- # NUMBER(p, 0); p is less than or equals to the precision of Fixnum
513
- [::Fixnum, val, nil]
514
- else
515
- # NUMBER(p, 0); p is greater than the precision of Fixnum
516
- [::Integer, val, nil]
517
- end
518
- else
519
- # NUMBER(p, s)
520
- if precision < 15 # the precision of double.
521
- [::Float, val, nil]
522
- else
523
- # use BigDecimal instead?
524
- [::OraNumber, val, nil]
525
- end
526
- end
527
- end
528
- end
529
-
530
- # get/set OCIRowid
531
- OCIRowid = Object.new
532
- class << OCIRowid
533
- def fix_type(env, val, length, precision, scale)
534
- [OCI8::SQLT_RDD, nil, val]
535
- end
536
- end
537
-
538
- # get/set BLOB
539
- BLOB = Object.new
540
- class << BLOB
541
- def check_type(val)
542
- raise ArgumentError, "invalid argument: #{val.class} (expect OCI8::BLOB)" unless val.is_a? OCI8::BLOB
543
- end
544
- def fix_type(env, val, length, precision, scale)
545
- unless val.nil?
546
- check_type(val)
547
- val = val.instance_variable_get(:@locator)
548
- end
549
- [OCI8::SQLT_BLOB, nil, val]
550
- end
551
- def decorate(b)
552
- def b.set(val)
553
- check_type(val)
554
- val = val.instance_variable_get(:@locator)
555
- super(val)
556
- end
557
- def b.get()
558
- (val = super()) && OCI8::BLOB.new(@svc, val.clone(@svc))
559
- end
560
- end
561
- end
562
-
563
- # get/set CLOB
564
- CLOB = Object.new
565
- class << CLOB
566
- def check_type(val)
567
- raise ArgumentError, "invalid argument: #{val.class} (expect OCI8::CLOB)" unless val.is_a? OCI8::CLOB
568
- end
569
- def fix_type(env, val, length, precision, scale)
570
- unless val.nil?
571
- check_type(val)
572
- val = val.instance_variable_get(:@locator)
573
- end
574
- [OCI8::SQLT_CLOB, nil, val]
575
- end
576
- def decorate(b)
577
- def b.set(val)
578
- check_type(val)
579
- val = val.instance_variable_get(:@locator)
580
- super(val)
581
- end
582
- def b.get()
583
- (val = super()) && OCI8::CLOB.new(@svc, val.clone(@svc))
584
- end
585
- end
586
- end
587
-
588
- # get/set NCLOB
589
- NCLOB = Object.new
590
- class << NCLOB
591
- def check_type(val)
592
- raise ArgumentError, "invalid argument: #{val.class} (expect OCI8::NCLOB)" unless val.is_a? OCI8::NCLOB
593
- end
594
- def fix_type(env, val, length, precision, scale)
595
- unless val.nil?
596
- check_type(val)
597
- val = val.instance_variable_get(:@locator)
598
- end
599
- [OCI8::SQLT_CLOB, nil, val]
600
- end
601
- def decorate(b)
602
- b.attrSet(OCI_ATTR_CHARSET_FORM, SQLCS_NCHAR)
603
- def b.set(val)
604
- check_type(val)
605
- val = val.instance_variable_get(:@locator)
606
- super(val)
607
- end
608
- def b.get()
609
- (val = super()) && OCI8::NCLOB.new(@svc, val.clone(@svc))
610
- end
611
- end
612
- end
613
-
614
- # get/set BFILE
615
- BFILE = Object.new
616
- class << BFILE
617
- def check_type(val)
618
- raise ArgumentError, "invalid argument: #{val.class} (expect OCI8::BFILE)" unless val.is_a? OCI8::BFILE
619
- end
620
- def fix_type(env, val, length, precision, scale)
621
- unless val.nil?
622
- check_type(val)
623
- val = val.instance_variable_get(:@locator)
624
- end
625
- [OCI8::SQLT_BFILE, nil, val]
626
- end
627
- def decorate(b)
628
- def b.set(val)
629
- check_type(val)
630
- val = val.instance_variable_get(:@locator)
631
- super(val)
632
- end
633
- def b.get()
634
- (val = super()) && OCI8::BFILE.new(@svc, val.clone(@svc))
635
- end
636
- end
637
- end
638
-
639
- # get Cursor
640
- Cursor = Object.new
641
- class << Cursor
642
- def fix_type(env, val, length, precision, scale)
643
- [OCI8::SQLT_RSET, nil, val]
644
- end
645
- def decorate(b)
646
- def b.get()
647
- (val = super()) && OCI8::Cursor.new(@env, @svc, @ctx, val)
648
- end
649
- def b.pre_fetch_hook()
650
- set(@env.alloc(OCIStmt))
651
- end
652
- end
653
- end
654
-
655
- Mapping = {}
656
- end # BindType
657
-
658
- class Cursor
659
-
660
- include OCI8::Util
661
-
662
- # for backward compatibility
663
- def self.select_number_as=(val) # :nodoc:
664
- if val == ::Fixnum
665
- bind_type = ::OCI8::BindType::Fixnum
666
- elsif val == ::Integer
667
- bind_type = ::OCI8::BindType::Integer
668
- elsif val == ::Float
669
- bind_type = ::OCI8::BindType::Float
670
- else
671
- raise ArgumentError, "must be Fixnum, Integer or Float"
672
- end
673
- ::OCI8::BindType::Mapping[:number_unknown_prec] = bind_type
674
- end
675
-
676
- # for backward compatibility
677
- def self.select_number_as # :nodoc:
678
- ::OCI8::BindType::Mapping[:number_unknown_prec].fix_type(nil, nil, nil, nil, nil)[0]
679
- end
680
-
681
- def initialize(env, svc, ctx, stmt = nil)
682
- if Process.pid != svc.pid
683
- raise "The connection cannot be reused in the forked process."
684
- end
685
- @env = env
686
- @svc = svc
687
- @ctx = ctx
688
- @binds = nil
689
- @parms = []
690
- @defns = nil
691
- if stmt.nil?
692
- @stmt = @env.alloc(OCIStmt)
693
- @stmttype = nil
694
- else
695
- @stmt = stmt
696
- @stmttype = @stmt.attrGet(OCI_ATTR_STMT_TYPE)
697
- define_columns()
698
- end
699
- end # initialize
700
-
701
- def parse(sql)
702
- free_binds()
703
- @parms = []
704
- @stmt.prepare(sql)
705
- @stmttype = do_ocicall(@ctx) { @stmt.attrGet(OCI_ATTR_STMT_TYPE) }
706
- end # parse
707
-
708
- def define(pos, type, length = nil)
709
- @defns = [] if @defns.nil?
710
- if type == String and length.nil?
711
- length = 4000
712
- end
713
- b = bind_or_define(:define, pos, nil, type, length, nil, nil, false)
714
- @defns[pos].free() unless @defns[pos].nil?
715
- @defns[pos] = b
716
- self
717
- end # define
718
-
719
- def bind_param(key, val, type = nil, length = nil)
720
- @binds = {} if @binds.nil?
721
- b = bind_or_define(:bind, key, val, type, length, nil, nil, false)
722
- @binds[key].free() unless @binds[key].nil?
723
- @binds[key] = b
724
- self
725
- end # bind_param
726
-
727
- # get bind value
728
- def [](key)
729
- if @binds.nil? or @binds[key].nil?
730
- return nil
731
- end
732
- @binds[key].get()
733
- end
734
-
735
- # set bind value
736
- def []=(key, val)
737
- if @binds.nil? or @binds[key].nil?
738
- return nil
739
- end
740
- @binds[key].set(val)
741
- end
742
-
743
- # get bind keys
744
- def keys
745
- if @binds.nil?
746
- []
747
- else
748
- @binds.keys
749
- end
750
- end
751
-
752
- def exec(*bindvars)
753
- bind_params(*bindvars)
754
- case @stmttype
755
- when OCI_STMT_SELECT
756
- do_ocicall(@ctx) { @stmt.execute(@svc, 0, OCI_DEFAULT) }
757
- define_columns()
758
- else
759
- do_ocicall(@ctx) { @stmt.execute(@svc, 1, @ctx[CTX_EXECFLAG]) }
760
- @stmt.attrGet(OCI_ATTR_ROW_COUNT)
761
- end
762
- end # exec
763
-
764
- def type
765
- @stmttype
766
- end
767
-
768
- def row_count
769
- @stmt.attrGet(OCI_ATTR_ROW_COUNT)
770
- end
771
-
772
- def get_col_names
773
- @parms.collect do |p|
774
- do_ocicall(@ctx) { p.attrGet(OCI_ATTR_NAME) }
775
- end
776
- end # get_col_names
777
-
778
- # add alias compatible with 'Oracle7 Module for Ruby'.
779
- alias getColNames get_col_names
780
-
781
- def column_metadata
782
- @parms.collect do |p|
783
- OCI8::Metadata::Column.new(p)
784
- end
785
- end
786
-
787
- def fetch
788
- if iterator?
789
- while ret = fetch_a_row()
790
- yield(ret)
791
- end
792
- else
793
- fetch_a_row()
794
- end
795
- end # fetch
796
-
797
- def fetch_hash
798
- if iterator?
799
- while ret = fetch_a_hash_row()
800
- yield(ret)
801
- end
802
- else
803
- fetch_a_hash_row
804
- end
805
- end # fetch_hash
806
-
807
- def close
808
- @env = nil
809
- @svc = nil
810
- free_defns()
811
- free_binds()
812
- @stmt.free()
813
- @parms = nil
814
- @stmttype = nil
815
- end # close
816
-
817
- # Get the rowid of the last inserted/updated/deleted row.
818
- def rowid
819
- # get the binary rowid
820
- rid = @stmt.attrGet(OCI_ATTR_ROWID)
821
- # convert it to a string rowid.
822
- if rid.respond_to? :to_s
823
- # (Oracle 9.0 or upper)
824
- rid.to_s
825
- else
826
- # (Oracle 8.1 or lower)
827
- stmt = @env.alloc(OCIStmt)
828
- stmt.prepare('begin :1 := :2; end;')
829
- b = stmt.bindByPos(1, OCI8::SQLT_CHR, 64)
830
- stmt.bindByPos(2, OCI8::SQLT_RDD, rid)
831
- do_ocicall(@ctx) { stmt.execute(@svc, 1, OCI_DEFAULT) }
832
- str_rid = b.get()
833
- stmt.free()
834
- str_rid
835
- end
836
- end
837
-
838
- def prefetch_rows=(rows)
839
- @stmt.attrSet(OCI_ATTR_PREFETCH_ROWS, rows)
840
- end
841
-
842
- private
843
-
844
- def bind_or_define(bind_type, key, val, type, length, precision, scale, strict_check)
845
- if type.nil?
846
- if val.nil?
847
- raise "bind type is not given." if type.nil?
848
- else
849
- if val.class == Class
850
- type = val
851
- val = nil
852
- else
853
- type = val.class
854
- end
855
- end
856
- end
857
-
858
- binder = OCI8::BindType::Mapping[type]
859
- if binder
860
- type, val, option = binder.fix_type(@env, val, length, precision, scale)
861
- else
862
- if strict_check
863
- raise "unsupported datatype: #{SQLT_NAMES[type] ? SQLT_NAMES[type] : type}"
864
- else
865
- option = length
866
- end
867
- end
868
-
869
- case bind_type
870
- when :bind
871
- if key.is_a? Fixnum
872
- b = @stmt.bindByPos(key, type, option)
873
- else
874
- b = @stmt.bindByName(key, type, option)
875
- end
876
- when :define
877
- b = @stmt.defineByPos(key, type, option)
878
- end
879
- b.set_handle(@env, @svc, @ctx)
880
-
881
- if binder && binder.respond_to?(:decorate)
882
- # decorate the bind handle.
883
- binder.decorate(b)
884
- end
885
-
886
- b.set(val) unless val.nil?
887
- b
888
- end # bind_or_define
889
-
890
- def define_columns
891
- num_cols = @stmt.attrGet(OCI_ATTR_PARAM_COUNT)
892
- 1.upto(num_cols) do |i|
893
- @parms[i - 1] = @stmt.paramGet(i)
894
- end
895
- @defns = Array.new(@parms.size) if @defns.nil?
896
- 1.upto(num_cols) do |i|
897
- @defns[i] = define_a_column(i) if @defns[i].nil?
898
- end
899
- num_cols
900
- end # define_columns
901
-
902
- def define_a_column(i)
903
- p = @parms[i - 1]
904
- datatype = do_ocicall(@ctx) { p.attrGet(OCI_ATTR_DATA_TYPE) }
905
- datasize = do_ocicall(@ctx) { p.attrGet(OCI_ATTR_DATA_SIZE) }
906
- precision = do_ocicall(@ctx) { p.attrGet(OCI_ATTR_PRECISION) }
907
- scale = do_ocicall(@ctx) { p.attrGet(OCI_ATTR_SCALE) }
908
- csfrm = nil
909
-
910
- case datatype
911
- when SQLT_CHR, SQLT_AFC
912
- # character size may become large on character set conversion.
913
- # The length of a half-width kana is one in Shift_JIS, two in EUC-JP,
914
- # three in UTF-8.
915
- datasize *= 3
916
- when SQLT_LNG, SQLT_LBI
917
- datasize = @ctx[OCI8::Util::CTX_LONG_READ_LEN]
918
- when SQLT_CLOB
919
- datatype = :nclob if p.attrGet(OCI_ATTR_CHARSET_FORM) == SQLCS_NCHAR
920
- when SQLT_BIN
921
- datasize *= 2 if OCI8::BindType::Mapping[datatype] == OCI8::BindType::String
922
- when SQLT_RDD
923
- datasize = 64
924
- end
925
-
926
- bind_or_define(:define, i, nil, datatype, datasize, precision, scale, true)
927
- end # define_a_column
928
-
929
- def bind_params(*bindvars)
930
- bindvars.each_with_index do |val, i|
931
- if val.is_a? Array
932
- bind_param(i + 1, val[0], val[1], val[2])
933
- else
934
- bind_param(i + 1, val)
935
- end
936
- end
937
- end # bind_params
938
-
939
- def fetch_a_row
940
- @defns.each do |d|
941
- d.pre_fetch_hook if d.respond_to? :pre_fetch_hook
942
- end
943
- res = do_ocicall(@ctx) { @stmt.fetch() }
944
- return nil if res.nil?
945
- res.collect do |r| r.get() end
946
- end # fetch_a_row
947
-
948
- def fetch_a_hash_row
949
- if rs = fetch_a_row()
950
- ret = {}
951
- @parms.each do |p|
952
- ret[p.attrGet(OCI_ATTR_NAME)] = rs.shift
953
- end
954
- ret
955
- else
956
- nil
957
- end
958
- end # fetch_a_hash_row
959
-
960
- def free_defns
961
- unless @defns.nil?
962
- @defns.each do |b|
963
- b.free() unless b.nil?
964
- end
965
- end
966
- @defns = nil
967
- end # free_defns
968
-
969
- def free_binds
970
- unless @binds.nil?
971
- @binds.each_value do |b|
972
- b.free()
973
- end
974
- end
975
- @binds = nil
976
- end # free_binds
977
- end # OCI8::Cursor
978
-
979
- class LOB
980
- attr :pos
981
- def initialize(svc, val)
982
- svc = svc.instance_variable_get(:@svc) if svc.is_a? OCI8
983
- raise "invalid argument" unless svc.is_a? OCISvcCtx
984
- @env = svc.instance_variable_get(:@env)
985
- @svc = svc
986
- @csid = 0
987
- @pos = 0
988
- if val.is_a? OCILobLocator
989
- @locator = val
990
- else
991
- @locator = @env.alloc(OCILobLocator)
992
- @locator.create_temporary(@svc, @csid, @csfrm, @lobtype, false, nil)
993
- val.nil? || write(val.to_s)
994
- end
995
- end
996
-
997
- def available?
998
- @locator.is_initialized?(@env)
999
- end
1000
-
1001
- def truncate(len)
1002
- raise "uninitialized LOB" unless available?
1003
- @locator.trim(@svc, len)
1004
- self
1005
- end
1006
-
1007
- def read(readlen = nil)
1008
- rest = self.size - @pos
1009
- return nil if rest == 0 # eof.
1010
- if readlen.nil? or readlen > rest
1011
- readlen = rest # read until EOF.
1012
- end
1013
- begin
1014
- rv = @locator.read(@svc, @pos + 1, readlen, @csid, @csfrm)
1015
- rescue OCIError
1016
- raise if $!.code != 22289
1017
- # ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB.
1018
- open
1019
- retry
1020
- end
1021
- @pos += readlen
1022
- rv
1023
- end
1024
-
1025
- def write(data)
1026
- raise "uninitialized LOB" unless available?
1027
- size = @locator.write(@svc, @pos + 1, data, @csid, @csfrm)
1028
- @pos += size
1029
- size
1030
- end
1031
-
1032
- def size
1033
- raise "uninitialized LOB" unless available?
1034
- begin
1035
- rv = @locator.getLength(@svc)
1036
- rescue OCIError
1037
- raise if $!.code != 22289
1038
- # ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB.
1039
- open
1040
- retry
1041
- end
1042
- rv
1043
- end
1044
-
1045
- def size=(len)
1046
- raise "uninitialized LOB" unless available?
1047
- @locator.trim(@svc, len)
1048
- len
1049
- end
1050
-
1051
- def chunk_size # in bytes.
1052
- raise "uninitialized LOB" unless available?
1053
- @locator.getChunkSize(@svc)
1054
- end
1055
-
1056
- def eof?
1057
- @pos == size
1058
- end
1059
-
1060
- def tell
1061
- @pos
1062
- end
1063
-
1064
- def seek(pos, whence = IO::SEEK_SET)
1065
- length = size
1066
- case whence
1067
- when IO::SEEK_SET
1068
- @pos = pos
1069
- when IO::SEEK_CUR
1070
- @pos += pos
1071
- when IO::SEEK_END
1072
- @pos = length + pos
1073
- end
1074
- @pos = length if @pos >= length
1075
- @pos = 0 if @pos < 0
1076
- self
1077
- end
1078
-
1079
- def rewind
1080
- @pos = 0
1081
- self
1082
- end
1083
-
1084
- def close
1085
- @locator.free()
1086
- end
1087
-
1088
- end
1089
-
1090
- class BLOB < LOB
1091
- def initialize(*arg)
1092
- @lobtype = 1
1093
- @csfrm = SQLCS_IMPLICIT
1094
- super(*arg)
1095
- end
1096
- end
1097
-
1098
- class CLOB < LOB
1099
- def initialize(*arg)
1100
- @lobtype = 2
1101
- @csfrm = SQLCS_IMPLICIT
1102
- super(*arg)
1103
- end
1104
- end
1105
-
1106
- class NCLOB < LOB
1107
- def initialize(*arg)
1108
- @lobtype = 2
1109
- @csfrm = SQLCS_NCHAR
1110
- super(*arg)
1111
- end
1112
- end
1113
-
1114
- class BFILE < LOB
1115
- attr_reader :dir_alias
1116
- attr_reader :filename
1117
- def initialize(svc, locator)
1118
- raise "invalid argument" unless svc.is_a? OCISvcCtx
1119
- raise "invalid argument" unless locator.is_a? OCIFileLocator
1120
- @env = svc.instance_variable_get(:@env)
1121
- @svc = svc
1122
- @locator = locator
1123
- @pos = 0
1124
- @dir_alias, @filename = @locator.name(@env)
1125
- end
1126
-
1127
- def dir_alias=(val)
1128
- @locator.set_name(@env, val, @filename)
1129
- @dir_alias = val
1130
- end
1131
-
1132
- def filename=(val)
1133
- @locator.set_name(@env, @dir_alias, val)
1134
- @filename = val
1135
- end
1136
-
1137
- def truncate(len)
1138
- raise RuntimeError, "cannot modify a read-only BFILE object"
1139
- end
1140
- def write(data)
1141
- raise RuntimeError, "cannot modify a read-only BFILE object"
1142
- end
1143
- def size=(len)
1144
- raise RuntimeError, "cannot modify a read-only BFILE object"
1145
- end
1146
-
1147
- def open
1148
- begin
1149
- @locator.open(@svc, :file_readonly)
1150
- rescue OCIError
1151
- raise if $!.code != 22290
1152
- # ORA-22290: operation would exceed the maximum number of opened files or LOBs.
1153
- @svc.close_all_files
1154
- @locator.open(@svc, :file_readonly)
1155
- end
1156
- end
1157
-
1158
- def exists?
1159
- @locator.exists?(@svc)
1160
- end
1161
- end
1162
-
1163
- # bind or explicitly define
1164
- BindType::Mapping[::String] = BindType::String
1165
- BindType::Mapping[::OCI8::RAW] = BindType::RAW
1166
- BindType::Mapping[::OraDate] = BindType::OraDate
1167
- BindType::Mapping[::Time] = BindType::Time
1168
- BindType::Mapping[::Date] = BindType::Date
1169
- BindType::Mapping[::DateTime] = BindType::DateTime if defined? DateTime
1170
- BindType::Mapping[::OCIRowid] = BindType::OCIRowid
1171
- BindType::Mapping[::OCI8::BLOB] = BindType::BLOB
1172
- BindType::Mapping[::OCI8::CLOB] = BindType::CLOB
1173
- BindType::Mapping[::OCI8::NCLOB] = BindType::NCLOB
1174
- BindType::Mapping[::OCI8::BFILE] = BindType::BFILE
1175
- BindType::Mapping[::OCI8::Cursor] = BindType::Cursor
1176
-
1177
- # implicitly define
1178
-
1179
- # datatype type size prec scale
1180
- # -------------------------------------------------
1181
- # CHAR(1) SQLT_AFC 1 0 0
1182
- # CHAR(10) SQLT_AFC 10 0 0
1183
- BindType::Mapping[OCI8::SQLT_AFC] = BindType::String
1184
-
1185
- # datatype type size prec scale
1186
- # -------------------------------------------------
1187
- # VARCHAR(1) SQLT_CHR 1 0 0
1188
- # VARCHAR(10) SQLT_CHR 10 0 0
1189
- # VARCHAR2(1) SQLT_CHR 1 0 0
1190
- # VARCHAR2(10) SQLT_CHR 10 0 0
1191
- BindType::Mapping[OCI8::SQLT_CHR] = BindType::String
1192
-
1193
- # datatype type size prec scale
1194
- # -------------------------------------------------
1195
- # RAW(1) SQLT_BIN 1 0 0
1196
- # RAW(10) SQLT_BIN 10 0 0
1197
- BindType::Mapping[OCI8::SQLT_BIN] = BindType::RAW
1198
-
1199
- # datatype type size prec scale
1200
- # -------------------------------------------------
1201
- # LONG SQLT_LNG 0 0 0
1202
- BindType::Mapping[OCI8::SQLT_LNG] = BindType::String
1203
-
1204
- # datatype type size prec scale
1205
- # -------------------------------------------------
1206
- # LONG RAW SQLT_LBI 0 0 0
1207
- BindType::Mapping[OCI8::SQLT_LBI] = BindType::RAW
1208
-
1209
- # datatype type size prec scale
1210
- # -------------------------------------------------
1211
- # CLOB SQLT_CLOB 4000 0 0
1212
- BindType::Mapping[OCI8::SQLT_CLOB] = BindType::CLOB
1213
- BindType::Mapping[:nclob] = BindType::NCLOB # if OCI_ATTR_CHARSET_FORM is SQLCS_NCHAR.
1214
-
1215
- # datatype type size prec scale
1216
- # -------------------------------------------------
1217
- # BLOB SQLT_BLOB 4000 0 0
1218
- BindType::Mapping[OCI8::SQLT_BLOB] = BindType::BLOB
1219
-
1220
- # datatype type size prec scale
1221
- # -------------------------------------------------
1222
- # BFILE SQLT_BFILE 4000 0 0
1223
- BindType::Mapping[OCI8::SQLT_BFILE] = BindType::BFILE
1224
-
1225
- # datatype type size prec scale
1226
- # -------------------------------------------------
1227
- # DATE SQLT_DAT 7 0 0
1228
- BindType::Mapping[OCI8::SQLT_DAT] = BindType::OraDate
1229
-
1230
- BindType::Mapping[OCI8::SQLT_TIMESTAMP] = BindType::OraDate
1231
-
1232
- # datatype type size prec scale
1233
- # -------------------------------------------------
1234
- # ROWID SQLT_RDD 4 0 0
1235
- BindType::Mapping[OCI8::SQLT_RDD] = BindType::String
1236
-
1237
- # datatype type size prec scale
1238
- # -----------------------------------------------------
1239
- # FLOAT SQLT_NUM 22 126 -127
1240
- # FLOAT(1) SQLT_NUM 22 1 -127
1241
- # FLOAT(126) SQLT_NUM 22 126 -127
1242
- # DOUBLE PRECISION SQLT_NUM 22 126 -127
1243
- # REAL SQLT_NUM 22 63 -127
1244
- # calculated value SQLT_NUM 22 0 0
1245
- # NUMBER SQLT_NUM 22 0 0 (Oracle 9.2.0.2 or below)
1246
- # NUMBER SQLT_NUM 22 0 -127 (Oracle 9.2.0.3 or above)
1247
- # NUMBER(1) SQLT_NUM 22 1 0
1248
- # NUMBER(38) SQLT_NUM 22 38 0
1249
- # NUMBER(1, 0) SQLT_NUM 22 1 0
1250
- # NUMBER(38, 0) SQLT_NUM 22 38 0
1251
- # NUMERIC SQLT_NUM 22 38 0
1252
- # INT SQLT_NUM 22 38 0
1253
- # INTEGER SQLT_NUM 22 38 0
1254
- # SMALLINT SQLT_NUM 22 38 0
1255
- BindType::Mapping[OCI8::SQLT_NUM] = BindType::Number
1256
-
1257
- # This parameter specify the ruby datatype for
1258
- # calculated number values whose precision is unknown in advance.
1259
- # select col1 * 1.1 from tab1;
1260
- # For Oracle 9.2.0.2 or below, this is also used for NUMBER
1261
- # datatypes that have no explicit setting of their precision
1262
- # and scale.
1263
- BindType::Mapping[:number_unknown_prec] = BindType::Float
1264
-
1265
- # This parameter specify the ruby datatype for NUMBER datatypes
1266
- # that have no explicit setting of their precision and scale.
1267
- # create table tab1 (col1 number);
1268
- # select col1 from tab1;
1269
- # note: This is available only on Oracle 9.2.0.3 or above.
1270
- # see: Oracle 9.2.0.x Patch Set Notes.
1271
- BindType::Mapping[:number_no_prec_setting] = BindType::Float
1272
-
1273
- # datatype type size prec scale
1274
- # -------------------------------------------------
1275
- # BINARY FLOAT SQLT_IBFLOAT 4 0 0
1276
- # BINARY DOUBLE SQLT_IBDOUBLE 8 0 0
1277
- if defined? BindType::BinaryDouble
1278
- BindType::Mapping[OCI8::SQLT_IBFLOAT] = BindType::BinaryDouble
1279
- BindType::Mapping[OCI8::SQLT_IBDOUBLE] = BindType::BinaryDouble
1280
- else
1281
- BindType::Mapping[OCI8::SQLT_IBFLOAT] = BindType::Float
1282
- BindType::Mapping[OCI8::SQLT_IBDOUBLE] = BindType::Float
1283
- end
1284
-
1285
- # cursor in result set.
1286
- BindType::Mapping[SQLT_RSET] = BindType::Cursor
1287
- end # OCI8
1288
-
1289
- class OraDate
1290
- def to_time
1291
- begin
1292
- Time.local(year, month, day, hour, minute, second)
1293
- rescue ArgumentError
1294
- 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)
1295
- raise RangeError.new(msg)
1296
- end
1297
- end
1298
-
1299
- def to_date
1300
- Date.new(year, month, day)
1301
- end
1302
-
1303
- if defined? DateTime # ruby 1.8.0 or upper
1304
- def to_datetime
1305
- DateTime.new(year, month, day, hour, minute, second)
1306
- end
1307
- end
1308
-
1309
- def yaml_initialize(type, val) # :nodoc:
1310
- initialize(*val.split(/[ -\/:]+/).collect do |i| i.to_i end)
1311
- end
1312
-
1313
- def to_yaml(opts = {}) # :nodoc:
1314
- YAML.quick_emit(object_id, opts) do |out|
1315
- out.scalar(taguri, self.to_s, :plain)
1316
- end
1317
- end
1318
-
1319
- def to_json(options=nil) # :nodoc:
1320
- to_datetime.to_json(options)
1321
- end
1322
- end
1323
-
1324
- class OraNumber
1325
- def yaml_initialize(type, val) # :nodoc:
1326
- initialize(val)
1327
- end
1328
-
1329
- def to_yaml(opts = {}) # :nodoc:
1330
- YAML.quick_emit(object_id, opts) do |out|
1331
- out.scalar(taguri, self.to_s, :plain)
1332
- end
1333
- end
1334
-
1335
- def to_json(options=nil) # :nodoc:
1336
- to_s
47
+ # Returns an OCI8::OracleVersion of the Oracle client version.
48
+ #
49
+ # If this library is configured without '--with-runtime-check',
50
+ # and compiled for Oracle 10.1 or lower, the major and minor
51
+ # numbers are determined at compile-time. The rests are zeros.
52
+ #
53
+ # If this library is configured with '--with-runtime-check'
54
+ # and the runtime Oracle library is Oracle 10.1 or lower, the
55
+ # major and minor numbers are determined at run-time. The
56
+ # rests are zeros.
57
+ #
58
+ # Otherwise, it is the version retrieved from an OCI function
59
+ # OCIClientVersion().
60
+ def self.oracle_client_version
61
+ @@oracle_client_version
1337
62
  end
1338
63
  end
1339
64
 
65
+ require 'oci8/datetime.rb'
66
+ require 'oci8/oci8.rb'
67
+ require 'oci8/metadata.rb'
68
+ require 'oci8/compat.rb'
69
+ require 'oci8/object.rb'
1340
70
 
1341
- #
1342
- # OCI8::Metadata::Column
1343
- #
1344
71
  class OCI8
1345
- module Metadata
1346
-
1347
- # Abstract super class for Metadata classes.
1348
- class Base
1349
- # This class's code was copied from svn trunk whick will be ruby-oci8 2.0.
1350
-
1351
- # SQLT values to name
1352
- DATA_TYPE_MAP = {} # :nodoc:
1353
- TYPE_PROC_MAP = {} # :nodoc:
1354
-
1355
- # SQLT_CHR
1356
- DATA_TYPE_MAP[1] = :varchar2
1357
- TYPE_PROC_MAP[1] = Proc.new do |p|
1358
- if p.charset_form == :nchar
1359
- "NVARCHAR2(#{p.char_size})"
1360
- else
1361
- if (p.respond_to? :char_used?) && (p.char_used?)
1362
- "VARCHAR2(#{p.char_size} CHAR)"
1363
- else
1364
- "VARCHAR2(#{p.data_size})"
1365
- end
1366
- end
1367
- end
1368
-
1369
- # SQLT_NUM
1370
- DATA_TYPE_MAP[2] = :number
1371
- TYPE_PROC_MAP[2] = Proc.new do |p|
1372
- begin
1373
- case p.scale
1374
- when -127
1375
- case p.precision
1376
- when 0
1377
- "NUMBER"
1378
- when 126
1379
- "FLOAT"
1380
- else
1381
- "FLOAT(#{p.precision})"
1382
- end
1383
- when 0
1384
- case p.precision
1385
- when 0
1386
- "NUMBER"
1387
- else
1388
- "NUMBER(#{p.precision})"
1389
- end
1390
- else
1391
- "NUMBER(#{p.precision},#{p.scale})"
1392
- end
1393
- rescue OCIError
1394
- "NUMBER"
1395
- end
1396
- end
1397
-
1398
- # SQLT_LNG
1399
- DATA_TYPE_MAP[8] = :long
1400
- TYPE_PROC_MAP[8] = "LONG"
1401
-
1402
- # SQLT_DAT
1403
- DATA_TYPE_MAP[12] = :date
1404
- TYPE_PROC_MAP[12] = "DATE"
1405
-
1406
- # SQLT_BIN
1407
- DATA_TYPE_MAP[23] = :raw
1408
- TYPE_PROC_MAP[23] = Proc.new do |p|
1409
- "RAW(#{p.data_size})"
1410
- end
1411
-
1412
- # SQLT_LBI
1413
- DATA_TYPE_MAP[24] = :long_raw
1414
- TYPE_PROC_MAP[24] = "LONG RAW"
1415
-
1416
- # SQLT_AFC
1417
- DATA_TYPE_MAP[96] = :char
1418
- TYPE_PROC_MAP[96] = Proc.new do |p|
1419
- if p.charset_form == :nchar
1420
- "NCHAR(#{p.char_size})"
1421
- else
1422
- if (p.respond_to? :char_used?) && (p.char_used?)
1423
- "CHAR(#{p.char_size} CHAR)"
1424
- else
1425
- "CHAR(#{p.data_size})"
1426
- end
1427
- end
1428
- end
1429
-
1430
- # SQLT_IBFLOAT
1431
- DATA_TYPE_MAP[100] = :binary_float
1432
- TYPE_PROC_MAP[100] = "BINARY_FLOAT"
1433
-
1434
- # SQLT_IBDOUBLE
1435
- DATA_TYPE_MAP[101] = :binary_double
1436
- TYPE_PROC_MAP[101] = "BINARY_DOUBLE"
1437
-
1438
- # SQLT_RDD
1439
- DATA_TYPE_MAP[104] = :rowid
1440
- TYPE_PROC_MAP[104] = "ROWID"
1441
-
1442
- # SQLT_NTY
1443
- DATA_TYPE_MAP[108] = :named_type
1444
- TYPE_PROC_MAP[108] = "Object"
1445
-
1446
- # SQLT_REF
1447
- DATA_TYPE_MAP[110] = :ref
1448
- TYPE_PROC_MAP[110] = "REF"
1449
-
1450
- # SQLT_CLOB
1451
- DATA_TYPE_MAP[112] = :clob
1452
- TYPE_PROC_MAP[112] = Proc.new do |p|
1453
- if p.charset_form == :nchar
1454
- "NCLOB"
1455
- else
1456
- "CLOB"
1457
- end
1458
- end
1459
-
1460
- # SQLT_BLOB
1461
- DATA_TYPE_MAP[113] = :blob
1462
- TYPE_PROC_MAP[113] = "BLOB"
1463
-
1464
- # SQLT_BFILE
1465
- DATA_TYPE_MAP[114] = :bfile
1466
- TYPE_PROC_MAP[114] = "BFILE"
1467
-
1468
- # SQLT_TIMESTAMP
1469
- DATA_TYPE_MAP[187] = :timestamp
1470
- TYPE_PROC_MAP[187] = Proc.new do |p|
1471
- fsprecision = p.fsprecision
1472
- if fsprecision == 6
1473
- "TIMESTAMP"
1474
- else
1475
- "TIMESTAMP(#{fsprecision})"
1476
- end
1477
- end
1478
-
1479
- # SQLT_TIMESTAMP_TZ
1480
- DATA_TYPE_MAP[188] = :timestamp_tz
1481
- TYPE_PROC_MAP[188] = Proc.new do |p|
1482
- fsprecision = p.fsprecision
1483
- if fsprecision == 6
1484
- "TIMESTAMP WITH TIME ZONE"
1485
- else
1486
- "TIMESTAMP(#{fsprecision}) WITH TIME ZONE"
1487
- end
1488
- end
1489
-
1490
- # SQLT_INTERVAL_YM
1491
- DATA_TYPE_MAP[189] = :interval_ym
1492
- TYPE_PROC_MAP[189] = Proc.new do |p|
1493
- lfprecision = p.lfprecision
1494
- if lfprecision == 2
1495
- "INTERVAL YEAR TO MONTH"
1496
- else
1497
- "INTERVAL YEAR(#{lfprecision}) TO MONTH"
1498
- end
1499
- end
1500
-
1501
- # SQLT_INTERVAL_DS
1502
- DATA_TYPE_MAP[190] = :interval_ds
1503
- TYPE_PROC_MAP[190] = Proc.new do |p|
1504
- lfprecision = p.lfprecision
1505
- fsprecision = p.fsprecision
1506
- if lfprecision == 2 && fsprecision == 6
1507
- "INTERVAL DAY TO SECOND"
1508
- else
1509
- "INTERVAL DAY(#{lfprecision}) TO SECOND(#{fsprecision})"
1510
- end
1511
- end
1512
-
1513
- # SQLT_TIMESTAMP_LTZ
1514
- DATA_TYPE_MAP[232] = :timestamp_ltz
1515
- TYPE_PROC_MAP[232] = Proc.new do |p|
1516
- fsprecision = p.fsprecision
1517
- if fsprecision == 6
1518
- "TIMESTAMP WITH LOCAL TIME ZONE"
1519
- else
1520
- "TIMESTAMP(#{fsprecision}) WITH LOCAL TIME ZONE"
1521
- end
1522
- end
1523
-
1524
- def inspect # :nodoc:
1525
- "#<#{self.class.name}:(#{@obj_id}) #{@obj_schema}.#{@obj_name}>"
1526
- end
1527
-
1528
- private
1529
-
1530
- def __data_type(p)
1531
- DATA_TYPE_MAP[p.attrGet(OCI_ATTR_DATA_TYPE)] || p.attrGet(OCI_ATTR_DATA_TYPE)
1532
- end
1533
-
1534
- def __type_string(p)
1535
- type = TYPE_PROC_MAP[p.attrGet(OCI_ATTR_DATA_TYPE)] || "unknown(#{p.attrGet(OCI_ATTR_DATA_TYPE)})"
1536
- type = type.call(self) if type.is_a? Proc
1537
- if respond_to?(:nullable?) && !nullable?
1538
- type + " NOT NULL"
1539
- else
1540
- type
1541
- end
1542
- end
1543
-
1544
- def initialize_table_or_view(param)
1545
- @num_cols = param.attrGet(OCI_ATTR_NUM_COLS)
1546
- @obj_id = param.attrGet(OCI_ATTR_OBJ_ID)
1547
- @obj_name = param.attrGet(OCI_ATTR_OBJ_NAME)
1548
- @obj_schema = param.attrGet(OCI_ATTR_OBJ_SCHEMA)
1549
- colparam = param.attrGet(OCI_ATTR_LIST_COLUMNS)
1550
- @columns = []
1551
- 1.upto @num_cols do |i|
1552
- @columns << OCI8::Metadata::Column.new(colparam.paramGet(i))
1553
- end
1554
- end
1555
- end
1556
-
1557
- class Table < Base
1558
- attr_reader :num_cols
1559
- attr_reader :obj_name
1560
- attr_reader :obj_schema
1561
- attr_reader :columns
1562
-
1563
- def initialize(param)
1564
- initialize_table_or_view(param)
1565
- end
1566
- end
1567
-
1568
- class View < Base
1569
- attr_reader :num_cols
1570
- attr_reader :obj_name
1571
- attr_reader :obj_schema
1572
- attr_reader :columns
1573
-
1574
- def initialize(param)
1575
- initialize_table_or_view(param)
1576
- end
1577
- end
1578
-
1579
- class Column < Base
1580
- attr_reader :name
1581
- attr_reader :type_string
1582
- attr_reader :data_type
1583
- attr_reader :charset_form
1584
- def nullable?; @nullable; end
1585
-
1586
- # string data type
1587
- def char_used?; @char_used; end if defined? OCI_ATTR_CHAR_USED
1588
- attr_reader :char_size if defined? OCI_ATTR_CHAR_SIZE
1589
- attr_reader :data_size
1590
- attr_reader :charset_id
1591
-
1592
- # number data type
1593
- attr_reader :precision
1594
- attr_reader :scale
1595
-
1596
- # interval
1597
- if defined? OCI_ATTR_FSPRECISION and defined? OCI_ATTR_LFPRECISION
1598
- # Oracle 8i or upper has OCI_ATTR_FSPRECISION and OCI_ATTR_LFPRECISION
1599
- @@is_fsprecision_available = true
1600
- else
1601
- @@is_fsprecision_available = false
1602
- end
1603
- attr_reader :fsprecision
1604
- attr_reader :lfprecision
1605
-
1606
- def initialize(param)
1607
- @name = param.attrGet(OCI_ATTR_NAME)
1608
- @data_type = __data_type(param)
1609
-
1610
- @data_size = param.attrGet(OCI_ATTR_DATA_SIZE)
1611
- @char_used = param.attrGet(OCI_ATTR_CHAR_USED) if defined? OCI_ATTR_CHAR_USED
1612
- @char_size = param.attrGet(OCI_ATTR_CHAR_SIZE) if defined? OCI_ATTR_CHAR_SIZE
1613
-
1614
- @precision = param.attrGet(OCI_ATTR_PRECISION)
1615
- @scale = param.attrGet(OCI_ATTR_SCALE)
1616
- @nullable = param.attrGet(OCI_ATTR_IS_NULL)
1617
- @charset_id = param.attrGet(OCI_ATTR_CHARSET_ID)
1618
- @charset_form = case param.attrGet(OCI_ATTR_CHARSET_FORM)
1619
- when 0: nil
1620
- when 1; :implicit
1621
- when 2; :nchar
1622
- when 3; :explicit
1623
- when 4; :flexible
1624
- when 5; :lit_null
1625
- else raise "unknown charset_form #{param.attrGet(OCI_ATTR_CHARSET_FORM)}"
1626
- end
1627
-
1628
- @fsprecision = nil
1629
- @lfprecision = nil
1630
- if @@is_fsprecision_available
1631
- begin
1632
- @fsprecision = param.attrGet(OCI_ATTR_FSPRECISION)
1633
- @lfprecision = param.attrGet(OCI_ATTR_LFPRECISION)
1634
- rescue OCIError
1635
- raise if $!.code != 24316 # ORA-24316: illegal handle type
1636
- # Oracle 8i could not use OCI_ATTR_FSPRECISION and
1637
- # OCI_ATTR_LFPRECISION even though it defines these
1638
- # constants in oci.h.
1639
- @@is_fsprecision_available = false
1640
- end
1641
- end
1642
-
1643
- @type_string = __type_string(param)
1644
- end
1645
-
1646
- def to_s
1647
- %Q{"#{@name}" #{@type_string}}
1648
- end
1649
-
1650
- def inspect # :nodoc:
1651
- "#<#{self.class.name}: #{@name} #{@type_string}>"
1652
- end
1653
- end
1654
- end
72
+ VERSION = '@@OCI8_MODULE_VERSION@@'
73
+ CLIENT_VERSION = '@@OCI8_CLIENT_VERSION@@'
1655
74
  end