ruby-oci8 2.1.8 → 2.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,6 @@
4
4
  *
5
5
  * Copyright (C) 2011 KUBO Takehiro <kubo@jiubao.org>
6
6
  */
7
- #ifdef USE_THREAD_LOCAL_ERRHP
8
7
 
9
8
  /*
10
9
  * Prepare to execute thread-related functions.
@@ -17,14 +16,3 @@ void Init_oci8_thread_util(void);
17
16
  * The return value is errno.
18
17
  */
19
18
  int oci8_run_native_thread(void *(*func)(void *), void *arg);
20
-
21
- #else
22
-
23
- /*
24
- * For ruby 1.8 configured without --enable-pthread on Unix.
25
- */
26
-
27
- #define Init_oci8_thread_util() do {} while (0)
28
- #define oci8_run_native_thread(func, arg) ((func)(arg), 0)
29
-
30
- #endif
@@ -0,0 +1,71 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ util.c - part of ruby-oci8
4
+
5
+ Copyright (C) 2015 Kubo Takehiro <kubo@jiubao.org>
6
+ */
7
+ #if defined __linux && !defined(_GNU_SOURCE)
8
+ #define _GNU_SOURCE 1
9
+ #endif
10
+ #include "oci8.h"
11
+ #ifdef HAVE_DLADDR
12
+ #include <dlfcn.h>
13
+ #endif
14
+ #ifdef __CYGWIN__
15
+ #undef boolean
16
+ #include <windows.h>
17
+ #endif
18
+
19
+ const char *oci8_dll_path(void)
20
+ {
21
+ #if defined _WIN32 || defined __CYGWIN__
22
+ HMODULE hMod = GetModuleHandleA("OCI.DLL");
23
+ static char buf[MAX_PATH];
24
+ if (hMod != NULL) {
25
+ if (GetModuleFileName(hMod, buf, sizeof(buf))) {
26
+ return buf;
27
+ }
28
+ }
29
+ #elif defined HAVE_DLADDR && defined RTLD_DEFAULT
30
+ void *addr = dlsym(RTLD_DEFAULT, "OCIEnvCreate");
31
+ Dl_info info;
32
+ if (addr != NULL && dladdr(addr, &info)) {
33
+ return info.dli_fname;
34
+ }
35
+ #elif defined HAVE_DLMODINFO && defined HAVE_DLGETNAME && defined RTLD_DEFAULT
36
+ void *addr = dlsym(RTLD_DEFAULT, "OCIEnvCreate");
37
+ if (addr != NULL) {
38
+ struct load_module_desc desc;
39
+ if (dlmodinfo((uint64_t)addr, &desc, sizeof(desc), NULL, 0, 0) != 0) {
40
+ return dlgetname(&desc, sizeof(desc), NULL, 0, 0);
41
+ }
42
+ }
43
+ #endif
44
+ return NULL;
45
+ }
46
+
47
+ /*
48
+ * Returns the full path of Oracle client library used by the current process.
49
+ *
50
+ * @return [String]
51
+ */
52
+ static VALUE dll_path(VALUE module)
53
+ {
54
+ const char *path = oci8_dll_path();
55
+ if (path == NULL) {
56
+ return Qnil;
57
+ }
58
+ return rb_external_str_new_with_enc(path, strlen(path), rb_filesystem_encoding());
59
+ }
60
+
61
+ void Init_oci8_util(VALUE cOCI8)
62
+ {
63
+ #if 0
64
+ /* for yard */
65
+ cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
66
+ cOCI8 = rb_define_class("OCI8", cOCIHandle);
67
+ #endif
68
+ VALUE mUtil = rb_define_module_under(cOCI8, "Util");
69
+
70
+ rb_define_module_function(mUtil, "dll_path", dll_path, 0);
71
+ }
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  win32.c - part of ruby-oci8
4
4
 
5
- Copyright (C) 2009-2010 KUBO Takehiro <kubo@jiubao.org>
5
+ Copyright (C) 2009-2015 Kubo Takehiro <kubo@jiubao.org>
6
6
  */
7
7
  #include "oci8.h"
8
8
  #ifdef __CYGWIN__
@@ -41,29 +41,6 @@ static void raise_error(void)
41
41
  rb_raise(rb_eRuntimeError, "%s", msg);
42
42
  }
43
43
 
