ruby-oci8 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/ChangeLog +569 -0
  2. data/Makefile +51 -0
  3. data/NEWS +322 -0
  4. data/README +415 -0
  5. data/VERSION +1 -0
  6. data/dist-files +70 -0
  7. data/doc/api.en.html +527 -0
  8. data/doc/api.en.rd +554 -0
  9. data/doc/api.ja.html +525 -0
  10. data/doc/api.ja.rd +557 -0
  11. data/doc/manual.css +35 -0
  12. data/ext/oci8/MANIFEST +22 -0
  13. data/ext/oci8/attr.c +415 -0
  14. data/ext/oci8/bind.c +194 -0
  15. data/ext/oci8/const.c +165 -0
  16. data/ext/oci8/define.c +53 -0
  17. data/ext/oci8/describe.c +81 -0
  18. data/ext/oci8/descriptor.c +39 -0
  19. data/ext/oci8/env.c +276 -0
  20. data/ext/oci8/error.c +234 -0
  21. data/ext/oci8/extconf.rb +118 -0
  22. data/ext/oci8/handle.c +262 -0
  23. data/ext/oci8/lob.c +386 -0
  24. data/ext/oci8/oci8.c +137 -0
  25. data/ext/oci8/oci8.h +345 -0
  26. data/ext/oci8/ocinumber.c +117 -0
  27. data/ext/oci8/oraconf.rb +1026 -0
  28. data/ext/oci8/oradate.c +426 -0
  29. data/ext/oci8/oranumber.c +445 -0
  30. data/ext/oci8/param.c +37 -0
  31. data/ext/oci8/post-config.rb +5 -0
  32. data/ext/oci8/server.c +182 -0
  33. data/ext/oci8/session.c +99 -0
  34. data/ext/oci8/stmt.c +624 -0
  35. data/ext/oci8/svcctx.c +229 -0
  36. data/lib/DBD/OCI8/OCI8.rb +549 -0
  37. data/lib/oci8.rb.in +1605 -0
  38. data/metaconfig +142 -0
  39. data/pre-distclean.rb +7 -0
  40. data/ruby-oci8.gemspec +54 -0
  41. data/ruby-oci8.spec +62 -0
  42. data/setup.rb +1331 -0
  43. data/support/README +4 -0
  44. data/support/runit/assert.rb +281 -0
  45. data/support/runit/cui/testrunner.rb +101 -0
  46. data/support/runit/error.rb +4 -0
  47. data/support/runit/method_mappable.rb +20 -0
  48. data/support/runit/robserver.rb +25 -0
  49. data/support/runit/setuppable.rb +15 -0
  50. data/support/runit/teardownable.rb +16 -0
  51. data/support/runit/testcase.rb +113 -0
  52. data/support/runit/testfailure.rb +25 -0
  53. data/support/runit/testresult.rb +121 -0
  54. data/support/runit/testsuite.rb +43 -0
  55. data/support/runit/version.rb +3 -0
  56. data/test/README +4 -0
  57. data/test/config.rb +129 -0
  58. data/test/test_all.rb +43 -0
  59. data/test/test_bind_raw.rb +53 -0
  60. data/test/test_bind_time.rb +191 -0
  61. data/test/test_break.rb +81 -0
  62. data/test/test_clob.rb +101 -0
  63. data/test/test_connstr.rb +80 -0
  64. data/test/test_dbi.rb +317 -0
  65. data/test/test_dbi_clob.rb +56 -0
  66. data/test/test_describe.rb +137 -0
  67. data/test/test_metadata.rb +243 -0
  68. data/test/test_oci8.rb +273 -0
  69. data/test/test_oradate.rb +263 -0
  70. data/test/test_oranumber.rb +149 -0
  71. metadata +118 -0
