ruby-oci8 2.2.0.2 → 2.2.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -6
  3. data/ChangeLog +600 -0
  4. data/NEWS +426 -35
  5. data/README.md +27 -9
  6. data/dist-files +13 -2
  7. data/docs/bind-array-to-in_cond.md +38 -0
  8. data/docs/conflicts-local-connections-and-processes.md +98 -0
  9. data/docs/hanging-after-inactivity.md +63 -0
  10. data/docs/install-binary-package.md +15 -11
  11. data/docs/install-full-client.md +18 -21
  12. data/docs/install-instant-client.md +45 -27
  13. data/docs/install-on-osx.md +31 -117
  14. data/docs/ldap-auth-and-function-interposition.md +123 -0
  15. data/docs/number-type-mapping.md +79 -0
  16. data/docs/platform-specific-issues.md +17 -50
  17. data/docs/report-installation-issue.md +11 -8
  18. data/docs/timeout-parameters.md +94 -0
  19. data/ext/oci8/apiwrap.c.tmpl +2 -5
  20. data/ext/oci8/apiwrap.rb +6 -1
  21. data/ext/oci8/apiwrap.yml +39 -143
  22. data/ext/oci8/attr.c +4 -2
  23. data/ext/oci8/bind.c +421 -9
  24. data/ext/oci8/connection_pool.c +3 -3
  25. data/ext/oci8/encoding.c +5 -5
  26. data/ext/oci8/env.c +8 -2
  27. data/ext/oci8/error.c +24 -16
  28. data/ext/oci8/extconf.rb +35 -63
  29. data/ext/oci8/hook_funcs.c +274 -61
  30. data/ext/oci8/lob.c +31 -75
  31. data/ext/oci8/metadata.c +8 -6
  32. data/ext/oci8/object.c +119 -29
  33. data/ext/oci8/oci8.c +46 -133
  34. data/ext/oci8/oci8.h +40 -123
  35. data/ext/oci8/oci8lib.c +178 -46
  36. data/ext/oci8/ocihandle.c +37 -37
  37. data/ext/oci8/ocinumber.c +24 -35
  38. data/ext/oci8/oraconf.rb +168 -337
  39. data/ext/oci8/oradate.c +19 -19
  40. data/ext/oci8/plthook.h +10 -0
  41. data/ext/oci8/plthook_elf.c +433 -268
  42. data/ext/oci8/plthook_osx.c +40 -9
  43. data/ext/oci8/plthook_win32.c +16 -1
  44. data/ext/oci8/stmt.c +52 -17
  45. data/ext/oci8/win32.c +4 -22
  46. data/lib/oci8/bindtype.rb +10 -17
  47. data/lib/oci8/check_load_error.rb +57 -10
  48. data/lib/oci8/compat.rb +5 -1
  49. data/lib/oci8/connection_pool.rb +74 -3
  50. data/lib/oci8/cursor.rb +70 -31
  51. data/lib/oci8/metadata.rb +9 -1
  52. data/lib/oci8/object.rb +14 -1
  53. data/lib/oci8/oci8.rb +184 -58
  54. data/lib/oci8/ocihandle.rb +0 -16
  55. data/lib/oci8/oracle_version.rb +11 -1
  56. data/lib/oci8/properties.rb +55 -0
  57. data/lib/oci8/version.rb +1 -1
  58. data/lib/oci8.rb +48 -4
  59. data/lib/ruby-oci8.rb +1 -0
  60. data/pre-distclean.rb +1 -3
  61. data/ruby-oci8.gemspec +4 -9
  62. data/setup.rb +11 -2
  63. data/test/README.md +37 -0
  64. data/test/config.rb +8 -1
  65. data/test/setup_test_object.sql +42 -14
  66. data/test/setup_test_package.sql +59 -0
  67. data/test/test_all.rb +4 -0
  68. data/test/test_bind_array.rb +70 -0
  69. data/test/test_bind_boolean.rb +99 -0
  70. data/test/test_bind_integer.rb +47 -0
  71. data/test/test_break.rb +11 -9
  72. data/test/test_clob.rb +5 -17
  73. data/test/test_connstr.rb +142 -0
  74. data/test/test_datetime.rb +8 -3
  75. data/test/test_metadata.rb +2 -1
  76. data/test/test_object.rb +99 -18
  77. data/test/test_oci8.rb +170 -46
  78. data/test/test_oranumber.rb +12 -6
  79. data/test/test_package_type.rb +17 -3
  80. data/test/test_properties.rb +17 -0
  81. metadata +45 -55
  82. data/docs/osx-install-dev-tools.png +0 -0
  83. data/test/README +0 -42
data/ext/oci8/oraconf.rb CHANGED
@@ -4,88 +4,37 @@ require 'mkmf'
4
4
  # compatibility for ruby-1.9
5
5
  RbConfig = Config unless defined? RbConfig
6
6
 
