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.
- checksums.yaml +7 -0
- data/ChangeLog +427 -0
- data/NEWS +335 -42
- data/README.md +20 -9
- data/dist-files +9 -3
- data/docs/bind-array-to-in_cond.md +2 -2
- data/docs/conflicts-local-connections-and-processes.md +7 -4
- data/docs/hanging-after-inactivity.md +63 -0
- data/docs/install-binary-package.md +15 -11
- data/docs/install-full-client.md +18 -21
- data/docs/install-instant-client.md +45 -27
- data/docs/install-on-osx.md +31 -120
- data/docs/ldap-auth-and-function-interposition.md +123 -0
- data/docs/number-type-mapping.md +79 -0
- data/docs/platform-specific-issues.md +17 -50
- data/docs/report-installation-issue.md +3 -0
- data/docs/timeout-parameters.md +3 -0
- data/ext/oci8/apiwrap.c.tmpl +2 -5
- data/ext/oci8/apiwrap.rb +6 -1
- data/ext/oci8/apiwrap.yml +34 -22
- data/ext/oci8/attr.c +4 -2
- data/ext/oci8/bind.c +366 -6
- data/ext/oci8/connection_pool.c +3 -3
- data/ext/oci8/encoding.c +5 -5
- data/ext/oci8/env.c +8 -2
- data/ext/oci8/error.c +24 -16
- data/ext/oci8/extconf.rb +8 -4
- data/ext/oci8/hook_funcs.c +274 -61
- data/ext/oci8/lob.c +31 -75
- data/ext/oci8/metadata.c +2 -2
- data/ext/oci8/object.c +72 -27
- data/ext/oci8/oci8.c +45 -132
- data/ext/oci8/oci8.h +32 -88
- data/ext/oci8/oci8lib.c +178 -38
- data/ext/oci8/ocihandle.c +37 -37
- data/ext/oci8/ocinumber.c +23 -18
- data/ext/oci8/oraconf.rb +158 -339
- data/ext/oci8/oradate.c +19 -19
- data/ext/oci8/plthook.h +10 -0
- data/ext/oci8/plthook_elf.c +433 -268
- data/ext/oci8/plthook_osx.c +40 -9
- data/ext/oci8/plthook_win32.c +9 -0
- data/ext/oci8/stmt.c +52 -17
- data/ext/oci8/win32.c +4 -22
- data/lib/oci8/bindtype.rb +1 -15
- data/lib/oci8/check_load_error.rb +57 -10
- data/lib/oci8/cursor.rb +57 -25
- data/lib/oci8/metadata.rb +9 -1
- data/lib/oci8/object.rb +10 -0
- data/lib/oci8/oci8.rb +33 -28
- data/lib/oci8/oracle_version.rb +11 -1
- data/lib/oci8/properties.rb +22 -0
- data/lib/oci8/version.rb +1 -1
- data/lib/oci8.rb +48 -4
- data/lib/ruby-oci8.rb +0 -3
- data/pre-distclean.rb +1 -3
- data/ruby-oci8.gemspec +3 -8
- data/setup.rb +11 -2
- data/test/README.md +37 -0
- data/test/config.rb +1 -1
- data/test/setup_test_object.sql +21 -13
- data/test/setup_test_package.sql +59 -0
- data/test/test_all.rb +2 -0
- data/test/test_bind_boolean.rb +99 -0
- data/test/test_bind_integer.rb +47 -0
- data/test/test_break.rb +11 -9
- data/test/test_clob.rb +4 -16
- data/test/test_connstr.rb +29 -13
- data/test/test_datetime.rb +8 -3
- data/test/test_object.rb +27 -9
- data/test/test_oci8.rb +170 -46
- data/test/test_oranumber.rb +12 -6
- data/test/test_package_type.rb +15 -3
- data/test/test_properties.rb +17 -0
- metadata +40 -54
- data/docs/osx-install-dev-tools.png +0 -0
- data/test/README +0 -42
data/ext/oci8/hook_funcs.c
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
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(
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
88
|
-
|
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
|
-
|
130
|
+
plthook_close(ph);
|
131
|
+
return rv;
|
92
132
|
}
|
93
133
|
|
94
|
-
#ifdef
|
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
|
-
|
163
|
+
if (enable_cancel > 0) {
|
164
|
+
socket_entry_set(&entry, s);
|
165
|
+
}
|
129
166
|
rv = WSARecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
|
130
|
-
|
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
|
-
|
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
|
-
|
301
|
+
if (enable_cancel > 0) {
|
302
|
+
socket_entry_set(&entry, fd);
|
303
|
+
}
|
182
304
|
rv = read(fd, buf, count);
|
183
|
-
|
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
|
-
|
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
|
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
|
-
|
655
|
+
sz = UB4MAXVAL;
|
689
656
|
} else {
|
690
|
-
|
691
|
-
|
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 =
|
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 =
|
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
|
743
|
-
|
744
|
-
|
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
|
-
|
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
|
768
|
+
return ULL2NUM(char_amt);
|
805
769
|
} else {
|
806
770
|
lob->pos += byte_amt;
|
807
|
-
return
|
771
|
+
return ULL2NUM(byte_amt);
|
808
772
|
}
|
809
773
|
}
|
810
774
|
|
811
775
|
/*
|
812
|
-
* @deprecated
|
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
|
-
|
818
|
-
return
|
781
|
+
rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
|
782
|
+
return Qfalse;
|
819
783
|
}
|
820
784
|
|
821
785
|
/*
|
822
|
-
* @deprecated
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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 =
|
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);
|