44
- /*
45
- * Returns the full path of OCI.DLL used by the current process.
46
- *
47
- * @return [String]
48
- */
49
- static VALUE dll_path(VALUE module)
50
- {
51
- HMODULE hModule;
52
- DWORD len;
53
- char path[1024];
54
-
55
- hModule = GetModuleHandle("OCI.DLL");
56
- if (hModule == NULL) {
57
- raise_error();
58
- }
59
- len = GetModuleFileName(hModule, path, sizeof(path));
60
- if (len == 0) {
61
- raise_error();
62
- }
63
- return rb_external_str_new_with_enc(path, len, rb_filesystem_encoding());
64
- }
65
-
66
-
67
44
  typedef struct {
68
45
  HKEY hKey;
69
46
  HKEY hSubKey;
@@ -154,6 +131,5 @@ void Init_oci8_win32(VALUE cOCI8)
154
131
  {
155
132
  VALUE mWin32Util = rb_define_module_under(cOCI8, "Win32Util");
156
133
 
157
- rb_define_module_function(mWin32Util, "dll_path", dll_path, 0);
158
134
  rb_define_module_function(mWin32Util, "enum_homes", enum_homes, 0);
159
135
  }
@@ -67,12 +67,20 @@ when 'jruby'
67
67
  else
68
68
  raise 'unsupported ruby engine: ' + RUBY_ENGINE
69
69
  end
70
- require so_basename
71
70
 
72
- if OCI8::VERSION != '@@OCI8_MODULE_VERSION@@'
71
+ begin
72
+ require so_basename
73
+ rescue LoadError, OCIError
74
+ require 'oci8/check_load_error'
75
+ OCI8::Util::check_load_error($!)
76
+ raise
77
+ end
78
+
79
+ require 'oci8/version.rb'
80
+ if OCI8::VERSION != OCI8::LIB_VERSION
73
81
  require 'rbconfig'
74
82
  so_name = so_basename + "." + RbConfig::CONFIG['DLEXT']
75
- raise "VERSION MISMATCH! #{so_name} version is #{OCI8::VERSION}, but oci8.rb version is @@OCI8_MODULE_VERSION@@."
83
+ raise "VERSION MISMATCH! #{so_name} version is #{OCI8::LIB_VERSION}, but oci8.rb version is #{OCI8::VERSION}."
76
84
  end
77
85
 
78
86
  require 'oci8/encoding-init.rb'
@@ -115,18 +115,12 @@ class OCI8
115
115
  param[:length] = val.size
116
116
  else
117
117
  # byte semantics
118
- if OCI8.respond_to? :encoding and OCI8.encoding != val.encoding
118
+ if OCI8.encoding != val.encoding
119
119
  # If the string encoding is different with NLS_LANG character set,
120
120
  # convert it to get the length.
121
121
  val = val.encode(OCI8.encoding)
122
122
  end
123
- if val.respond_to? :bytesize
124
- # ruby 1.8.7 or upper
125
- param[:length] = val.bytesize
126
- else
127
- # ruby 1.8.6 or lower
128
- param[:length] = val.size
129
- end
123
+ param[:length] = val.bytesize
130
124
  end
131
125
  else
132
126
  param[:length] = @@minimum_bind_length
@@ -166,11 +160,7 @@ class OCI8
166
160
  unless param[:length]
167
161
  if val.respond_to? :to_str
168
162
  val = val.to_str
169
- if val.respond_to? :bytesize
170
- param[:length] = val.bytesize
171
- else
172
- param[:length] = val.size
173
- end
163
+ param[:length] = val.bytesize
174
164
  else
175
165
  param[:length] = 400
176
166
  end
@@ -0,0 +1,99 @@
1
+ # This file is loaded only on LoadError.
2
+
3
+ class OCI8
4
+ module Util
5
+
6
+ case RUBY_PLATFORM
7
+ when /mswin32|cygwin|mingw32|bccwin32/
8
+
9
+ require 'Win32API'
10
+ MAX_PATH = 260
11
+ GetModuleFileNameA = Win32API.new('kernel32', 'GetModuleFileNameA', 'PPL', 'L')
12
+ GetSystemDirectoryA = Win32API.new('kernel32', 'GetSystemDirectoryA', 'PL', 'L')
13
+ GetWindowsDirectoryA = Win32API.new('kernel32', 'GetWindowsDirectoryA', 'PL', 'L')
14
+
15
+ def self.check_os_specific_load_error(exc)
16
+ case exc.message
17
+ when /^193: / # "193: %1 is not a valid Win32 application." in English
18
+ check_win32_pe_arch(exc.message.split(' - ')[1], "ruby-oci8")
19
+ dll_load_path_list.each do |path|
20
+ check_win32_pe_arch(File.join(path, '\OCI.DLL'), "Oracle client")
21
+ end
22
+ end
23
+ end # self.check_os_specific_load_error
24
+
25
+ def self.dll_load_path_list
26
+ buf = "\0" * MAX_PATH
27
+ paths = []
28
+ paths << buf[0, GetModuleFileNameA.call(nil, buf, MAX_PATH)].force_encoding("locale").gsub(/\\[^\\]*$/, '')
29
+ paths << buf[0, GetSystemDirectoryA.call(buf, MAX_PATH)].force_encoding("locale")
30
+ paths << buf[0, GetWindowsDirectoryA.call(buf, MAX_PATH)].force_encoding("locale")
31
+ paths << "."
32
+ paths + ENV['PATH'].split(';')
33
+ end # self.dll_load_path_list
34
+
35
+ def self.check_win32_pe_arch(filename, package)
36
+ open(filename, 'rb') do |f|
37
+ # DOS header.
38
+ if f.read(2) == 'MZ'
39
+ f.seek(60, IO::SEEK_SET)
40
+ pe_offset = f.read(4).unpack('V')[0]
41
+ f.seek(pe_offset)
42
+ # PE header.
43
+ if f.read(4) == "PE\000\000"
44
+ case f.read(2).unpack('v')[0]
45
+ when 0x8664
46
+ if [nil].pack('P').size == 4
47
+ raise LoadError, "\"#{filename}\" is x64 DLL. Use 32-bit #{package} instead."
48
+ end
49
+ return true
50
+ when 0x014c
51
+ if [nil].pack('P').size == 8
52
+ raise LoadError, "\"#{filename}\" is 32-bit DLL. Use x64 #{package} instead."
53
+ end
54
+ return true
55
+ end
56
+ end
57
+ end
58
+ raise LoadError, "\"#{filename}\" is not a valid Win32 application."
59
+ end
60
+ nil
61
+ rescue
62
+ nil
63
+ end # self.check_win32_pe_arch
64
+
65
+ when /linux/
66
+
67
+ def self.check_os_specific_load_error(exc)
68
+ case exc.message
69
+ when /^libaio\.so\.1:/ # "libaio.so.1: cannot open shared object file: No such file or directory" in English
70
+ install_cmd = if File.executable? '/usr/bin/apt-get'
71
+ 'apt-get install libaio1'
72
+ elsif File.executable? '/usr/bin/yum'
73
+ 'yum install libaio'
74
+ end
75
+ if install_cmd
76
+ raise LoadError, "You need to install libaio.so.1. Run '#{install_cmd}'."
77
+ else
78
+ raise LoadError, "You need to install libaio.so.1."
79
+ end
80
+ end
81
+ end # self.check_os_specific_load_error
82
+
83
+ else
84
+
85
+ def self.check_os_specific_load_error(exc)
86
+ end
87
+
88
+ end # case RUBY_PLATFORM
89
+
90
+ def self.check_load_error(exc)
91
+ check_os_specific_load_error(exc)
92
+ case exc.message
93
+ when /^OCI Library Initialization Error/
94
+ # TODO
95
+ end
96
+ end
97
+
98
+ end # module Util
99
+ end
@@ -5,75 +5,41 @@
5
5
  #
6
6
  class OCI8
7
7
 
8
- # get the environment variable NLS_LANG.
9
- nls_lang = ENV['NLS_LANG']
8
+ @@client_charset_name = charset_id2name(@@environment_handle.send(:attr_get_ub2, 31))
9
+ # 31 is OCI_ATTR_ENV_CHARSET_ID.
10
10
 
11
- if nls_lang.is_a? String and nls_lang.length == 0
12
- nls_lang = nil
13
- end
14
-
15
- # if NLS_LANG is not set, get it from the Windows registry.
16
- if nls_lang.nil? and defined? OCI8::Win32Util
17
- dll_path = OCI8::Win32Util.dll_path.upcase
18
- if dll_path =~ %r{\\BIN\\OCI.DLL}
19
- oracle_home = $`
20
- OCI8::Win32Util.enum_homes do |home, lang|
21
- if oracle_home == home.upcase
22
- nls_lang = lang
23
- break
11
+ if @@client_charset_name == 'US7ASCII'
12
+ # Check whether US7ASCII is explicitly set by NLS_LANG or not.
13
+ nls_lang = ENV['NLS_LANG']
14
+ if nls_lang.nil? and defined? OCI8::Win32Util
15
+ if OCI8::Util::dll_path =~ /\\BIN\\OCI\.DLL$/i
16
+ oracle_home = $`
17
+ OCI8::Win32Util.enum_homes do |home, lang|
18
+ if oracle_home == home.upcase
19
+ nls_lang = lang
20
+ break
21
+ end
24
22
  end
25
23
  end
26
24
  end
27
- end
28
-
29
- # extract the charset name.
30
- if nls_lang
31
- if nls_lang =~ /\.([[:alnum:]]+)$/
32
- @@client_charset_name = $1.upcase
33
- else
34
- raise "Invalid NLS_LANG format: #{nls_lang}"
25
+ if nls_lang.nil?
26
+ warn "Warning: NLS_LANG is not set. fallback to US7ASCII."
35
27
  end
36
- else
37
- warn "Warning: NLS_LANG is not set. fallback to US7ASCII."
38
- # @private
39
- @@client_charset_name = 'US7ASCII'
40
28
  end
41
29
 
42
- # Ruby encoding name for ruby 1.9.
43
- if OCI8.respond_to? :encoding
44
- if defined? DEFAULT_OCI8_ENCODING
45
- enc = DEFAULT_OCI8_ENCODING
46
- else
47
- require 'yaml'
48
- enc = YAML::load_file(File.dirname(__FILE__) + '/encoding.yml')[@@client_charset_name]
49
- if enc.nil?
50
- raise "Ruby encoding name is not found in encoding.yml for NLS_LANG #{nls_lang}."
51
- end
52
- if enc.is_a? Array
53
- # Use the first available encoding in the array.
54
- enc = enc.find do |e| Encoding.find(e) rescue false; end
55
- end
56
- end
57
- OCI8.encoding = enc
30
+ if defined? DEFAULT_OCI8_ENCODING
31
+ enc = DEFAULT_OCI8_ENCODING
58
32
  else
59
- # NLS ratio, maximum number of bytes per one chracter
60
- case @@client_charset_name
61
- when 'UTF8'
62
- OCI8.nls_ratio = 3
63
- when 'AL16UTF16'
64
- OCI8.nls_ratio = 4
65
- when /^[[:alpha:]]+(\d+)/
66
- # convert maximum number of bits per one chracter to NLS ratio.
67
- # charset name max bits max bytes
68
- # ------------ -------- ---------
69
- # US7ASCII 7 1
70
- # WE8ISO8859P1 8 1
71
- # JA16SJIS 16 2
72
- # AL32UTF8 32 4
73
- # ...
74
- OCI8.nls_ratio = (($1.to_i + 7) >> 3)
75
- else
76
- raise "Unknown NLS character set name format: #{@@client_charset_name}"
33
+ require 'yaml'
34
+ yaml_file = File.dirname(__FILE__) + '/encoding.yml'
35
+ enc = YAML::load_file(yaml_file)[@@client_charset_name]
36
+ if enc.nil?
37
+ raise "Cannot convert Oracle charset name #{@@client_charset_name} to Ruby encoding name in #{yaml_file}."
38
+ end
39
+ if enc.is_a? Array
40
+ # Use the first available encoding in the array.
41
+ enc = enc.find do |e| Encoding.find(e) rescue false; end
77
42
  end
78
43
  end
44
+ OCI8.encoding = enc
79
45
  end
@@ -996,20 +996,14 @@ class OCI8
996
996
  __charset_form
997
997
  end
998
998
 
999
- if OCI8.oracle_client_version >= ORAVER_9_0
1000
- # The fractional seconds precision of a datetime or interval.
1001
- #
1002
- # (unavailable on Oracle 8.1 or lower)
1003
- def fsprecision
1004
- attr_get_ub1(OCI_ATTR_FSPRECISION)
1005
- end
999
+ # The fractional seconds precision of a datetime or interval.
1000
+ def fsprecision
1001
+ attr_get_ub1(OCI_ATTR_FSPRECISION)
1002
+ end
1006
1003
 
1007
- # The leading field precision of an interval
1008
- #
1009
- # (unavailable on Oracle 8.1 or lower)
1010
- def lfprecision
1011
- attr_get_ub1(OCI_ATTR_LFPRECISION)
1012
- end
1004
+ # The leading field precision of an interval
1005
+ def lfprecision
1006
+ attr_get_ub1(OCI_ATTR_LFPRECISION)
1013
1007
  end
1014
1008
 
1015
1009
  # character set name if the type attribute is of a string/character type.
@@ -1339,30 +1333,18 @@ class OCI8
1339
1333
 
1340
1334
  ## Table 6-13 Attributes Belonging to Columns of Tables or Views
1341
1335
 
1342
- if OCI8.oracle_client_version >= ORAVER_9_0
1343
- # returns the type of length semantics of the column.
1344
- # [<tt>:byte</tt>] byte-length semantics
1345
- # [<tt>:char</tt>] character-length semantics.
1346
- #
1347
- # (unavailable on Oracle 8.1 or lower)
1348
- def char_used?
1349
- attr_get_ub1(OCI_ATTR_CHAR_USED) != 0
1350
- end
1351
-
1352
- # returns the column character length which is the number of
1353
- # characters allowed in the column. It is the counterpart of
1354
- # OCI8::Metadata::Column#data_size which gets the byte length.
1355
- def char_size
1356
- attr_get_ub2(OCI_ATTR_CHAR_SIZE)
1357
- end
1358
- else
1359
- def char_used?
1360
- false
1361
- end
1336
+ # returns the type of length semantics of the column.
1337
+ # [<tt>:byte</tt>] byte-length semantics
1338
+ # [<tt>:char</tt>] character-length semantics.
1339
+ def char_used?
1340
+ attr_get_ub1(OCI_ATTR_CHAR_USED) != 0
1341
+ end
1362
1342
 
1363
- def char_size
1364
- data_size
1365
- end
1343
+ # returns the column character length which is the number of
1344
+ # characters allowed in the column. It is the counterpart of
1345
+ # OCI8::Metadata::Column#data_size which gets the byte length.
1346
+ def char_size
1347
+ attr_get_ub2(OCI_ATTR_CHAR_SIZE)
1366
1348
  end
1367
1349
 
1368
1350
  # The maximum size of the column. This length is
@@ -1445,20 +1427,14 @@ class OCI8
1445
1427
  ## Table 6-8 Attributes Belonging to Type Attributes
1446
1428
  ## But Column also have these.
1447
1429
 
1448
- if OCI8.oracle_client_version >= ORAVER_9_0
1449
- # The fractional seconds precision of a datetime or interval.
1450
- #
1451
- # (unavailable on Oracle 8.1 or lower)
1452
- def fsprecision
1453
- attr_get_ub1(OCI_ATTR_FSPRECISION)
1454
- end
1430
+ # The fractional seconds precision of a datetime or interval.
1431
+ def fsprecision
1432
+ attr_get_ub1(OCI_ATTR_FSPRECISION)
1433
+ end
1455
1434
 
1456
- # The leading field precision of an interval
1457
- #
1458
- # (unavailable on Oracle 8.1 or lower)
1459
- def lfprecision
1460
- attr_get_ub1(OCI_ATTR_LFPRECISION)
1461
- end
1435
+ # The leading field precision of an interval
1436
+ def lfprecision
1437
+ attr_get_ub1(OCI_ATTR_LFPRECISION)
1462
1438
  end
1463
1439
 
1464
1440
  # The character set name, if the column is of a string/character type
@@ -1677,14 +1653,8 @@ class OCI8
1677
1653
 
1678
1654
  ## Table 6-15 List Attributes
1679
1655
 
1680
- if OCI8::oracle_client_version < OCI8::ORAVER_8_1
1681
- def ltype
1682
- raise "This feature is unavailable on Oracle 8.0"
1683
- end
1684
- else
1685
- def ltype
1686
- attr_get_ub2(OCI_ATTR_LTYPE)
1687
- end
1656
+ def ltype
1657
+ attr_get_ub2(OCI_ATTR_LTYPE)
1688
1658
  end
1689
1659
 
1690
1660
  # convert to array