7
- module MiniRegistry
8
- class MiniRegistryError < StandardError
9
- attr_reader :api_name
10
- attr_reader :code
11
- def initialize(api_name, code)
12
- @api_name = api_name
13
- @code = code
14
- end
15
- end
16
- if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/
17
- # Windows
18
- require 'Win32API' # raise LoadError when UNIX.
19
-
20
- # I looked in Win32Module by MoonWolf <URL:http://www.moonwolf.com/ruby/>,
21
- # copy the minimum code and reorganize it.
22
- ERROR_SUCCESS = 0
23
- ERROR_FILE_NOT_FOUND = 2
24
- ERROR_NO_MORE_ITEMS = 259
25
-
26
- HKEY_LOCAL_MACHINE = 0x80000002
27
- KEY_ENUMERATE_SUB_KEYS = 0x0008
28
- KEY_QUERY_VALUE = 0x0001
29
- RegOpenKeyExA = Win32API.new('advapi32', 'RegOpenKeyExA', 'LPLLP', 'L')
30
- RegEnumKeyExA = Win32API.new('advapi32', 'RegEnumKeyExA', 'LLPPPPPP', 'L')
31
- RegQueryValueExA = Win32API.new('advapi32','RegQueryValueExA','LPPPPP','L')
32
- RegCloseKey = Win32API.new('advapi32', 'RegCloseKey', 'L', 'L')
33
-
34
- def self.get_str_value(hKey, name)
35
- lpcbData = [0].pack('L')
36
- code = RegQueryValueExA.call(hKey, name, nil, nil, nil, lpcbData)
37
- if code == ERROR_FILE_NOT_FOUND
38
- return nil
39
- elsif code != ERROR_SUCCESS
40
- raise MiniRegistryError.new("Win32::RegQueryValueExA",code)
41
- end
42
- len = lpcbData.unpack('L')[0]
43
- lpType = [0].pack('L')
44
- lpData = "\0"*len
45
- lpcbData = [len].pack('L')
46
- code = RegQueryValueExA.call(hKey, name, nil, lpType, lpData, lpcbData)
47
- if code != ERROR_SUCCESS
48
- raise MiniRegistryError.new("Win32::RegQueryValueExA",code)
49
- end
50
- lpData.unpack('Z*')[0]
51
- end
52
-
53
- def self.enum_homes
54
- phkResult = [0].pack('L')
55
- code = RegOpenKeyExA.call(HKEY_LOCAL_MACHINE, 'SOFTWARE\ORACLE', 0, 0x20019, phkResult)
56
- if code != ERROR_SUCCESS
57
- raise MiniRegistryError.new("Win32::RegOpenKeyExA", code)
58
- end
59
- hKey = phkResult.unpack('L')[0]
60
- idx = 0
61
- maxkeylen = 256
62
- loop do
63
- lpName = "\0" * maxkeylen
64
- lpcName = [maxkeylen].pack('L')
65
- code = RegEnumKeyExA.call(hKey, idx, lpName, lpcName, nil, nil, nil, nil);
66
- break if code == ERROR_NO_MORE_ITEMS
67
- if code != ERROR_SUCCESS
68
- RegCloseKey.call(hKey)
69
- raise MiniRegistryError.new("Win32::RegEnumKeyEx", code)
70
- end
71
- code = RegOpenKeyExA.call(hKey, lpName, 0, KEY_QUERY_VALUE, phkResult)
72
- if code != ERROR_SUCCESS
73
- RegCloseKey.call(hKey)
74
- raise MiniRegistryError.new("Win32::RegEnumKeyEx", code)
7
+ if RUBY_PLATFORM =~ /mswin32|mswin64|cygwin|mingw/
8
+ # Windows
9
+ require 'win32/registry'
10
+ module Registry
11
+
12
+ class OracleHome
13
+ attr_reader :name
14
+ attr_reader :path
15
+ def initialize(name, path)
16
+ @name = name
17
+ @path = path
18
+ end
19
+ end
20
+
21
+ def self.oracle_homes
22
+ homes = []
23
+ Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Oracle') do |key|
24
+ key.each_key do |subkey_name|
25
+ subkey = key.open(subkey_name)
26
+ begin
27
+ homes << OracleHome.new(subkey['ORACLE_HOME_NAME'], subkey['ORACLE_HOME'].chomp('\\'))
28
+ rescue Win32::Registry::Error
29
+ # ignore errors
30
+ end
75
31
  end
76
- hSubkey = phkResult.unpack('L')[0]
77
-
78
- name = get_str_value(hSubkey, 'ORACLE_HOME_NAME')
79
- path = get_str_value(hSubkey, 'ORACLE_HOME')
80
- yield name, path
81
- RegCloseKey.call(hSubkey)
82
- idx += 1
83
32
  end
84
- RegCloseKey.call(hKey)
33
+ homes
85
34
  end
86
35
 
87
36
  end
88
- end # module MiniRegistry
37
+ end
89
38
 
90
39
  # minimal implementation to read information of a shared object.
91
40
  class MiniSOReader
@@ -94,6 +43,10 @@ class MiniSOReader
94
43
  attr_reader :endian
95
44
  attr_reader :bits
96
45
 
