ruby-oci8 2.2.3 → 2.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +427 -0
  3. data/NEWS +335 -42
  4. data/README.md +20 -9
  5. data/dist-files +9 -3
  6. data/docs/bind-array-to-in_cond.md +2 -2
  7. data/docs/conflicts-local-connections-and-processes.md +7 -4
  8. data/docs/hanging-after-inactivity.md +63 -0
  9. data/docs/install-binary-package.md +15 -11
  10. data/docs/install-full-client.md +18 -21
  11. data/docs/install-instant-client.md +45 -27
  12. data/docs/install-on-osx.md +31 -120
  13. data/docs/ldap-auth-and-function-interposition.md +123 -0
  14. data/docs/number-type-mapping.md +79 -0
  15. data/docs/platform-specific-issues.md +17 -50
  16. data/docs/report-installation-issue.md +3 -0
  17. data/docs/timeout-parameters.md +3 -0
  18. data/ext/oci8/apiwrap.c.tmpl +2 -5
  19. data/ext/oci8/apiwrap.rb +6 -1
  20. data/ext/oci8/apiwrap.yml +34 -22
  21. data/ext/oci8/attr.c +4 -2
  22. data/ext/oci8/bind.c +366 -6
  23. data/ext/oci8/connection_pool.c +3 -3
  24. data/ext/oci8/encoding.c +5 -5
  25. data/ext/oci8/env.c +8 -2
  26. data/ext/oci8/error.c +24 -16
  27. data/ext/oci8/extconf.rb +8 -4
  28. data/ext/oci8/hook_funcs.c +274 -61
  29. data/ext/oci8/lob.c +31 -75
  30. data/ext/oci8/metadata.c +2 -2
  31. data/ext/oci8/object.c +72 -27
  32. data/ext/oci8/oci8.c +45 -132
  33. data/ext/oci8/oci8.h +32 -88
  34. data/ext/oci8/oci8lib.c +178 -38
  35. data/ext/oci8/ocihandle.c +37 -37
  36. data/ext/oci8/ocinumber.c +23 -18
  37. data/ext/oci8/oraconf.rb +158 -339
  38. data/ext/oci8/oradate.c +19 -19
  39. data/ext/oci8/plthook.h +10 -0
  40. data/ext/oci8/plthook_elf.c +433 -268
  41. data/ext/oci8/plthook_osx.c +40 -9
  42. data/ext/oci8/plthook_win32.c +9 -0
  43. data/ext/oci8/stmt.c +52 -17
  44. data/ext/oci8/win32.c +4 -22
  45. data/lib/oci8/bindtype.rb +1 -15
  46. data/lib/oci8/check_load_error.rb +57 -10
  47. data/lib/oci8/cursor.rb +57 -25
  48. data/lib/oci8/metadata.rb +9 -1
  49. data/lib/oci8/object.rb +10 -0
  50. data/lib/oci8/oci8.rb +33 -28
  51. data/lib/oci8/oracle_version.rb +11 -1
  52. data/lib/oci8/properties.rb +22 -0
  53. data/lib/oci8/version.rb +1 -1
  54. data/lib/oci8.rb +48 -4
  55. data/lib/ruby-oci8.rb +0 -3
  56. data/pre-distclean.rb +1 -3
  57. data/ruby-oci8.gemspec +3 -8
  58. data/setup.rb +11 -2
  59. data/test/README.md +37 -0
  60. data/test/config.rb +1 -1
  61. data/test/setup_test_object.sql +21 -13
  62. data/test/setup_test_package.sql +59 -0
  63. data/test/test_all.rb +2 -0
  64. data/test/test_bind_boolean.rb +99 -0
  65. data/test/test_bind_integer.rb +47 -0
  66. data/test/test_break.rb +11 -9
  67. data/test/test_clob.rb +4 -16
  68. data/test/test_connstr.rb +29 -13
  69. data/test/test_datetime.rb +8 -3
  70. data/test/test_object.rb +27 -9
  71. data/test/test_oci8.rb +170 -46
  72. data/test/test_oranumber.rb +12 -6
  73. data/test/test_package_type.rb +15 -3
  74. data/test/test_properties.rb +17 -0
  75. metadata +40 -54
  76. data/docs/osx-install-dev-tools.png +0 -0
  77. data/test/README +0 -42