@@ -0,0 +1,117 @@
1
+ /*
2
+ ocinumber.c - part of ruby-oci8
3
+ copy from ocinumber.c in ruby-oci8 0.2.
4
+ */
5
+
6
+ #include "oci8.h"
7
+ #include <orl.h>
8
+
9
+ /* use for local call */
10
+ #define oci_lc(rv) do { \
11
+ sword __rv = (rv); \
12
+ if (__rv != OCI_SUCCESS) { \
13
+ oci8_raise(errhp, __rv, NULL); \
14
+ } \
15
+ } while(0)
16
+
17
+ #define NUMBER_FORMAT1_STR "FM9999999999999999999999990.9999999999999999999999999999999999999"
18
+ #define NUMBER_FORMAT1 (OraText*)NUMBER_FORMAT1_STR
19
+ #define NUMBER_FORMAT1_LEN (sizeof(NUMBER_FORMAT1_STR) - 1)
20
+ #define NUMBER_FORMAT2_STR "FM99999999999999999999999999999999999990.999999999999999999999999"
21
+ #define NUMBER_FORMAT2 (OraText*)NUMBER_FORMAT2_STR
22
+ #define NUMBER_FORMAT2_LEN (sizeof(NUMBER_FORMAT2_STR) - 1)
23
+ #define NUMBER_FORMAT2_DECIMAL (sizeof("999999999999999999999999") - 1)
24
+ #define NUMBER_FORMAT_INT_STR "FM99999999999999999999999999999999999990"
25
+ #define NUMBER_FORMAT_INT (OraText*)NUMBER_FORMAT_INT_STR
26
+ #define NUMBER_FORMAT_INT_LEN (sizeof(NUMBER_FORMAT_INT_STR) - 1)
27
+
28
+ #ifndef StringValue
29
+ #define StringValue(s) ((s) = (TYPE(s) == T_STRING) ? (s) : rb_str_to_str(s))
30
+ #endif
31
+
32
+ /* fill C structure (OCINumber) from a string. */
33
+ static void set_oci_number_from_str(OCINumber *result, VALUE str, VALUE fmt, VALUE nls_params, OCIError *errhp)
34
+ {
35
+ oratext *fmt_ptr;
36
+ oratext *nls_params_ptr;
37
+ ub4 fmt_len;
38
+ ub4 nls_params_len;
39
+
40
+ StringValue(str);
41
+ /* set from string. */
42
+ if (NIL_P(fmt)) {
43
+ int i, cnt = 0;
44
+ for (i = RSTRING_LEN(str) - 1; i >= 0; i--) {
45
+ if (RSTRING_PTR(str)[i] != ' ')
46
+ cnt++;
47
+ if (RSTRING_PTR(str)[i] == '.') {
48
+ i = RSTRING_LEN(str) - i;
49
+ break;
50
+ }
51
+ }
52
+ if (i == -1)
53
+ cnt = 0;
54
+ if (cnt <= NUMBER_FORMAT2_DECIMAL) {
55
+ fmt_ptr = NUMBER_FORMAT2;
56
+ fmt_len = NUMBER_FORMAT2_LEN;
57
+ } else {
58
+ fmt_ptr = NUMBER_FORMAT1;
59
+ fmt_len = NUMBER_FORMAT1_LEN;
60
+ }
61
+ } else {
62
+ StringValue(fmt);
63
+ fmt_ptr = RSTRING_ORATEXT(fmt);
64
+ fmt_len = RSTRING_LEN(fmt);
65
+ }
66
+ if (NIL_P(nls_params)) {
67
+ nls_params_ptr = NULL;
68
+ nls_params_len = 0;
69
+ } else {
70
+ StringValue(nls_params);
71
+ nls_params_ptr = RSTRING_ORATEXT(nls_params);
72
+ nls_params_len = RSTRING_LEN(nls_params);
73
+ }
74
+ oci_lc(OCINumberFromText(errhp,
75
+ RSTRING_ORATEXT(str), RSTRING_LEN(str),
76
+ fmt_ptr, fmt_len, nls_params_ptr, nls_params_len,
77
+ result));
78
+ }
79
+
80
+ /* fill C structure (OCINumber) from a numeric object. */
81
+ /* 1 - success, 0 - error */
82
+ static int set_oci_number_from_num(OCINumber *result, VALUE num, OCIError *errhp)
83
+ {
84
+ signed long sl;
85
+ double dbl;
86
+
87
+ if (!RTEST(rb_obj_is_kind_of(num, rb_cNumeric)))
88
+ rb_raise(rb_eTypeError, "expect Numeric but %s", rb_class2name(CLASS_OF(num)));
89
+ switch (rb_type(num)) {
90
+ case T_FIXNUM:
91
+ /* set from long. */
92
+ sl = NUM2LONG(num);
93
+ oci_lc(OCINumberFromInt(errhp, &sl, sizeof(sl), OCI_NUMBER_SIGNED, result));
94
+ return 1;
95
+ case T_FLOAT:
96
+ /* set from double. */
97
+ dbl = NUM2DBL(num);
98
+ oci_lc(OCINumberFromReal(errhp, &dbl, sizeof(dbl), result));
99
+ return 1;
100
+ case T_BIGNUM:
101
+ /* change via string. */
102
+ num = rb_big2str(num, 10);
103
+ set_oci_number_from_str(result, num, Qnil, Qnil, errhp);
104
+ return 1;
105
+ }
106
+ if (RTEST(rb_obj_is_instance_of(num, cOraNumber))) {
107
+ /* OCI::Number */
108
+ oci_lc(OCINumberAssign(errhp, DATA_PTR(num), result));
109
+ return 1;
110
+ }
111
+ return 0;
112
+ }
113
+
114
+ int set_oci_vnumber(ora_vnumber_t *result, VALUE num, OCIError *errhp)
115
+ {
116
+ return set_oci_number_from_num((OCINumber*)result, num, errhp);
117
+ }
@@ -0,0 +1,1026 @@
1
+ require 'mkmf'
2
+
3
+ unless defined? macro_defined?
4
+ # ruby 1.6 doesn't have 'macro_defined?'.
5
+ def macro_defined?(macro, src, opt="")
6
+ try_cpp(src + <<"SRC", opt)
7
+ #ifndef #{macro}
8
+ # error
9
+ #endif
10
+ SRC
11
+ end
12
+ end
13
+
14
+ module Logging
15
+ unless Logging.respond_to?(:open)
16
+ # emulate Logging::open of ruby 1.6.8 or later.
17
+
18
+ if $log.nil? # ruby 1.6.2 doesn't have $log.
19
+ $log = open('mkmf.log', 'w')
20
+ end
21
+ def Logging::open
22
+ begin
23
+ $stderr.reopen($log)
24
+ $stdout.reopen($log)
25
+ yield
26
+ ensure
27
+ $stderr.reopen($orgerr)
28
+ $stdout.reopen($orgout)
29
+ end
30
+ end
31
+ end
32
+ end # module Logging
33
+
34
+ module MiniRegistry
35
+ class MiniRegistryError < StandardError
36
+ attr_reader :api_name
37
+ attr_reader :code
38
+ def initialize(api_name, code)
39
+ @api_name = api_name
40
+ @code = code
41
+ end
42
+ end
43
+ if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/
44
+ # Windows
45
+ require 'Win32API' # raise LoadError when UNIX.
46
+
47
+ # I looked in Win32Module by MoonWolf <URL:http://www.moonwolf.com/ruby/>,
48
+ # copy the minimum code and reorganize it.
49
+ ERROR_SUCCESS = 0
50
+ ERROR_FILE_NOT_FOUND = 2
51
+
52
+ HKEY_LOCAL_MACHINE = 0x80000002
53
+ RegOpenKeyExA = Win32API.new('advapi32', 'RegOpenKeyExA', 'LPLLP', 'L')
54
+ RegQueryValueExA = Win32API.new('advapi32','RegQueryValueExA','LPPPPP','L')
55
+ RegCloseKey = Win32API.new('advapi32', 'RegCloseKey', 'L', 'L')
56
+
57
+ def get_reg_value(root, subkey, name)
58
+ result = [0].pack('L')
59
+ code = RegOpenKeyExA.call(root, subkey, 0, 0x20019, result)
60
+ if code != ERROR_SUCCESS
61
+ raise MiniRegistryError.new("Win32::RegOpenKeyExA", code)
62
+ end
63
+ hkey = result.unpack('L')[0]
64
+ begin
65
+ lpcbData = [0].pack('L')
66
+ code = RegQueryValueExA.call(hkey, name, nil, nil, nil, lpcbData)
67
+ if code == ERROR_FILE_NOT_FOUND
68
+ return nil
69
+ elsif code != ERROR_SUCCESS
70
+ raise MiniRegistryError.new("Win32::RegQueryValueExA",code)
71
+ end
72
+ len = lpcbData.unpack('L')[0]
73
+ lpType = "\0\0\0\0"
74
+ lpData = "\0"*len
75
+ lpcbData = [len].pack('L')
76
+ code = RegQueryValueExA.call(hkey, name, nil, lpType, lpData, lpcbData)
77
+ if code != ERROR_SUCCESS
78
+ raise MiniRegistryError.new("Win32::RegQueryValueExA",code)
79
+ end
80
+ lpData.unpack('Z*')[0]
81
+ ensure
82
+ RegCloseKey.call(hkey)
83
+ end
84
+ end
85
+ def get_local_registry(subkey, name)
86
+ get_reg_value(HKEY_LOCAL_MACHINE, subkey, name)
87
+ end
88
+ else
89
+ # UNIX
90
+ def get_local_registry(subkey, name)
91
+ nil
92
+ end
93
+ end
94
+ end # module MiniRegistry
95
+
96
+ # minimal implementation to read information of a shared object.
97
+ class MiniSOReader
98
+ attr_reader :file_format
99
+ attr_reader :cpu
100
+ attr_reader :endian
101
+ attr_reader :bits
102
+
103
+ def initialize(filename)
104
+ f = open(filename, 'rb')
105
+ begin
106
+ case file_header = f.read(2)
107
+ when "\177E"
108
+ # Linux, Solaris and HP-UX(64-bit)
109
+ read_elf(f) if f.read(2) == 'LF'
110
+ when "MZ"
111
+ # Windows
112
+ read_pe(f)
113
+ else
114
+ # HP-UX(32-bit), AIX, Mac OS X and Tru64
115
+ raise format("unknown file header: %02x %02x", file_header[0], file_header[1])
116
+ end
117
+ ensure
118
+ f.close
119
+ end
120
+ end
121
+
122
+ private
123
+ # ELF format
124
+ def read_elf(f)
125
+ # 0-3 "\177ELF"
126
+ @file_format = :elf
127
+ # 4
128
+ case f.read(1).unpack('C')[0]
129
+ when 1
130
+ @bits = 32
131
+ when 2
132
+ @bits = 64
133
+ else
134
+ raise 'Invalid ELF class'
135
+ end
136
+ # 5
137
+ case f.read(1).unpack('C')[0]
138
+ when 1
139
+ @endian = :little
140
+ pack_type_short = 'v'
141
+ when 2
142
+ @endian = :big
143
+ pack_type_short = 'n'
144
+ else
145
+ raise 'Invalid ELF byte order'
146
+ end
147
+ # 6
148
+ raise 'Invalid ELF header version' if f.read(1) != "\x01"
149
+ # 16-17
150
+ f.seek(16, IO::SEEK_SET)
151
+ raise 'Invalid ELF filetype' if f.read(2).unpack(pack_type_short)[0] != 3
152
+ # 18-19
153
+ case archtype = f.read(2).unpack(pack_type_short)[0]
154
+ when 2
155
+ @cpu = :sparc
156
+ when 3
157
+ @cpu = :i386
158
+ when 15
159
+ @cpu = :parisc
160
+ when 20
161
+ @cpu = :ppc
162
+ when 21
163
+ @cpu = :ppc64
164
+ when 22
165
+ @cpu = :s390
166
+ when 43
167
+ @cpu = :sparcv9
168
+ when 50
169
+ @cpu = :ia64
170
+ when 62
171
+ @cpu = :x86_64
172
+ else
173
+ raise "Invalid ELF archtype: #{archtype}"
174
+ end
175
+ end
176
+
177
+ # PE/COFF format
178
+ def read_pe(f)
179
+ # 0-1 "MZ"
180
+ @file_format = :pe
181
+ # 60-63
182
+ f.seek(60, IO::SEEK_SET)
183
+ pe_offset = f.read(4).unpack('V')[0]
184
+ # read PE signature
185
+ f.seek(pe_offset)
186
+ raise 'invalid pe format' if f.read(4) != "PE\000\000"
187
+ # read COFF header
188
+ case machine = f.read(2).unpack('v')[0]
189
+ when 0x014c
190
+ @cpu = :i386
191
+ @endian = :little
192
+ @bits = 32
193
+ when 0x0200
194
+ @cpu = :ia64
195
+ @endian = :little
196
+ @bits = 64
197
+ when 0x8664
198
+ @cpu = :x86_64
199
+ @endian = :little
200
+ @bits = 64
201
+ else
202
+ raise "Invalid coff machine: #{machine}"
203
+ end
204
+ end
205
+ end
206
+
207
+ class OraConf
208
+ include MiniRegistry
209
+
210
+ attr_reader :cc_is_gcc
211
+ attr_reader :version
212
+ attr_reader :cflags
213
+ attr_reader :libs
214
+
215
+ def initialize
216
+ raise 'use OraConf.get instead'
217
+ end
218
+
219
+ def self.get
220
+ original_CFLAGS = $CFLAGS
221
+ original_defs = $defs
222
+ ic_dir = nil
223
+ begin
224
+ # check Oracle instant client
225
+ if with_config('instant-client')
226
+ puts <<EOS
227
+ =======================================================
228
+
229
+ '--with-instant-client' is an obsolete option. ignore it.
230
+
231
+ =======================================================
232
+ EOS
233
+ end
234
+ ic_dir = check_ic_dir
235
+ if ic_dir
236
+ OraConfIC.new(ic_dir)
237
+ else
238
+ OraConfFC.new()
239
+ end
240
+ rescue
241
+ case ENV['LANG']
242
+ when /^ja/
243
+ lang = 'ja'
244
+ else
245
+ lang = 'en'
246
+ end
247
+ print <<EOS
248
+ ---------------------------------------------------
249
+ error messages:
250
+ #{$!.to_str}
251
+ ---------------------------------------------------
252
+ See:
253
+ * http://ruby-oci8.rubyforge.org/#{lang}/HowToInstall.html
254
+ * http://ruby-oci8.rubyforge.org/#{lang}/ReportInstallProblem.html
255
+
256
+ EOS
257
+ exc = RuntimeError.new
258
+ exc.set_backtrace($!.backtrace)
259
+ raise exc
260
+ ensure
261
+ $CFLAGS = original_CFLAGS
262
+ $defs = original_defs
263
+ end
264
+ end
265
+
266
+ def self.ld_envs
267
+ @@ld_envs
268
+ end
269
+
270
+ private
271
+
272
+ def self.check_ic_dir
273
+ print "checking for load library path... "
274
+ STDOUT.flush
275
+
276
+ # get library load path names
277
+ oci_basename = 'libclntsh'
278
+ oci_glob_postfix = '.[0-9]*'
279
+ ocidata_basename = ['libociei', 'libociicus']
280
+ @@ld_envs = %w[LD_LIBRARY_PATH]
281
+ so_ext = 'so'
282
+ check_proc = nil
283
+ case RUBY_PLATFORM
284
+ when /mswin32|cygwin|mingw32|bccwin32/
285
+ oci_basename = 'oci'
286
+ oci_glob_postfix = ''
287
+ ocidata_basename = ['oraociei11', 'oraociicus11', 'oraociei10', 'oraociicus10']
288
+ @@ld_envs = %w[PATH]
289
+ so_ext = 'dll'
290
+ when /i.86-linux/
291
+ check_proc = Proc.new do |file|
292
+ so = MiniSOReader.new(file)
293
+ if so.cpu == :i386
294
+ true
295
+ else
296
+ puts " skip: #{file} is for #{so.cpu} cpu."
297
+ false
298
+ end
299
+ end
300
+ when /ia64-linux/
301
+ check_proc = Proc.new do |file|
302
+ so = MiniSOReader.new(file)
303
+ if so.cpu == :ia64
304
+ true
305
+ else
306
+ puts " skip: #{file} is for #{so.cpu} cpu."
307
+ false
308
+ end
309
+ end
310
+ when /x86_64-linux/
311
+ check_proc = Proc.new do |file|
312
+ so = MiniSOReader.new(file)
313
+ if so.cpu == :x86_64
314
+ true
315
+ else
316
+ puts " skip: #{file} is for #{so.cpu} cpu."
317
+ false
318
+ end
319
+ end
320
+ when /solaris/
321
+ if [0].pack('l!').length == 8
322
+ @@ld_envs = %w[LD_LIBRARY_PATH_64 LD_LIBRARY_PATH]
323
+ else
324
+ @@ld_envs = %w[LD_LIBRARY_PATH_32 LD_LIBRARY_PATH]
325
+ end
326
+ when /aix/
327
+ oci_glob_postfix = ''
328
+ @@ld_envs = %w[LIBPATH]
329
+ so_ext = 'a'
330
+ when /hppa.*-hpux/
331
+ if [0].pack('l!').length == 4
332
+ @@ld_envs = %w[SHLIB_PATH]
333
+ end
334
+ so_ext = 'sl'
335
+ when /darwin/
336
+ @@ld_envs = %w[DYLD_LIBRARY_PATH]
337
+ so_ext = 'dylib'
338
+ end
339
+
340
+ glob_name = "#{oci_basename}.#{so_ext}#{oci_glob_postfix}"
341
+ ld_path = nil
342
+ file = nil
343
+ @@ld_envs.collect do |env|
344
+ puts "(#{env})... "
345
+ ENV[env] && ENV[env].split(File::PATH_SEPARATOR)
346
+ end.flatten.each do |path|
347
+ next if path.nil? or path == ''
348
+ path.gsub!(/\\/, '/') if /mswin32|cygwin|mingw32|bccwin32/ =~ RUBY_PLATFORM
349
+ files = Dir.glob(File.join(path, glob_name))
350
+ next if files.empty?
351
+ STDOUT.flush
352
+ next if (check_proc && !check_proc.call(files[0]))
353
+ file = files[0]
354
+ ld_path = path
355
+ break
356
+ end
357
+
358
+ if ld_path.nil? and RUBY_PLATFORM =~ /linux/
359
+ open("|/sbin/ldconfig -p") do |f|
360
+ print "(ld.so.conf)... "
361
+ STDOUT.flush
362
+ while line = f.gets
363
+ if line =~ /libclntsh\.so\..* => (\/.*)\/libclntsh\.so\.(.*)/
364
+ file = "#$1/libclntsh.so.#$2"
365
+ path = $1
366
+ next if (check_proc && !check_proc.call(file))
367
+ ld_path = path
368
+ break
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ if ld_path
375
+ ocidata_basename.each do |basename|
376
+ if File.exist?(File.join(ld_path, "#{basename}.#{so_ext}"))
377
+ puts " found: #{file} looks like an instant client."
378
+ return ld_path
379
+ end
380
+ end
381
+ puts " found: #{file} looks like a full client."
382
+ else
383
+ puts " not found"
384
+ end
385
+ nil
386
+ end
387
+
388
+ def init
389
+ check_cc()
390
+ @cc_is_gcc = check_cc_is_gcc()
391
+ @lp64 = check_lp64()
392
+ check_ruby_header()
393
+ end
394
+
395
+ def check_cc
396
+ print "checking for cc... "
397
+ STDOUT.flush
398
+ if try_run("int main() { return 0; }")
399
+ puts "ok"
400
+ else
401
+ puts "ng"
402
+ raise "C compiler doesn't work correctly."
403
+ end
404
+ end # check_cc
405
+
406
+ def check_cc_is_gcc
407
+ # bcc defines __GNUC__. why??
408
+ return false if RUBY_PLATFORM =~ /bccwin32/
409
+
410
+ print "checking for gcc... "
411
+ STDOUT.flush
412
+ if macro_defined?("__GNUC__", "")
413
+ print "yes\n"
414
+ return true
415
+ else
416
+ print "no\n"
417
+ return false
418
+ end
419
+ end # check_cc_is_gcc
420
+
421
+ def check_lp64
422
+ print "checking for LP64... "
423
+ STDOUT.flush
424
+ if try_run("int main() { return sizeof(long) == 8 ? 0 : 1; }")
425
+ puts "yes"
426
+ true
427
+ else
428
+ puts "no"
429
+ false
430
+ end
431
+ end # check_lp64
432
+
433
+ def check_ruby_header
434
+ print "checking for ruby header... "
435
+ STDOUT.flush
436
+ unless File.exist?("#{Config::CONFIG['archdir']}/ruby.h")
437
+ puts "ng"
438
+ if RUBY_PLATFORM =~ /darwin/ and File.exist?("#{Config::CONFIG['archdir']}/../universal-darwin8.0/ruby.h")
439
+ raise <<EOS
440
+ #{Config::CONFIG['archdir']}/ruby.h doesn't exist.
441
+ Run the following commands to fix the problem.
442
+
443
+ cd #{Config::CONFIG['archdir']}
444
+ sudo ln -s ../universal-darwin8.0/* ./
445
+ EOS
446
+ else
447
+ raise <<EOS
448
+ #{Config::CONFIG['archdir']}/ruby.h doesn't exist.
449
+ Install the ruby development library.
450
+ EOS
451
+ end
452
+ end
453
+ if RUBY_PLATFORM =~ /linux/ and not File.exist?("/usr/include/sys/types.h")
454
+ raise <<EOS
455
+ Do you install glibc-devel(redhat) or libc6-dev(debian)?
456
+ You need /usr/include/sys/types.h to compile ruby-oci8.
457
+ EOS
458
+ end
459
+ puts "ok"
460
+ end # check_ruby_header
461
+
462
+ def try_link_oci
463
+ original_libs = $libs
464
+ begin
465
+ $libs += " -L#{CONFIG['libdir']} " + @libs
466
+ have_func("OCIInitialize", "oci.h")
467
+ ensure
468
+ $libs = original_libs
469
+ end
470
+ end
471
+
472
+ if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/ # when Windows
473
+
474
+ def get_libs(base_dir = oci_base_dir)
475
+ case RUBY_PLATFORM
476
+ when /cygwin/
477
+ open("OCI.def", "w") do |f|
478
+ f.puts("EXPORTS")
479
+ open("|nm #{base_dir}/LIB/MSVC/OCI.LIB") do |r|
480
+ while line = r.gets
481
+ f.puts($') if line =~ / T _/
482
+ end
483
+ end
484
+ end
485
+ command = "dlltool -d OCI.def -D OCI.DLL -l libOCI.a"
486
+ print("Running: '#{command}' ...")
487
+ STDOUT.flush
488
+ system(command)
489
+ puts("done")
490
+ "-L. -lOCI"
491
+ when /bccwin32/
492
+ # replace '/' to '\\' because bcc linker misunderstands
493
+ # 'C:/foo/bar/OCI.LIB' as unknown option.
494
+ lib = "#{base_dir}/LIB/BORLAND/OCI.LIB"
495
+ return lib.tr('/', '\\') if File.exist?(lib)
496
+ raise <<EOS
497
+ #{lib} does not exist.
498
+
499
+ Your Oracle may not support Borland C++.
500
+ If you want to run this module, run the following command at your own risk.
501
+ cd #{base_dir.tr('/', '\\')}\\LIB
502
+ mkdir Borland
503
+ cd Borland
504
+ coff2omf ..\\MSVC\\OCI.LIB OCI.LIB
505
+ EOS
506
+ exit 1
507
+ else
508
+ "\"#{base_dir}/LIB/MSVC/OCI.LIB\""
509
+ end
510
+ end
511
+
512
+ end
513
+ end
514
+
515
+ # OraConf for Full Client
516
+ class OraConfFC < OraConf
517
+ def initialize
518
+ init
519
+
520
+ @oracle_home = get_home()
521
+ if RUBY_PLATFORM =~ /freebsd/ && @oracle_home == '/usr/local/oracle8-client'
522
+ @version = '817'
523
+ else
524
+ @version = get_version()
525
+ end
526
+ @cflags = get_cflags()
527
+ $CFLAGS += @cflags
528
+
529
+ if !@lp64 && File.exist?("#{@oracle_home}/lib32")
530
+ # ruby - 32bit
531
+ # oracle - 64bit
532
+ use_lib32 = true
533
+ else
534
+ use_lib32 = false
535
+ end
536
+
537
+ # default
538
+ if @version.to_i >= 900
539
+ if use_lib32
540
+ lib_dir = "#{@oracle_home}/lib32"
541
+ else
542
+ lib_dir = "#{@oracle_home}/lib"
543
+ end
544
+ case RUBY_PLATFORM
545
+ when /solaris/
546
+ @libs = " -L#{lib_dir} -R#{lib_dir} -lclntsh"
547
+ when /linux/
548
+ @libs = " -L#{lib_dir} -Wl,-rpath,#{lib_dir} -lclntsh"
549
+ else
550
+ @libs = " -L#{lib_dir} -lclntsh"
551
+ end
552
+ return if try_link_oci()
553
+ end
554
+
555
+ # get from demo_rdbms.mk
556
+ if use_lib32
557
+ if File.exist?("#{@oracle_home}/rdbms/demo/demo_rdbms32.mk")
558
+ @libs = get_libs('32', '')
559
+ else
560
+ @libs = get_libs('', '32')
561
+ end
562
+ else
563
+ @libs = get_libs()
564
+ end
565
+ return if try_link_oci()
566
+
567
+ raise 'cannot compile OCI'
568
+ end
569
+
570
+ private
571
+
572
+ def get_version
573
+ print("Get the version of Oracle from SQL*Plus... ")
574
+ STDOUT.flush
575
+ version = nil
576
+ dev_null = RUBY_PLATFORM =~ /mswin32|mingw32|bccwin32/ ? "nul" : "/dev/null"
577
+ if File.exist?("#{@oracle_home}/bin/plus80.exe")
578
+ sqlplus = "plus80.exe"
579
+ else
580
+ sqlplus = "sqlplus"
581
+ end
582
+ Logging::open do
583
+ open("|#{@oracle_home}/bin/#{sqlplus} < #{dev_null}") do |f|
584
+ while line = f.gets
585
+ print line
586
+ if line =~ /(\d+)\.(\d)\.(\d)/
587
+ version = $1 + $2 + $3
588
+ break
589
+ end
590
+ end
591
+ end
592
+ end
593
+ if version.nil?
594
+ raise 'cannot get Oracle version from sqlplus'
595
+ end
596
+ puts version
597
+ version
598
+ end # get_version
599
+
600
+ if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/ # when Windows
601
+
602
+ def is_valid_home?(oracle_home)
603
+ return false if oracle_home.nil?
604
+ sqlplus = "#{oracle_home}/bin/sqlplus.exe"
605
+ print("checking for ORACLE_HOME(#{oracle_home})... ")
606
+ STDOUT.flush
607
+ if File.exist?(sqlplus)
608
+ puts("yes")
609
+ true
610
+ else
611
+ puts("no")
612
+ false
613
+ end
614
+ end
615
+
616
+ def get_home()
617
+ oracle_home = ENV['ORACLE_HOME']
618
+ if oracle_home.nil?
619
+ struct = Struct.new("OracleHome", :name, :path)
620
+ oracle_homes = []
621
+ begin
622
+ last_home = get_local_registry("SOFTWARE\\ORACLE\\ALL_HOMES", 'LAST_HOME')
623
+ 0.upto last_home.to_i do |id|
624
+ oracle_homes << "HOME#{id}"
625
+ end
626
+ rescue MiniRegistryError
627
+ end
628
+ oracle_homes << "KEY_XE"
629
+ oracle_homes << "KEY_XEClient"
630
+ oracle_homes.collect! do |home|
631
+ begin
632
+ name = get_local_registry("SOFTWARE\\ORACLE\\#{home}", 'ORACLE_HOME_NAME')
633
+ path = get_local_registry("SOFTWARE\\ORACLE\\#{home}", 'ORACLE_HOME')
634
+ path.chomp!("\\")
635
+ struct.new(name, path) if is_valid_home?(path)
636
+ rescue MiniRegistryError
637
+ nil
638
+ end
639
+ end
640
+ oracle_homes.compact!
641
+ if oracle_homes.empty?
642
+ raise <<EOS
643
+ Set the environment variable ORACLE_HOME if Oracle Full Client.
644
+ Append the path of Oracle client libraries to #{OraConf.ld_envs[0]} if Oracle Instant Client.
645
+ EOS
646
+ end
647
+ if oracle_homes.length == 1
648
+ oracle_home = oracle_homes[0].path
649
+ else
650
+ default_path = ''
651
+ if RUBY_PLATFORM =~ /cygwin/
652
+ path_sep = ':'
653
+ dir_sep = '/'
654
+ else
655
+ path_sep = ';'
656
+ dir_sep = '\\'
657
+ end
658
+ ENV['PATH'].split(path_sep).each do |path|
659
+ path.chomp!(dir_sep)
660
+ if File.exist?("#{path}/OCI.DLL")
661
+ default_path = path
662
+ break
663
+ end
664
+ end
665
+ puts "---------------------------------------------------"
666
+ puts "Multiple Oracle Homes are found."
667
+ printf " %-15s : %s\n", "[NAME]", "[PATH]"
668
+ oracle_homes.each do |home|
669
+ if RUBY_PLATFORM =~ /cygwin/
670
+ path = `cygpath -u '#{home.path}'`.chomp!
671
+ else
672
+ path = home.path
673
+ end
674
+ if default_path.downcase == "#{path.downcase}#{dir_sep}bin"
675
+ oracle_home = home
676
+ end
677
+ printf " %-15s : %s\n", home.name, home.path
678
+ end
679
+ if oracle_home.nil?
680
+ puts "default oracle home is not found."
681
+ puts "---------------------------------------------------"
682
+ raise 'Cannot get ORACLE_HOME. Please set the environment valiable ORACLE_HOME.'
683
+ else
684
+ printf "use %s\n", oracle_home.name
685
+ puts "run ohsel.exe to use another oracle home."
686
+ puts "---------------------------------------------------"
687
+ oracle_home = oracle_home.path
688
+ end
689
+ end
690
+ end
691
+ if RUBY_PLATFORM =~ /cygwin/
692
+ oracle_home = oracle_home.sub(/^([a-zA-Z]):/, "/cygdrive/\\1")
693
+ end
694
+ oracle_home.gsub(/\\/, '/')
695
+ end
696
+
697
+ def oci_base_dir
698
+ case @version
699
+ when /80./
700
+ "#{@oracle_home}/OCI80"
701
+ else
702
+ "#{@oracle_home}/OCI"
703
+ end
704
+ end
705
+
706
+ def get_cflags
707
+ unless File.exist?("#{oci_base_dir}/INCLUDE/OCI.H")
708
+ raise "'#{oci_base_dir}/INCLUDE/OCI.H' does not exists. Please install 'Oracle Call Interface'."
709
+ end
710
+ if RUBY_PLATFORM =~ /cygwin/
711
+ " \"-I#{oci_base_dir}/INCLUDE\" -D_int64=\"long long\""
712
+ else
713
+ " \"-I#{oci_base_dir}/INCLUDE\""
714
+ end
715
+ end
716
+
717
+ else # when UNIX
718
+
719
+ def get_home
720
+ oracle_home = ENV['ORACLE_HOME']
721
+ if oracle_home.nil?
722
+ raise <<EOS
723
+ Set the environment variable ORACLE_HOME if Oracle Full Client.
724
+ Append the path of Oracle client libraries to #{OraConf.ld_envs[0]} if Oracle Instant Client.
725
+ EOS
726
+ end
727
+ oracle_home
728
+ end
729
+
730
+ def get_cflags
731
+ cflags = ''
732
+ ok = false
733
+ original_CFLAGS = $CFLAGS
734
+ begin
735
+ for i in ["rdbms/public", "rdbms/demo", "network/public", "plsql/public"]
736
+ cflags += " -I#{@oracle_home}/#{i}"
737
+ $CFLAGS += " -I#{@oracle_home}/#{i}"
738
+ print("try #{cflags}\n");
739
+ if have_header("oci.h")
740
+ ok = true
741
+ break
742
+ end
743
+ end
744
+ unless ok
745
+ if @version.to_i >= 1000
746
+ oci_h = "#{@oracle_home}/rdbms/public/oci.h"
747
+ else
748
+ oci_h = "#{@oracle_home}/rdbms/demo/oci.h"
749
+ end
750
+ unless File.exist?(oci_h)
751
+ raise "'#{oci_h}' does not exists. Install 'Oracle Call Interface' component."
752
+ end
753
+ raise 'Cannot get proper cflags.'
754
+ end
755
+ cflags
756
+ ensure
757
+ $CFLAGS = original_CFLAGS
758
+ end
759
+ end # get_cflags
760
+
761
+ def get_libs(postfix1 = '', postfix2 = "")
762
+ print("Running make for $ORACLE_HOME/rdbms/demo/demo_rdbms#{postfix1}.mk (build#{postfix2}) ...")
763
+ STDOUT.flush
764
+
765
+ make_opt = "CC='echo MARKER' EXE=/dev/null ECHODO=echo ECHO=echo GENCLNTSH='echo genclntsh'"
766
+ if @cc_is_gcc && /solaris/ =~ RUBY_PLATFORM
767
+ # suggested by Brian Candler.
768
+ make_opt += " KPIC_OPTION= NOKPIC_CCFLAGS#{postfix2}="
769
+ end
770
+
771
+ command = "|make -f #{@oracle_home}/rdbms/demo/demo_rdbms#{postfix1}.mk build#{postfix2} #{make_opt}"
772
+ marker = /^\s*MARKER/
773
+ echo = /^\s*echo/
774
+ libs = nil
775
+ Logging::open do
776
+ puts command
777
+ open(command, "r") do |f|
778
+ while line = f.gets
779
+ puts line
780
+ line.chomp!
781
+ line = $' while line =~ echo
782
+ if line =~ marker
783
+ # found a line where a compiler runs.
784
+ libs = $'
785
+ libs.gsub!(/-o\s+\/dev\/null/, "")
786
+ libs.gsub!(/-o\s+build/, "")
787
+ end
788
+ end
789
+ end
790
+ end
791
+ raise 'Cannot get proper libs.' if libs.nil?
792
+ print("OK\n")
793
+
794
+ case RUBY_PLATFORM
795
+ when /hpux/
796
+ if @cc_is_gcc
797
+ # strip +DA2.0W, +DS2.0, -Wl,+s, -Wl,+n
798
+ libs.gsub!(/\+DA\S+(\s)*/, "")
799
+ libs.gsub!(/\+DS\S+(\s)*/, "")
800
+ libs.gsub!(/-Wl,\+[sn](\s)*/, "")
801
+ end
802
+ libs.gsub!(/ -Wl,/, " ")
803
+ when /aix/
804
+ if @cc_is_gcc
805
+ # strip -bI:/xxx
806
+ libs.gsub!(/(-bI:\S+)/, '')
807
+ end
808
+ end
809
+
810
+ # remove object files from libs.
811
+ objs = []
812
+ libs.gsub!(/\S+\.o\b/) do |obj|
813
+ objs << obj
814
+ ""
815
+ end
816
+ # change object files to an archive file to work around.
817
+ if objs.length > 0
818
+ Logging::open do
819
+ puts "change object files to an archive file."
820
+ command = Config::CONFIG["AR"] + " cru oracle_objs.a " + objs.join(" ")
821
+ puts command
822
+ system(command)
823
+ libs = "oracle_objs.a " + libs
824
+ end
825
+ end
826
+ libs
827
+ end # get_libs
828
+ end
829
+ end
830
+
831
+ # OraConf for Instant Client
832
+ class OraConfIC < OraConf
833
+ def initialize(ic_dir)
834
+ init
835
+
836
+ if ic_dir =~ /^\/usr\/lib(?:64)?\/oracle\/(\d+\.\d+\.\d+\.\d+)\/client(64)?\/lib(?:64)?/
837
+ # rpm package
838
+ # official x86 rpms:
839
+ # library: /usr/lib/oracle/X.X.X.X/client/lib/
840
+ # include: /usr/include/oracle/X.X.X.X/client/
841
+ #
842
+ # official x86_64 rpms:
843
+ # library: /usr/lib/oracle/X.X.X.X/client64/lib/
844
+ # include: /usr/include/oracle/X.X.X.X/client64/
845
+ #
846
+ # third-party x86_64 rpms(*1):
847
+ # library: /usr/lib64/oracle/X.X.X.X/client/lib/
848
+ # or /usr/lib64/oracle/X.X.X.X/client/lib64/
849
+ # include: /usr/include/oracle/X.X.X.X/client/
850
+ #
851
+ # *1 These had been used before Oracle released official x86_64 rpms.
852
+ #
853
+ lib_dir = ic_dir
854
+ inc_dir = "/usr/include/oracle/#{$1}/client#{$2}"
855
+ else
856
+ # zip package
857
+ lib_dir = ic_dir
858
+ inc_dir = "#{ic_dir}/sdk/include"
859
+ end
860
+
861
+ if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/ # when Windows
862
+ unless File.exist?("#{ic_dir}/sdk/lib/msvc/oci.lib")
863
+ raise <<EOS
864
+ Could not compile with Oracle instant client.
865
+ #{ic_dir}/sdk/lib/msvc/oci.lib could not be found.
866
+ EOS
867
+ raise 'failed'
868
+ end
869
+ @cflags = " \"-I#{inc_dir}\""
870
+ @cflags += " -D_int64=\"long long\"" if RUBY_PLATFORM =~ /cygwin/
871
+ @libs = get_libs("#{ic_dir}/sdk")
872
+ ld_path = nil
873
+ else
874
+ @cflags = " -I#{inc_dir}"
875
+ # set ld_path and so_ext
876
+ case RUBY_PLATFORM
877
+ when /aix/
878
+ ld_path = 'LIBPATH'
879
+ so_ext = 'a'
880
+ when /hppa.*-hpux/
881
+ if @lp64
882
+ ld_path = 'LD_LIBRARY_PATH'
883
+ else
884
+ ld_path = 'SHLIB_PATH'
885
+ end
886
+ so_ext = 'sl'
887
+ when /darwin/
888
+ ld_path = 'DYLD_LIBRARY_PATH'
889
+ so_ext = 'dylib'
890
+ else
891
+ ld_path = 'LD_LIBRARY_PATH'
892
+ so_ext = 'so'
893
+ end
894
+ # check Oracle client library.
895
+ unless File.exist?("#{lib_dir}/libclntsh.#{so_ext}")
896
+ files = Dir.glob("#{lib_dir}/libclntsh.#{so_ext}.*")
897
+ if files.empty?
898
+ raise <<EOS
899
+ Could not compile with Oracle instant client.
900
+ '#{lib_dir}/libclntsh.#{so_ext}' could not be found.
901
+ Did you install instantclient-basic?
902
+ EOS
903
+ else
904
+ file = File.basename(files.sort[-1])
905
+ raise <<EOS
906
+ Could not compile with Oracle instant client.
907
+ #{lib_dir}/libclntsh.#{so_ext} could not be found.
908
+ You may need to make a symbolic link.
909
+ cd #{lib_dir}
910
+ ln -s #{file} libclntsh.#{so_ext}
911
+ EOS
912
+ end
913
+ raise 'failed'
914
+ end
915
+ @libs = " -L#{lib_dir} -lclntsh "
916
+ end
917
+ unless File.exist?("#{inc_dir}/oci.h")
918
+ raise <<EOS
919
+ '#{inc_dir}/oci.h' does not exist.
920
+ Install 'Instant Client SDK'.
921
+ EOS
922
+ end
923
+ $CFLAGS += @cflags
924
+ if try_link_oci()
925
+ major = try_constant("OCI_MAJOR_VERSION", "oci.h")
926
+ minor = try_constant("OCI_MINOR_VERSION", "oci.h")
927
+ if major and minor
928
+ @version = format('%d%d0', major, minor)
929
+ else
930
+ # 10.1.0 doesn't have OCI_MAJOR_VERSION and OCI_MINOR_VERSION in oci.h.
931
+ @version = "1010"
932
+ end
933
+ return
934
+ end
935
+
936
+ if RUBY_PLATFORM =~ /darwin/
937
+ is_intelmac = ([1].pack('s') == "\001\000")
938
+ arch_ppc_error = false
939
+ arch_i386_error = false
940
+ open('mkmf.log', 'r') do |f|
941
+ while line = f.gets
942
+ # universal-darwin8.0 (Mac OS X 10.4?)
943
+ if line.include? 'cputype (18, architecture ppc) does not match cputype (7)'
944
+ # try to link an i386 library but the instant client is ppc.
945
+ arch_i386_error = true
946
+ end
947
+ if line.include? 'cputype (7, architecture i386) does not match cputype (18)'
948
+ # try to link a ppc library but the instant client is i386.
949
+ arch_ppc_error = true
950
+ end
951
+ if line.include? '/libclntsh.dylib load command 8 unknown cmd field'
952
+ raise <<EOS
953
+ Intel mac instant client is for Mac OS X 10.5.
954
+ It doesn't work on Mac OS X 10.4 or before.
955
+
956
+ You have three workarounds.
957
+ 1. Compile ruby as ppc binary and use it with ppc instant client.
958
+ 2. Use JRuby and JDBC
959
+ 3. Use a third-party ODBC driver and ruby-odbc.
960
+ EOS
961
+ # '
962
+ end
963
+ # universal-darwin9.0 (Mac OS X 10.5?)
964
+ if line.include? 'Undefined symbols for architecture i386:'
965
+ # try to link an i386 library but the instant client is ppc.
966
+ arch_i386_error = true
967
+ end
968
+ if line.include? 'Undefined symbols for architecture ppc:'
969
+ # try to link a ppc library but the instant client is i386.
970
+ arch_ppc_error = true
971
+ end
972
+
973
+ if arch_i386_error
974
+ if is_intelmac
975
+ # intel mac and '-arch i386' error
976
+ raise <<EOS
977
+ Could not compile with Oracle instant client.
978
+ Use intel mac instant client.
979
+ EOS
980
+ else
981
+ # ppc mac and '-arch i386' error
982
+ raise <<EOS
983
+ Could not compile with Oracle instant client.
984
+ You may need to set a environment variable:
985
+ RC_ARCHS=ppc
986
+ export RC_ARCHS
987
+ If it does not fix the problem, delete all '-arch i386'
988
+ in '#{Config::CONFIG['archdir']}/rbconfig.rb'.
989
+ EOS
990
+ end
991
+ end
992
+
993
+ if arch_ppc_error
994
+ if is_intelmac
995
+ # intel mac and '-arch ppc' error
996
+ raise <<EOS
997
+ Could not compile with Oracle instant client.
998
+ You may need to set a environment variable:
999
+ RC_ARCHS=i386
1000
+ export RC_ARCHS
1001
+ If it does not fix the problem, delete all '-arch ppc'
1002
+ in '#{Config::CONFIG['archdir']}/rbconfig.rb'.
1003
+ EOS
1004
+ else
1005
+ # ppc mac and '-arch ppc' error
1006
+ raise <<EOS
1007
+ Could not compile with Oracle instant client.
1008
+ Use ppc instant client.
1009
+ EOS
1010
+ end
1011
+ end
1012
+ end
1013
+ end
1014
+ end
1015
+
1016
+ unless ld_path.nil?
1017
+ raise <<EOS
1018
+ Could not compile with Oracle instant client.
1019
+ You may need to set a environment variable:
1020
+ #{ld_path}=#{lib_dir}
1021
+ export #{ld_path}
1022
+ EOS
1023
+ end
1024
+ raise 'failed'
1025
+ end
1026
+ end