46
+ MACH_O_CPU_TYPE_I386 = 7
47
+ MACH_O_CPU_TYPE_X86_64 = 7 + 0x01000000
48
+ MACH_O_CPU_TYPE_ARM64 = 12 + 0x01000000
49
+
97
50
  def initialize(filename)
98
51
  f = open(filename, 'rb')
99
52
  begin
@@ -107,9 +60,6 @@ class MiniSOReader
107
60
  when "\x02\x10"
108
61
  # HP-UX PA-RISC1.1
109
62
  read_parisc(f)
110
- when "\xfe\xed"
111
- # Big-endian Mach-O File
112
- read_mach_o_be(f)
113
63
  when "\xce\xfa"
114
64
  # 32-bit Little-endian Mach-O File
115
65
  read_mach_o_le(f, 32)
@@ -118,10 +68,10 @@ class MiniSOReader
118
68
  read_mach_o_le(f, 64)
119
69
  when "\xca\xfe"
120
70
  # Universal binary
121
- read_mach_o_unversal(f)
71
+ read_mach_o_universal(f)
122
72
  else
123
73
  # AIX and Tru64
124
- raise format("unknown file header: %02x %02x", file_header[0].to_i, file_header[1].to_i)
74
+ raise format("unknown file header: %02x %02x (%s)", file_header[0].ord, file_header[1].ord, filename)
125
75
  end
126
76
  ensure
127
77
  f.close
@@ -225,22 +175,6 @@ class MiniSOReader
225
175
  @cpu = :parisc
226
176
  end
227
177
 
228
- # Big-endian Mach-O File
229
- def read_mach_o_be(f)
230
- @file_format = :mach_o
231
- @endian = :big
232
- case f.read(2)
233
- when "\xfa\xce" # feedface
234
- @cpu = :ppc
235
- @bits = 32
236
- when "\xfa\xcf" # feedfacf
237
- @cpu = :ppc64
238
- @bits = 64
239
- else
240
- raise "unknown file format"
241
- end
242
- end
243
-
244
178
  def read_mach_o_le(f, bits)
245
179
  @file_format = :mach_o
246
180
  @endian = :little
@@ -250,12 +184,20 @@ class MiniSOReader
250
184
  @cpu = :i386
251
185
  @bits = 32
252
186
  when 64
253
- @cpu = :x86_64
187
+ cputype = f.read(4).unpack('V')[0]
188
+ case cputype
189
+ when MACH_O_CPU_TYPE_X86_64
190
+ @cpu = :x86_64
191
+ when MACH_O_CPU_TYPE_ARM64
192
+ @cpu = :arm64
193
+ else
194
+ raise "unknown mach-o cpu type: #{cputype}"
195
+ end
254
196
  @bits = 64
255
197
  end
256
198
  end
257
199
 
258
- def read_mach_o_unversal(f)
200
+ def read_mach_o_universal(f)
259
201
  raise 'unknown file format' if f.read(2) != "\xba\xbe" # cafebabe
260
202
  @file_format = :universal
261
203
  nfat_arch = f.read(4).unpack('N')[0]
@@ -264,21 +206,17 @@ class MiniSOReader
264
206
  @bits = []
265
207
  nfat_arch.times do
266
208
  case cputype = f.read(4).unpack('N')[0]
267
- when 7
209
+ when MACH_O_CPU_TYPE_I386
268
210
  @cpu << :i386
269
211
  @endian << :little
270
212
  @bits << 32
271
- when 7 + 0x01000000
213
+ when MACH_O_CPU_TYPE_X86_64
272
214
  @cpu << :x86_64
273
215
  @endian << :little
274
216
  @bits << 64
275
- when 18
276
- @cpu << :ppc
277
- @endian << :big
278
- @bits << 32
279
- when 18 + 0x01000000
280
- @cpu << :ppc64
281
- @endian << :big
217
+ when MACH_O_CPU_TYPE_ARM64
218
+ @cpu << :arm64
219
+ @endian << :little
282
220
  @bits << 64
283
221
  else
284
222
  raise "Unknown mach-o cputype: #{cputype}"
@@ -301,7 +239,6 @@ class OraConf
301
239
  def self.get
302
240
  original_CFLAGS = $CFLAGS
303
241
  original_defs = $defs
304
- ic_dir = nil
305
242
  begin
306
243
  # check Oracle instant client
307
244
  if with_config('instant-client')
@@ -313,11 +250,17 @@ class OraConf
313
250
  =======================================================
314
251
  EOS
315
252
  end
316
- ic_dir = check_ic_dir
317
- if ic_dir
318
- OraConfIC.new(ic_dir)
253
+ inc, lib = dir_config('instant-client')
254
+ if inc && lib
255
+ OraConfIC.new(inc, lib)
319
256
  else
320
- OraConfFC.new()
257
+ base = guess_ic_dir
258
+ if base
259
+ inc, lib = guess_dirs_from_ic_base(base)
260
+ OraConfIC.new(inc, lib)
261
+ else
262
+ OraConfFC.new
263
+ end
321
264
  end
322
265
  rescue
323
266
  case ENV['LANG']
@@ -349,6 +292,44 @@ EOS
349
292
  end