@@ -2,29 +2,69 @@
2
2
  /*
3
3
  * hook.c
4
4
  *
5
- * Copyright (C) 2015 Kubo Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2015-2018 Kubo Takehiro <kubo@jiubao.org>
6
6
  */
7
+ #if defined(_WIN32) || defined(__CYGWIN__)
8
+ #define WINDOWS
9
+ #include <winsock2.h>
10
+ #endif
7
11
  #include "oci8.h"
8
12
  #include "plthook.h"
9
- #ifndef WIN32
13
+ #ifdef __CYGWIN__
14
+ #undef boolean /* boolean defined in oratypes.h coflicts with that in windows.h */
15
+ #define stricmp strcasecmp
16
+ #define strnicmp strncasecmp
17
+ #endif
18
+ #ifdef WINDOWS
19
+ #include <windows.h>
20
+ #include <mstcpip.h>
21
+ #include <tlhelp32.h>
22
+ #else
10
23
  #include <unistd.h>
11
24
  #include <sys/socket.h>
25
+ #include <netinet/in.h>
26
+ #include <netinet/tcp.h>
27
+ #include <dlfcn.h>
12
28
  #endif
13
29
 
14
- #define DEBUG_HOOK_FUNCS 1
15
-
16
- #ifdef WIN32
30
+ #ifdef WINDOWS
17
31
  static CRITICAL_SECTION lock;
18
32
  #define LOCK(lock) EnterCriticalSection(lock)
19
33
  #define UNLOCK(lock) LeaveCriticalSection(lock)
34
+ typedef int socklen_t;
20
35
  #else
21
36
  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
22
37
  #define LOCK(lock) pthread_mutex_lock(lock)
23
38
  #define UNLOCK(lock) pthread_mutex_unlock(lock)
24
39
  #define SOCKET int
25
40
  #define INVALID_SOCKET (-1)
41
+ #define WSAAPI
42
+ #endif
43
+
44
+ #if defined(__APPLE__) && defined(TCP_KEEPALIVE) /* macOS */
45
+ #define USE_TCP_KEEPALIVE
46
+ #define SUPPORT_TCP_KEEPALIVE_TIME
47
+ #elif defined(__sun) && defined(TCP_KEEPALIVE_THRESHOLD) /* Solaris */
48
+ #define USE_TCP_KEEPALIVE_THRESHOLD
49
+ #define SUPPORT_TCP_KEEPALIVE_TIME
50
+ #elif defined(TCP_KEEPIDLE) /* Linux, etc */
51
+ #define USE_TCP_KEEPIDLE
52
+ #define SUPPORT_TCP_KEEPALIVE_TIME
53
+ #elif defined(WINDOWS)
54
+ #define SUPPORT_TCP_KEEPALIVE_TIME
26
55
  #endif
27
56
 
57
+ int oci8_cancel_read_at_exit = 0;
58
+
59
+ #ifdef SUPPORT_TCP_KEEPALIVE_TIME
60
+ int oci8_tcp_keepalive_time = 0;
61
+ static int WSAAPI hook_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen);
62
+ #else
63
+ int oci8_tcp_keepalive_time = -1;
64
+ #endif
65
+
66
+ static char hook_errmsg[512];
67
+
28
68
  typedef struct {
29
69
  const char *func_name;
30
70
  void *func_addr;
@@ -60,62 +100,56 @@ static void socket_entry_clear(socket_entry_t *entry)
60
100
  UNLOCK(&lock);
61
101
  }
62
102
 