350
293
  end
351
294
 
295
+ # Guess the include and directory paths from
296
+ def self.guess_dirs_from_ic_base(ic_dir)
297
+ if ic_dir =~ /^\/usr\/lib(?:64)?\/oracle\/(\d+(?:\.\d+)*)\/client(64)?\/lib(?:64)?/
298
+ # rpm package
299
+ # x86 rpms after 11.1.0.7.0:
300
+ # library: /usr/lib/oracle/X.X/client/lib/
301
+ # include: /usr/include/oracle/X.X/client/
302
+ #
303
+ # x86_64 rpms after 11.1.0.7.0:
304
+ # library: /usr/lib/oracle/X.X/client64/lib/
305
+ # include: /usr/include/oracle/X.X/client64/
306
+ #
307
+ # x86 rpms before 11.1.0.6.0:
308
+ # library: /usr/lib/oracle/X.X.X.X/client/lib/
309
+ # include: /usr/include/oracle/X.X.X.X/client/
310
+ #
311
+ # x86_64 rpms before 11.1.0.6.0:
312
+ # library: /usr/lib/oracle/X.X.X.X/client64/lib/
313
+ # include: /usr/include/oracle/X.X.X.X/client64/
314
+ #
315
+ # third-party x86_64 rpms(*1):
316
+ # library: /usr/lib64/oracle/X.X.X.X/client/lib/
317
+ # or /usr/lib64/oracle/X.X.X.X/client/lib64/
318
+ # include: /usr/include/oracle/X.X.X.X/client/
319
+ #
320
+ # *1 These had been used before Oracle released official x86_64 rpms.
321
+ #
322
+ lib_dir = ic_dir
323
+ inc_dir = "/usr/include/oracle/#{$1}/client#{$2}"
324
+ else
325
+ # zip package
326
+ lib_dir = ic_dir
327
+ inc_dir = "#{ic_dir}/sdk/include"
328
+ end
329
+
330
+ [inc_dir, lib_dir]
331
+ end
332
+
352
333
  def self.ld_envs
353
334
  @@ld_envs
354
335
  end
@@ -367,8 +348,9 @@ EOS
367
348
  end
368
349
  end
369
350
 
370
- def self.check_ic_dir
371
- puts "checking for load library path... "
351
+ def self.guess_ic_dir
352
+ puts "attempting to locate oracle-instantclient..."
353
+ puts "checking load library path... "
372
354
  STDOUT.flush
373
355
 
374
356
  # get library load path names
@@ -384,13 +366,13 @@ EOS
384
366
  [nil].pack('P').size
385
367
  rescue ArgumentError
386
368
  # Rubinius 1.2.3 doesn't support Array#pack('P').
387
- # Use Fixnum#size, which returns the size of long.
369
+ # Use Integer#size, which returns the size of long.
388
370
  1.size
389
371
  end
390
372
  is_32bit = size_of_pointer == 4
391
373
  is_big_endian = "\x01\x02".unpack('s')[0] == 0x0102
392
374
  case RUBY_PLATFORM
393
- when /mswin32|cygwin|mingw32|bccwin32/
375
+ when /mswin32|mswin64|cygwin|mingw/
394
376
  oci_basename = 'oci'
395
377
  oci_glob_postfix = ''
396
378
  nls_data_basename = ['oraociei*', 'oraociicus*']
@@ -433,20 +415,13 @@ EOS
433
415
  end
434
416
  so_ext = 'sl'
435
417
  when /darwin/
436
- @@ld_envs = %w[DYLD_LIBRARY_PATH]
418
+ @@ld_envs = %w[OCI_DIR]
437
419
  so_ext = 'dylib'
438
420
  if is_32bit
439
- if is_big_endian
440
- this_cpu = :ppc # 32-bit big-endian
441
- else
442
- this_cpu = :i386 # 32-bit little-endian
443
- end
421
+ this_cpu = :i386 # 32-bit little-endian
444
422
  else
445
- if is_big_endian
446
- this_cpu = :ppc64 # 64-bit big-endian
447
- else
448
- this_cpu = :x86_64 # 64-bit little-endian
449
- end
423
+ require 'etc'
424
+ this_cpu = Etc.uname[:machine].to_sym
450
425
  end
451
426
  check_proc = Proc.new do |file|
452
427
  so = MiniSOReader.new(file)
@@ -520,61 +495,18 @@ EOS
520
495
  end
521
496
  end
522
497
  when /darwin/
523
- fallback_path = ENV['DYLD_FALLBACK_LIBRARY_PATH']
524
- if fallback_path.nil?
525
- fallback_path = "#{ENV['HOME']}/lib:/usr/local/lib:/lib:/usr/lib"
526
- end
527
- puts " checking DYLD_FALLBACK_LIBRARY_PATH..."
528
- ld_path, file = check_lib_in_path(fallback_path, glob_name, check_proc)
529
498
  if ld_path.nil?
530
- puts " checking OCI_DIR..."
531
- ld_path, file = check_lib_in_path(ENV['OCI_DIR'], glob_name, check_proc)
532
- if ld_path
533
- puts " checking dependent shared libraries in #{file}..."
534
- open("|otool -L #{file}") do |f|
535
- f.gets # discard the first line
536
- while line = f.gets
537
- line =~ /^\s+(\S+)/
538
- libname = $1
539
- case libname
540
- when /^@rpath\/libclntsh\.dylib/, /^@rpath\/libnnz\d\d\.dylib/, /^@loader_path\/libnnz\d\d\.dylib/
541
- # No need to check the real path.
542
- # The current instant client doesn't use @rpath or @loader_path.
543
- when /\/libclntsh\.dylib/, /\/libnnz\d\d.dylib/
544
- raise <<EOS unless File.exists?(libname)
545
- The output of "otool -L #{file}" is:
546
- | #{IO.readlines("|otool -L #{file}").join(' | ')}
547
- Ruby-oci8 doesn't work without DYLD_LIBRARY_PATH or DYLD_FALLBACK_LIBRARY_PATH
548
- because the dependent file "#{libname}" doesn't exist.
549
-
550
- If you need to use ruby-oci8 without DYLD_LIBRARY_PATH or DYLD_FALLBACK_LIBRARY_PATH,
551
- download "fix_oralib.rb" in https://github.com/kubo/fix_oralib_osx
552
- and execute it in the directory "#{File.dirname(file)}" as follows to fix the path.
553
-
554
- cd #{File.dirname(file)}
555
- curl -O https://raw.githubusercontent.com/kubo/fix_oralib_osx/master/fix_oralib.rb
556
- ruby fix_oralib.rb
557
-
558
- Note: DYLD_* environment variables are unavailable for security reasons on OS X 10.11 El Capitan.
559
- EOS
560
- end
561
- end
562
- end
499
+ fallback_path = ENV['DYLD_FALLBACK_LIBRARY_PATH']
500
+ if fallback_path.nil?
501
+ fallback_path = "#{ENV['HOME']}/lib:/usr/local/lib:/lib:/usr/lib"
502
+ puts " checking the default value of DYLD_FALLBACK_LIBRARY_PATH..."
503
+ ld_path, file = check_lib_in_path(fallback_path, glob_name, check_proc)
563
504
  end
564
505
  end
565
506
  if ld_path.nil?
566
507
  raise <<EOS
567
- Set the environment variable DYLD_LIBRARY_PATH, DYLD_FALLBACK_LIBRARY_PATH or
568
- OCI_DIR to point to the Instant client directory.
569
-
570
- If DYLD_LIBRARY_PATH or DYLD_FALLBACK_LIBRARY_PATH is set, the environment
571
- variable must be set at runtime also.
572
-
573
- If OCI_DIR is set, dependent shared library paths are checked. If the checking
574
- is passed, ruby-oci8 works without DYLD_LIBRARY_PATH or DYLD_FALLBACK_LIBRARY_PATH.
575
-
576
- Note: OCI_DIR should be absolute path.
577
- Note: DYLD_* environment variables are unavailable for security reasons on OS X 10.11 El Capitan.
508
+ Oracle instant client is not found.
509
+ You need to install Oracle instant client.
578
510
  EOS
579
511
  end
580
512
  end
@@ -598,8 +530,8 @@ EOS
598
530
  paths.split(File::PATH_SEPARATOR).each do |path|
599
531
  next if path.nil? or path == ''
600
532
  print " checking #{path}... "
601
- path.gsub!(/\\/, '/') if /mswin32|cygwin|mingw32|bccwin32/ =~ RUBY_PLATFORM
602
- files = Dir.glob(File.join(path, glob_name))
533
+ path.gsub!(/\\/, '/') if /mswin32|mswin64|cygwin|mingw/ =~ RUBY_PLATFORM
534
+ files = Dir.glob(File.join(path, glob_name)).sort.reverse
603
535
  if files.empty?
604
536
  puts "no"
605
537
  next
@@ -626,7 +558,7 @@ EOS
626
558
  if try_run("int main() { return 0; }")
627
559
  puts "ok"
628
560
  else
629
- puts "ng"
561
+ puts "failed"
630
562
  raise "C compiler doesn't work correctly."
631
563
  end
632
564
  end # check_cc
@@ -672,21 +604,11 @@ EOS
672
604
  STDOUT.flush
673
605
  rubyhdrdir = RbConfig::CONFIG["rubyhdrdir"] || RbConfig::CONFIG['archdir']
674
606
  unless File.exist?(rubyhdrdir + '/ruby.h')