63
- static int replace_functions(const char * const *files, hook_func_entry_t *functions)
103
+ static int replace_functions(void *addr, const char *file, hook_func_entry_t *functions)
64
104
  {
105
+ plthook_t *ph;
65
106
  int i;
107
+ int rv = 0;
66
108
 
67
- for (i = 0; files[i] != NULL; i++) {
68
- const char *file = files[i];
69
- plthook_t *ph;
70
- if (plthook_open(&ph, file) == 0) {
71
- int j;
72
- int rv = 0;
73
-
74
- /* install hooks */
75
- for (j = 0; functions[j].func_name != NULL ; j++) {
76
- hook_func_entry_t *function = &functions[j];
77
- rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
78
- if (rv != 0) {
79
- while (--j >= 0) {
80
- /*restore hooked fuction address */
81
- plthook_replace(ph, functions[j].func_name, functions[j].old_func_addr, NULL);
82
- }
83
- plthook_close(ph);
84
- rb_raise(rb_eRuntimeError, "Could not replace function %s in %s", function->func_name, file);
85
- }
109
+ if (plthook_open_by_address(&ph, addr) != 0) {
110
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
111
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
112
+ return -1;
113
+ }
114
+
115
+ /* install hooks */
116
+ for (i = 0; functions[i].func_name != NULL ; i++) {
117
+ hook_func_entry_t *function = &functions[i];
118
+ rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
119
+ if (rv != 0) {
120
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
121
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
122
+ while (--i >= 0) {
123
+ /*restore hooked fuction address */
124
+ plthook_replace(ph, functions[i].func_name, functions[i].old_func_addr, NULL);
86
125
  }
87
- plthook_close(ph);
88
- return 0;
126
+ snprintf(hook_errmsg, sizeof(hook_errmsg), "Could not replace function %s in %s", function->func_name, file);
127
+ break;
89
128
  }
90
129
  }
91
- return -1;
130
+ plthook_close(ph);
131
+ return rv;
92
132
  }
93
133
 
94
- #ifdef WIN32
134
+ #ifdef WINDOWS
135
+
136
+ #ifndef _MSC_VER
137
+ /* setsockopt() in ws2_32.dll */
138
+ #define setsockopt rboci_setsockopt
139
+ typedef int (WSAAPI *setsockopt_t)(SOCKET, int, int, const void *, int);
140
+ static setsockopt_t setsockopt;
141
+ #endif
142
+
143
+ /* system-wide keepalive interval */
144
+ static DWORD keepalive_interval;
95
145
 
96
146
  static int locK_is_initialized;
97
147
 
98
148
  static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
99
149
 
100
- static const char * const tcp_func_files[] = {
101
- /* full client */
102
- "orantcp12.dll",
103
- "orantcp11.dll",
104
- "orantcp10.dll",
105
- "orantcp9.dll",
106
- /* instant client basic */
107
- "oraociei12.dll",
108
- "oraociei11.dll",
109
- "oraociei10.dll",
110
- /* instant client basic lite */
111
- "oraociicus12.dll",
112
- "oraociicus11.dll",
113
- "oraociicus10.dll",
114
- NULL,
115
- };
116
-
117
150
  static hook_func_entry_t tcp_functions[] = {
118
151
  {"WSARecv", (void*)hook_WSARecv, NULL},
152
+ {"setsockopt", (void*)hook_setsockopt, NULL},
119
153
  {NULL, NULL, NULL},
120
154
  };
121
155
 
@@ -123,22 +157,112 @@ static hook_func_entry_t tcp_functions[] = {
123
157
  static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
124
158
  {
125
159
  socket_entry_t entry;
160
+ int enable_cancel = oci8_cancel_read_at_exit;
126
161
  int rv;
127
162
 
128
- socket_entry_set(&entry, s);
163
+ if (enable_cancel > 0) {
164
+ socket_entry_set(&entry, s);
165
+ }
129
166
  rv = WSARecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
130
- socket_entry_clear(&entry);
167
+ if (enable_cancel > 0) {
168
+ socket_entry_clear(&entry);
169
+ }
131
170
  return rv;
132
171
  }
133
172
 
173
+ static int is_target_dll(MODULEENTRY32 *me)
174
+ {
175
+ static const char *basenames[] = {
176
+ "orantcp", // ORACLE_HOME-based client
177
+ "oraociei", // instant client basic
178
+ "oraociicus", // instant client basic lite
179
+ NULL,
180
+ };
181
+ const char **basename = basenames;
182
+ while (*basename != NULL) {
183
+ if (strnicmp(me->szModule, *basename, strlen(*basename)) == 0) {
184
+ break;
185
+ }
186
+ basename++;
187
+ }
188
+ if (*basename == NULL) {
189
+ return 0;
190
+ }
191
+ // basename{zero_or_more_digits}.dll
192
+ const char *p = me->szModule + strlen(*basename);
193
+ while ('0' <= *p && *p <= '9') {
194
+ p++;
195
+ }
196
+ if (stricmp(p, ".dll") != 0) {
197
+ return 0;
198
+ }
199
+ if (GetProcAddress((HMODULE)me->modBaseAddr, "nttini") == NULL) {
200
+ return 0;
201
+ }
202
+ return 1;
203
+ }
204
+
134
205
  void oci8_install_hook_functions()
135
206
  {
207
+ static int hook_functions_installed = 0;
208
+ HKEY hKey;
209
+ DWORD type;
210
+ DWORD data;
211
+ DWORD cbData = sizeof(data);
212
+ const char *reg_key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
213
+ HANDLE hSnapshot;
214
+ MODULEENTRY32 me;
215
+ BOOL module_found = FALSE;
216
+
217
+ if (hook_functions_installed) {
218
+ return;
219
+ }
220
+
136
221
  InitializeCriticalSectionAndSpinCount(&lock, 5000);
137
222
  locK_is_initialized = 1;
138
223
 
139
- if (replace_functions(tcp_func_files, tcp_functions) != 0) {
224
+ #ifndef _MSC_VER
225
+ /* Get setsockopt in ws2_32.dll.
226
+ * setsockopt used by mingw compiler isn't same with that in ws2_32.dll.
227
+ */
228
+ setsockopt = (setsockopt_t)GetProcAddress(GetModuleHandleA("WS2_32.DLL"), "setsockopt");
229
+ if (setsockopt == NULL){
230
+ rb_raise(rb_eRuntimeError, "setsockopt isn't found in WS2_32.DLL");
231
+ }
232
+ #endif
233
+
234
+ /* Get system-wide keepalive interval parameter.
235
+ * https://technet.microsoft.com/en-us/library/cc957548.aspx
236
+ */
237
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, reg_key, 0, KEY_QUERY_VALUE, &hKey) != 0) {
238
+ rb_raise(rb_eRuntimeError, "failed to open the registry key HKLM\\%s", reg_key);
239
+ }
240
+ keepalive_interval = 1000; /* default value when the following entry isn't found. */
241
+ if (RegQueryValueEx(hKey, "KeepAliveInterval", NULL, &type, (LPBYTE)&data, &cbData) == 0) {
242
+ if (type == REG_DWORD) {
243
+ keepalive_interval = data;
244
+ }
245
+ }
246
+ RegCloseKey(hKey);
247
+
248
+ hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
249
+ me.dwSize = sizeof(me);
250
+ if (Module32First(hSnapshot, &me)) {
251
+ do {
252
+ if (is_target_dll(&me)) {
253
+ module_found = TRUE;
254
+ if (replace_functions(me.modBaseAddr, me.szExePath, tcp_functions) != 0) {
255
+ CloseHandle(hSnapshot);
256
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
257
+ }
258
+ }
259
+ } while (Module32Next(hSnapshot, &me));
260
+ }
261
+ CloseHandle(hSnapshot);
262
+ if (!module_found) {
140
263
  rb_raise(rb_eRuntimeError, "No DLL is found to hook.");
141
264
  }
265
+ hook_functions_installed = 1;
142
266
  }
143
267
 
144
268
  static void shutdown_socket(socket_entry_t *entry)
@@ -160,35 +284,89 @@ static ssize_t hook_read(int fd, void *buf, size_t count);
160
284
  #define SO_EXT "so"
161
285
  #endif
162
286
 
163
- static const char * const files[] = {
164
- "libclntsh." SO_EXT ".12.1",
165
- "libclntsh." SO_EXT ".11.1",
166
- "libclntsh." SO_EXT ".10.1",
167
- "libclntsh." SO_EXT ".9.0",
168
- NULL,
169
- };
170
-
171
287
  static hook_func_entry_t functions[] = {
172
288
  {"read", (void*)hook_read, NULL},
289
+ #ifdef SUPPORT_TCP_KEEPALIVE_TIME
290
+ {"setsockopt", (void*)hook_setsockopt, NULL},
291
+ #endif
173
292
  {NULL, NULL, NULL},
174
293
  };
175
294
 
176
295
  static ssize_t hook_read(int fd, void *buf, size_t count)
177
296
  {
178
297
  socket_entry_t entry;
298
+ int enable_cancel = oci8_cancel_read_at_exit;
179
299
  ssize_t rv;
180
300
 
181
- socket_entry_set(&entry, fd);
301
+ if (enable_cancel > 0) {
302
+ socket_entry_set(&entry, fd);
303
+ }
182
304
  rv = read(fd, buf, count);
183
- socket_entry_clear(&entry);
305
+ if (enable_cancel > 0) {
306
+ socket_entry_clear(&entry);
307
+ }
184
308
  return rv;
185
309
  }
186
310
 
311
+ static void *ocifunc_addr(void *dlsym_handle, const char **file)
312
+ {
313
+ void *addr = dlsym(dlsym_handle, "OCIEnvCreate");
314
+ Dl_info dli;
315
+
316
+ if (addr == NULL) {
317
+ return NULL;
318
+ }
319
+ if (dladdr(addr, &dli) == 0) {
320
+ return NULL;
321
+ }
322
+ if (strstr(dli.dli_fname, "/libclntsh." SO_EXT) == NULL) {
323
+ return NULL;
324
+ }
325
+ *file = dli.dli_fname;
326
+ return addr;
327
+ }
328
+
329
+ #ifdef __linux__
330
+ #include <link.h>
331
+ static void *ocifunc_addr_linux(const char **file)
332
+ {
333
+ struct link_map *lm;
334
+ for (lm = _r_debug.r_map; lm != NULL; lm = lm->l_next) {
335
+ if (strstr(lm->l_name, "/libclntsh." SO_EXT) != NULL) {
336
+ *file = lm->l_name;
337
+ return (void*)lm->l_addr;
338
+ }
339
+ }
340
+ return NULL;
341
+ }
342
+ #endif
343
+
187
344
  void oci8_install_hook_functions(void)
188
345
  {
189
- if (replace_functions(files, functions) != 0) {
346
+ static int hook_functions_installed = 0;
347
+ void *addr;
348
+ const char *file;
349
+
350
+ if (hook_functions_installed) {
351
+ return;
352
+ }
353
+ addr = ocifunc_addr(RTLD_DEFAULT, &file);
354
+ if (addr == NULL) {
355
+ /* OCI symbols may be hooked by LD_PRELOAD. */
356
+ addr = ocifunc_addr(RTLD_NEXT, &file);
357
+ }
358
+ #ifdef __linux__
359
+ if (addr == NULL) {
360
+ addr = ocifunc_addr_linux(&file);
361
+ }
362
+ #endif
363
+ if (addr == NULL) {
190
364
  rb_raise(rb_eRuntimeError, "No shared library is found to hook.");
191
365
  }
366
+ if (replace_functions(addr, file, functions) != 0) {
367
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
368
+ }
369
+ hook_functions_installed = 1;
192
370
  }
193
371
 
194
372
  static void shutdown_socket(socket_entry_t *entry)
@@ -197,11 +375,46 @@ static void shutdown_socket(socket_entry_t *entry)
197
375
  }
198
376
  #endif
199
377
 
378
+ #ifdef SUPPORT_TCP_KEEPALIVE_TIME
379
+ static int WSAAPI hook_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen)
380
+ {
381
+ int rv = setsockopt(sockfd, level, optname, optval, optlen);
382
+
383
+ if (rv == 0 && level == SOL_SOCKET && optname == SO_KEEPALIVE
384
+ && optlen == sizeof(int) && *(const int*)optval != 0) {
385
+ /* If Oracle client libraries enables keepalive by (ENABLE=BROKEN),
386
+ * set per-connection keepalive socket options to overwrite
387
+ * system-wide setting.
388
+ */
389
+ if (oci8_tcp_keepalive_time > 0) {
390
+ #if defined(USE_TCP_KEEPALIVE) /* macOS */
391
+ setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, &oci8_tcp_keepalive_time, sizeof(int));
392
+ #elif defined(USE_TCP_KEEPALIVE_THRESHOLD) /* Solaris */
393
+ unsigned int millisec = oci8_tcp_keepalive_time * 1000;
394
+ setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &millisec, sizeof(millisec));
395
+ #elif defined(USE_TCP_KEEPIDLE) /* Linux, etc */
396
+ setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &oci8_tcp_keepalive_time, sizeof(int));
397
+ #elif defined(WINDOWS)
398
+ struct tcp_keepalive vals;
399
+ DWORD dummy;
400
+
401
+ vals.onoff = 1;
402
+ vals.keepalivetime = oci8_tcp_keepalive_time * 1000;
403
+ vals.keepaliveinterval = keepalive_interval;
404
+ WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0,
405
+ &dummy, NULL, NULL);
406
+ #endif
407
+ }
408
+ }
409
+ return rv;
410
+ }
411
+ #endif
412
+
200
413
  void oci8_shutdown_sockets(void)
201
414
  {
202
415
  socket_entry_t *entry;
203
416
 
204
- #ifdef WIN32
417
+ #ifdef WINDOWS
205
418
  if (!locK_is_initialized) {
206
419
  return;
207
420
  }
data/ext/oci8/lob.c CHANGED
@@ -26,8 +26,6 @@ static VALUE seek_end;
26
26
 
27
27
  enum state {
28
28
  S_NO_OPEN_CLOSE,
29
- S_OPEN,
30
- S_CLOSE,
31
29
  S_BFILE_CLOSE,
32
30
  S_BFILE_OPEN,
33
31
  };
@@ -266,28 +264,6 @@ static ub8 oci8_lob_get_length(oci8_lob_t *lob)
266
264
  return len;
267
265
  }
268
266
 
269
- static void lob_open(oci8_lob_t *lob)
270
- {
271
- if (lob->state == S_CLOSE) {
272
- oci8_svcctx_t *svcctx = check_svcctx(lob);
273
-
274
- chker2(OCILobOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_DEFAULT),
275
- &svcctx->base);
276
- lob->state = S_OPEN;
277
- }
278
- }
279
-
280
- static void lob_close(oci8_lob_t *lob)
281
- {
282
- if (lob->state == S_OPEN) {
283
- oci8_svcctx_t *svcctx = check_svcctx(lob);
284
-
285
- chker2(OCILobClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob),
286
- &svcctx->base);
287
- lob->state = S_CLOSE;
288
- }
289
- }
290
-
291
267
  static void bfile_close(oci8_lob_t *lob)