675
- puts "ng"
676
- if RUBY_PLATFORM =~ /darwin/ and File.exist?("#{RbConfig::CONFIG['archdir']}/../universal-darwin8.0/ruby.h")
677
- raise <<EOS
678
- #{RbConfig::CONFIG['archdir']}/ruby.h doesn't exist.
679
- Run the following commands to fix the problem.
680
-
681
- cd #{RbConfig::CONFIG['archdir']}
682
- sudo ln -s ../universal-darwin8.0/* ./
683
- EOS
684
- else
685
- raise <<EOS
607
+ puts "failed"
608
+ raise <<EOS
686
609
  #{RbConfig::CONFIG['archdir']}/ruby.h doesn't exist.
687
610
  Install the ruby development library.
688
611
  EOS
689
- end
690
612
  end
691
613
  puts "ok"
692
614
  $stdout.flush
@@ -696,23 +618,26 @@ EOS
696
618
  original_libs = $libs
697
619
  begin
698
620
  $libs += " -L#{CONFIG['libdir']} " + @libs
699
- have_func("OCIInitialize", "oci.h")
621
+ have_func("OCIEnvCreate", "oci.h")
700
622
  ensure
701
623
  $libs = original_libs
702
624
  end
703
625
  end
704
626
 
705
- if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/ # when Windows
627
+ if RUBY_PLATFORM =~ /mswin32|mswin64|cygwin|mingw/ # when Windows
706
628
 
707
629
  def get_libs(lib_dir)
708
630
  case RUBY_PLATFORM
709
- when /cygwin|x64-mingw32/
631
+ when /cygwin/
710
632
  regex = ([nil].pack('P').size == 8) ? / T (OCI\w+)/ : / T _(OCI\w+)/
633
+ oci_funcs = YAML.load(open(File.dirname(__FILE__) + '/apiwrap.yml')).keys.collect do |func|
634
+ func =~ /_nb$/ ? $` : func
635
+ end
711
636
  open("OCI.def", "w") do |f|
712
637
  f.puts("EXPORTS")
713
638
  open("|nm #{lib_dir}/MSVC/OCI.LIB") do |r|
714
639
  while line = r.gets
715
- f.puts($1) if regex =~ line
640
+ f.puts($1) if regex =~ line and oci_funcs.include?($1)
716
641
  end
717
642
  end
718
643
  end
@@ -722,22 +647,6 @@ EOS
722
647
  system(command)
723
648
  puts("done")
724
649
  "-L. -lOCI"
725
- when /bccwin32/
726
- # replace '/' to '\\' because bcc linker misunderstands
727
- # 'C:/foo/bar/OCI.LIB' as unknown option.
728
- lib = "#{lib_dir}/BORLAND/OCI.LIB"
729
- return lib.tr('/', '\\') if File.exist?(lib)
730
- raise <<EOS
731
- #{lib} does not exist.
732
-
733
- Your Oracle may not support Borland C++.
734
- If you want to run this module, run the following command at your own risk.
735
- cd #{lib_dir.tr('/', '\\')}
736
- mkdir Borland
737
- cd Borland
738
- coff2omf ..\\MSVC\\OCI.LIB OCI.LIB
739
- EOS
740
- exit 1
741
650
  else
742
651
  "\"#{lib_dir}/MSVC/OCI.LIB\""
743
652
  end
@@ -781,7 +690,7 @@ class OraConfFC < OraConf
781
690
  use_lib32 = false
782
691
  end
783
692
 
784
- if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/
693
+ if RUBY_PLATFORM =~ /mswin32|mswin64|cygwin|mingw/
785
694
  lib_dir = "#{@oracle_home}/oci/lib"
786
695
  elsif use_lib32
787
696
  lib_dir = "#{@oracle_home}/lib32"
@@ -800,7 +709,7 @@ class OraConfFC < OraConf
800
709
  print("Get the version of Oracle from SQL*Plus... ")
801
710
  STDOUT.flush
802
711
  version = nil
803
- dev_null = RUBY_PLATFORM =~ /mswin32|mingw32|bccwin32/ ? "nul" : "/dev/null"
712
+ dev_null = RUBY_PLATFORM =~ /mswin32|mswin64|mingw/ ? "nul" : "/dev/null"
804
713
  if File.exist?("#{@oracle_home}/bin/plus80.exe")
805
714
  sqlplus = "plus80.exe"
806
715
  else
@@ -825,7 +734,7 @@ class OraConfFC < OraConf
825
734
  version
826
735
  end # get_version
827
736
 
828
- if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/ # when Windows
737
+ if RUBY_PLATFORM =~ /mswin32|mswin64|cygwin|mingw/ # when Windows
829
738
 
830
739
  def is_valid_home?(oracle_home)
831
740
  return false if oracle_home.nil?
@@ -844,11 +753,8 @@ class OraConfFC < OraConf
844
753
  def get_home()
845
754
  oracle_home = ENV['ORACLE_HOME']
846
755
  if oracle_home.nil?
847
- struct = Struct.new("OracleHome", :name, :path)
848
- oracle_homes = []
849
- MiniRegistry.enum_homes do |name, path|
850
- path.chomp!("\\") if path
851
- oracle_homes << struct.new(name, path) if is_valid_home?(path)
756
+ oracle_homes = Registry::oracle_homes.select do |home|
757
+ is_valid_home?(home.path)
852
758
  end
853
759
  if oracle_homes.empty?
854
760
  raise <<EOS
@@ -910,7 +816,7 @@ EOS
910
816
  unless File.exist?("#{@oracle_home}/OCI/INCLUDE/OCI.H")
911
817
  raise "'#{@oracle_home}/OCI/INCLUDE/OCI.H' does not exists. Please install 'Oracle Call Interface'."
912
818
  end
913
- if RUBY_PLATFORM =~ /cygwin|mingw32/
819
+ if RUBY_PLATFORM =~ /cygwin|mingw/
914
820
  " \"-I#{@oracle_home}/OCI/INCLUDE\" -D_int64=\"long long\""
915
821
  else
916
822
  " \"-I#{@oracle_home}/OCI/INCLUDE\""
@@ -989,56 +895,25 @@ end
989
895
 
990
896
  # OraConf for Instant Client
991
897
  class OraConfIC < OraConf
992
- def initialize(ic_dir)
898
+ def initialize(inc_dir, lib_dir)
993
899
  init
994
900
 
995
- if ic_dir =~ /^\/usr\/lib(?:64)?\/oracle\/(\d+(?:\.\d+)*)\/client(64)?\/lib(?:64)?/
996
- # rpm package
997
- # x86 rpms after 11.1.0.7.0:
998
- # library: /usr/lib/oracle/X.X/client/lib/
999
- # include: /usr/include/oracle/X.X/client/
1000
- #
1001
- # x86_64 rpms after 11.1.0.7.0:
1002
- # library: /usr/lib/oracle/X.X/client64/lib/
1003
- # include: /usr/include/oracle/X.X/client64/
1004
- #
1005
- # x86 rpms before 11.1.0.6.0:
1006
- # library: /usr/lib/oracle/X.X.X.X/client/lib/
1007
- # include: /usr/include/oracle/X.X.X.X/client/
1008
- #
1009
- # x86_64 rpms before 11.1.0.6.0:
1010
- # library: /usr/lib/oracle/X.X.X.X/client64/lib/
1011
- # include: /usr/include/oracle/X.X.X.X/client64/
1012
- #
1013
- # third-party x86_64 rpms(*1):
1014
- # library: /usr/lib64/oracle/X.X.X.X/client/lib/
1015
- # or /usr/lib64/oracle/X.X.X.X/client/lib64/
1016
- # include: /usr/include/oracle/X.X.X.X/client/
1017
- #
1018
- # *1 These had been used before Oracle released official x86_64 rpms.
1019
- #
1020
- lib_dir = ic_dir
1021
- inc_dir = "/usr/include/oracle/#{$1}/client#{$2}"
1022
- else
1023
- # zip package
1024
- lib_dir = ic_dir
1025
- inc_dir = "#{ic_dir}/sdk/include"
1026
- end
1027
-
1028
- if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/ # when Windows
1029
- unless File.exist?("#{ic_dir}/sdk/lib/msvc/oci.lib")
901
+ # check lib_dir
902
+ lib_dirs = lib_dir.split(File::PATH_SEPARATOR)
903
+ if RUBY_PLATFORM =~ /mswin32|mswin64|cygwin|mingw/ # when Windows
904
+ ocilib = lib_dirs.find do |dir|
905
+ File.exist?("#{dir}/sdk/lib/msvc/oci.lib")
906
+ end
907
+ unless ocilib
1030
908
  raise <<EOS
1031
909
  Could not compile with Oracle instant client.
1032
- #{ic_dir}/sdk/lib/msvc/oci.lib could not be found.
910
+ "sdk/lib/msvc/oci.lib" could not be found in: #{lib_dirs.join(' ')}
911
+ Did you install instantclient-basic?
1033
912
  EOS
1034
- raise 'failed'
1035
913
  end
1036
- @cflags = " \"-I#{inc_dir}\""
1037
- @cflags += " -D_int64=\"long long\"" if RUBY_PLATFORM =~ /cygwin|mingw32/
1038
- @libs = get_libs("#{ic_dir}/sdk/lib")
914
+ @libs = get_libs("#{ocilib}/sdk/lib")
1039
915
  ld_path = nil
1040
916
  else
1041
- @cflags = " -I#{inc_dir}"
1042
917
  # set ld_path and so_ext
1043
918
  case RUBY_PLATFORM
1044
919
  when /aix/
@@ -1059,34 +934,53 @@ EOS
1059
934
  so_ext = 'so'
1060
935
  end
1061
936
  # check Oracle client library.
1062
- unless File.exist?("#{lib_dir}/libclntsh.#{so_ext}")
1063
- files = Dir.glob("#{lib_dir}/libclntsh.#{so_ext}.*")
937
+ ocilib = lib_dirs.find do |dir|
938
+ File.exist?("#{dir}/libclntsh.#{so_ext}")
939
+ end
940
+ unless ocilib
941
+ files = lib_dirs.map do |dir|
942
+ Dir.glob("#{dir}/libclntsh.#{so_ext}.*")
943
+ end.flatten
1064
944
  if files.empty?
1065
945
  raise <<EOS
1066
946
  Could not compile with Oracle instant client.
1067
- '#{lib_dir}/libclntsh.#{so_ext}' could not be found.
947
+ "libclntsh.#{so_ext}" could not be found in: #{lib_dirs.join(' ')}
1068
948
  Did you install instantclient-basic?
1069
949
  EOS
1070
950
  else
1071
- file = File.basename(files.sort[-1])
951
+ file = files.sort[-1]
1072
952
  raise <<EOS
1073
953
  Could not compile with Oracle instant client.
1074
- #{lib_dir}/libclntsh.#{so_ext} could not be found.
954
+ "libclntsh.#{so_ext}" could not be found in: #{lib_dirs.join(' ')}
1075
955
  You may need to make a symbolic link.
1076
- cd #{lib_dir}
1077
- ln -s #{file} libclntsh.#{so_ext}
956
+ cd #{File.dirname(file)}
957
+ ln -s #{File.basename(file)} libclntsh.#{so_ext}
1078
958
  EOS
1079
959
  end
1080
960
  raise 'failed'
1081
961
  end
1082
962
  @libs = get_libs(lib_dir)
1083
963
  end
1084
- unless File.exist?("#{inc_dir}/oci.h")
964
+
965
+ # check inc_dir
966
+ inc_dirs = inc_dir.split(File::PATH_SEPARATOR)
967
+ ociinc = inc_dirs.find do |dir|
968
+ File.exist?("#{dir}/oci.h")
969
+ end
970
+ unless ociinc
1085
971
  raise <<EOS
1086
- '#{inc_dir}/oci.h' does not exist.
972
+ "oci.h" could not be found in: #{inc_dirs.join(' ')}
1087
973
  Install 'Instant Client SDK'.
1088
974
  EOS
1089
975
  end
976
+ if ociinc.include?(' ')
977
+ @cflags = " \"-I#{ociinc}\""
978
+ else
979
+ @cflags = " -I#{ociinc}"
980
+ end
981
+ @cflags += " -D_int64=\"long long\"" if RUBY_PLATFORM =~ /cygwin|mingw/
982
+
983
+ # check link
1090
984
  $CFLAGS += @cflags
1091
985
  if try_link_oci()
1092
986
  major = try_constant("OCI_MAJOR_VERSION", "oci.h")
@@ -1096,73 +990,10 @@ EOS
1096
990
  else
1097
991
  # 10.1.0 doesn't have OCI_MAJOR_VERSION and OCI_MINOR_VERSION in oci.h.
1098
992
  @version = "1010"
1099
- if RUBY_PLATFORM =~ /darwin/ and 1.size == 8 and `sw_vers -productVersion`.chomp == "10.7"
1100
- $stderr.print <<EOS
1101
- WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN!
1102
-
1103
- 64-bit Oracle instant client doesn't work on OS X Lion.
1104
- See: https://forums.oracle.com/forums/thread.jspa?threadID=2187558
1105
-
1106
- The compilation is continued because the issue may be fixed in future.
1107
-
1108
- WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN! WARN!
1109
- EOS
1110
- end
1111
993
  end
1112
994
  return
1113
995
  end
1114
996
 
1115
- if RUBY_PLATFORM =~ /darwin/
1116
- open('mkmf.log', 'r') do |f|
1117
- while line = f.gets
1118
- if line.include? '/libclntsh.dylib load command 8 unknown cmd field'
1119
- raise <<EOS
1120
- Intel mac instant client is for Mac OS X 10.5.
1121
- It doesn't work on Mac OS X 10.4 or before.
1122
-
1123
- You have three workarounds.
1124
- 1. Compile ruby as ppc binary and use it with ppc instant client.
1125
- 2. Use JRuby and JDBC
1126
- 3. Use a third-party ODBC driver and ruby-odbc.
1127
- EOS
1128
- # '
1129
- end
1130
-
1131
- case line
1132
- when /cputype \(\d+, architecture \w+\) does not match cputype \(\d+\) for specified -arch flag: (\w+)/
1133
- missing_arch = $1
1134
- when /Undefined symbols for architecture (\w+)/
1135
- missing_arch = $1
1136
- when /missing required architecture (\w+) in file/
1137
- missing_arch = $1
1138
- end
1139
-
1140
- if missing_arch
1141
- if [nil].pack('p').size == 8
1142
- my_arch = 'x86_64'
1143
- elsif "\x01\x02".unpack('s')[0] == 0x0201
1144
- my_arch = 'i386'
1145
- else
1146
- my_arch = 'ppc'
1147
- end
1148
- raise <<EOS
1149
- Could not compile with Oracle instant client.
1150
- You may need to set the environment variable RC_ARCHS or ARCHFLAGS as follows:
1151
-
1152
- RC_ARCHS=#{my_arch}
1153
- export RC_ARCHS
1154
- or
1155
- ARCHFLAGS='-arch #{my_arch}'
1156
- export RC_ARCHS
1157
-
1158
- If it does not fix the problem, delete all '-arch #{missing_arch}'
1159
- in '#{RbConfig::CONFIG['archdir']}/rbconfig.rb'.
1160
- EOS
1161
- end
1162
- end
1163
- end
1164
- end
1165
-
1166
997
  unless ld_path.nil?
1167
998
  raise <<EOS
1168
999
  Could not compile with Oracle instant client.