292
268
  {
293
269
  if (lob->state == S_BFILE_OPEN) {
@@ -368,7 +344,6 @@ static void bfile_close(oci8_lob_t *lob)
368
344
  static VALUE oci8_lob_close(VALUE self)
369
345
  {
370
346
  oci8_lob_t *lob = TO_LOB(self);
371
- lob_close(lob);
372
347
  oci8_base_free(&lob->base);
373
348
  return self;
374
349
  }
@@ -591,7 +566,6 @@ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
591
566
  oci8_lob_t *lob = TO_LOB(self);
592
567
  oci8_svcctx_t *svcctx = check_svcctx(lob);
593
568
 
594
- lob_open(lob);
595
569
  chker2(OCILobTrim2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2ULL(len)),
596
570
  &svcctx->base);
597
571
  return self;
@@ -665,10 +639,9 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
665
639
  {
666
640
  oci8_lob_t *lob = TO_LOB(self);
667
641
  oci8_svcctx_t *svcctx = check_svcctx(lob);
668
- ub8 lob_length;
669
- ub8 read_len;
670
642
  ub8 pos = lob->pos;
671
- long strbufsiz;
643
+ long strbufsiz = 512;
644
+ ub8 sz;
672
645
  ub8 byte_amt;
673
646
  ub8 char_amt;
674
647
  sword rv;
@@ -678,36 +651,21 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
678
651
  ub1 piece = OCI_FIRST_PIECE;
679
652
 
680
653
  rb_scan_args(argc, argv, "01", &size);
681
- lob_length = oci8_lob_get_length(lob);
682
- if (lob_length == 0 && NIL_P(size)) {
683
- return rb_usascii_str_new("", 0);
684
- }
685
- if (lob_length <= pos) /* EOF */
686
- return Qnil;
687
654
  if (NIL_P(size)) {
688
- read_len = lob_length - pos;
655
+ sz = UB4MAXVAL;
689
656
  } else {
690
- ub8 sz = NUM2ULL(size);
691
- read_len = MIN(sz, lob_length - pos);
657
+ sz = NUM2ULL(size);
658
+ }
659
+ if (lob->state == S_BFILE_CLOSE) {
660
+ open_bfile(svcctx, lob, errhp);
692
661
  }
662
+ read_more_data:
693
663
  if (lob->lobtype == OCI_TEMP_CLOB) {
694
664
  byte_amt = 0;
695
- char_amt = read_len;
696
- if (oci8_nls_ratio == 1) {
697
- strbufsiz = MIN(read_len, ULONG_MAX);
698
- } else {
699
- strbufsiz = MIN(read_len + read_len / 8, ULONG_MAX);
700
- }
701
- if (strbufsiz <= 10) {
702
- strbufsiz = 10;
703
- }
665
+ char_amt = sz;
704
666
  } else {
705
- byte_amt = read_len;
667
+ byte_amt = sz;
706
668
  char_amt = 0;
707
- strbufsiz = MIN(read_len, ULONG_MAX);
708
- }
709
- if (lob->state == S_BFILE_CLOSE) {
710
- open_bfile(svcctx, lob, errhp);
711
669
  }
712
670
  do {
713
671
  VALUE strbuf = rb_str_buf_new(strbufsiz);
@@ -737,23 +695,30 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
737
695
  }
738
696
  rb_str_set_len(strbuf, byte_amt);
739
697
  rb_ary_push(v, strbuf);
698
+ if (strbufsiz < 128 * 1024 * 1024) {
699
+ strbufsiz *= 2;
700
+ }
740
701
  } while (rv == OCI_NEED_DATA);
741
702
 
742
- if (pos >= lob_length) {
743
- lob_close(lob);
744
- bfile_close(lob);
703
+ if (NIL_P(size) && pos - lob->pos == sz) {
704
+ lob->pos = pos;
705
+ piece = OCI_FIRST_PIECE;
706
+ goto read_more_data;
745
707
  }
746
708
  lob->pos = pos;
747
709
  switch (RARRAY_LEN(v)) {
748
710
  case 0:
749
- return Qnil;
711
+ if (NIL_P(size) && pos == 0) {
712
+ return rb_usascii_str_new("", 0);
713
+ } else {
714
+ return Qnil;
715
+ }
750
716
  case 1:
751
717
  v = RARRAY_AREF(v, 0);
752
718
  break;
753
719
  default:
754
720
  v = rb_ary_join(v, Qnil);
755
721
  }
756
- OBJ_TAINT(v);
757
722
  if (lob->lobtype == OCI_TEMP_CLOB) {
758
723
  /* set encoding */
759
724
  rb_enc_associate(v, oci8_encoding);
@@ -781,7 +746,6 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
781
746
  ub8 byte_amt;
782
747
  ub8 char_amt;
783
748
 
784
- lob_open(lob);
785
749
  if (TYPE(data) != T_STRING) {
786
750
  str = rb_obj_as_string(data);
787
751
  } else {
@@ -801,48 +765,40 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
801
765
  RB_GC_GUARD(str);
802
766
  if (lob->lobtype == OCI_TEMP_CLOB) {
803
767
  lob->pos += char_amt;
804
- return UINT2NUM(char_amt);
768
+ return ULL2NUM(char_amt);
805
769
  } else {
806
770
  lob->pos += byte_amt;
807
- return UINT2NUM(byte_amt);
771
+ return ULL2NUM(byte_amt);
808
772
  }
809
773
  }
810
774
 
811
775
  /*
812
- * @deprecated I'm not sure that this is what the name indicates.
776
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
813
777
  * @private
814
778
  */
815
779
  static VALUE oci8_lob_get_sync(VALUE self)
816
780
  {
817
- oci8_lob_t *lob = TO_LOB(self);
818
- return (lob->state == S_NO_OPEN_CLOSE) ? Qtrue : Qfalse;
781
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
782
+ return Qfalse;
819
783
  }
820
784
 
821
785
  /*
822
- * @deprecated I'm not sure that this is what the name indicates.
786
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
823
787
  * @private
824
788
  */
825
789
  static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
826
790
  {
827
- oci8_lob_t *lob = TO_LOB(self);
828
- if (RTEST(b)) {
829
- lob_close(lob);
830
- lob->state = S_NO_OPEN_CLOSE;
831
- } else {
832
- if (lob->state == S_NO_OPEN_CLOSE)
833
- lob->state = S_CLOSE;
834
- }
791
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
835
792
  return b;
836
793
  }
837
794
 
838
795
  /*
839
- * @deprecated I'm not sure that this is what the name indicates.
796
+ * @deprecated LOB#flush had not worked by mistake. Do nothing now.
840
797
  * @private
841
798
  */
842
799
  static VALUE oci8_lob_flush(VALUE self)
843
800
  {
844
- oci8_lob_t *lob = TO_LOB(self);
845
- lob_close(lob);
801
+ rb_warning("LOB#flush had not worked by mistake. Do nothing now.");
846
802
  return self;
847
803
  }
848
804
 
data/ext/oci8/metadata.c CHANGED
@@ -195,7 +195,7 @@ VALUE oci8_do_describe(VALUE self, void *objptr, ub4 objlen, ub1 objtype, VALUE
195
195
  static VALUE oci8_describe(VALUE self, VALUE name, VALUE klass, VALUE check_public)
196
196
  {
197
197
  char *str;
198
- size_t idx, len;
198
+ int idx, len;
199
199
  VALUE metadata;
200
200
  VALUE obj_link = Qnil;
201
201
 
@@ -204,7 +204,7 @@ static VALUE oci8_describe(VALUE self, VALUE name, VALUE klass, VALUE check_publ
204
204
  rb_raise(rb_eArgError, "empty string is set.");
205
205
  }
206
206
  str = RSTRING_PTR(name);
207
- len = RSTRING_LEN(name);
207
+ len = RSTRING_LENINT(name);
208
208
  for (idx = 0; idx < len; idx++) {
209
209
  if (str[idx] == '@') {
210
210
  obj_link = rb_enc_str_new(str + idx + 1, len - idx - 1, oci8_encoding);