ruby-oci8 2.1.7 → 2.1.8
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.
- data/ChangeLog +136 -0
- data/NEWS +61 -0
- data/README.md +2 -2
- data/VERSION +1 -1
- data/dist-files +5 -0
- data/docs/install-instant-client.md +2 -0
- data/ext/oci8/attr.c +0 -9
- data/ext/oci8/bind.c +86 -28
- data/ext/oci8/connection_pool.c +32 -17
- data/ext/oci8/extconf.rb +21 -0
- data/ext/oci8/hook_funcs.c +215 -0
- data/ext/oci8/lob.c +363 -168
- data/ext/oci8/metadata.c +43 -26
- data/ext/oci8/object.c +115 -36
- data/ext/oci8/oci8.c +392 -269
- data/ext/oci8/oci8.h +88 -33
- data/ext/oci8/oci8lib.c +59 -28
- data/ext/oci8/ocidatetime.c +100 -36
- data/ext/oci8/ocihandle.c +288 -286
- data/ext/oci8/ocinumber.c +172 -112
- data/ext/oci8/oradate.c +129 -87
- data/ext/oci8/plthook.h +56 -0
- data/ext/oci8/plthook_elf.c +537 -0
- data/ext/oci8/plthook_osx.c +474 -0
- data/ext/oci8/plthook_win32.c +376 -0
- data/ext/oci8/stmt.c +112 -75
- data/lib/oci8/cursor.rb +1 -1
- data/lib/oci8/oci8.rb +71 -0
- data/lib/oci8/properties.rb +18 -3
- metadata +10 -16
@@ -0,0 +1,376 @@
|
|
1
|
+
/* -*- indent-tabs-mode: nil -*-
|
2
|
+
*
|
3
|
+
* plthook_win32.c -- implemention of plthook for PE format
|
4
|
+
*
|
5
|
+
* URL: https://github.com/kubo/plthook
|
6
|
+
*
|
7
|
+
* ------------------------------------------------------
|
8
|
+
*
|
9
|
+
* Copyright 2013-2014 Kubo Takehiro <kubo@jiubao.org>
|
10
|
+
*
|
11
|
+
* Redistribution and use in source and binary forms, with or without modification, are
|
12
|
+
* permitted provided that the following conditions are met:
|
13
|
+
*
|
14
|
+
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
15
|
+
* conditions and the following disclaimer.
|
16
|
+
*
|
17
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
18
|
+
* of conditions and the following disclaimer in the documentation and/or other materials
|
19
|
+
* provided with the distribution.
|
20
|
+
*
|
21
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
22
|
+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
23
|
+
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
24
|
+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
27
|
+
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
29
|
+
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
*
|
31
|
+
* The views and conclusions contained in the software and documentation are those of the
|
32
|
+
* authors and should not be interpreted as representing official policies, either expressed
|
33
|
+
* or implied, of the authors.
|
34
|
+
*
|
35
|
+
*/
|
36
|
+
#include <stdio.h>
|
37
|
+
#include <stddef.h>
|
38
|
+
#include <stdarg.h>
|
39
|
+
#include <windows.h>
|
40
|
+
#include <dbghelp.h>
|
41
|
+
#include "plthook.h"
|
42
|
+
|
43
|
+
#ifdef _MSC_VER
|
44
|
+
#pragma comment(lib, "dbghelp.lib")
|
45
|
+
#endif
|
46
|
+
|
47
|
+
#ifndef _Printf_format_string_
|
48
|
+
#define _Printf_format_string_
|
49
|
+
#endif
|
50
|
+
#ifndef __GNUC__
|
51
|
+
#define __attribute__(arg)
|
52
|
+
#endif
|
53
|
+
|
54
|
+
#ifdef _WIN64
|
55
|
+
#define SIZE_T_FMT "I64u"
|
56
|
+
#else
|
57
|
+
#define SIZE_T_FMT "u"
|
58
|
+
#endif
|
59
|
+
|
60
|
+
typedef struct {
|
61
|
+
const char *mod_name;
|
62
|
+
const char *name;
|
63
|
+
void **addr;
|
64
|
+
} import_address_entry_t;
|
65
|
+
|
66
|
+
struct plthook {
|
67
|
+
HMODULE hMod;
|
68
|
+
unsigned int num_entries;
|
69
|
+
import_address_entry_t entries[1];
|
70
|
+
};
|
71
|
+
|
72
|
+
static char errbuf[512];
|
73
|
+
static int plthook_open_real(plthook_t **plthook_out, HMODULE hMod);
|
74
|
+
static void set_errmsg(_Printf_format_string_ const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
75
|
+
static void set_errmsg2(_Printf_format_string_ const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
76
|
+
static const char *winsock2_ordinal2name(int ordinal);
|
77
|
+
|
78
|
+
int plthook_open(plthook_t **plthook_out, const char *filename)
|
79
|
+
{
|
80
|
+
HMODULE hMod;
|
81
|
+
|
82
|
+
*plthook_out = NULL;
|
83
|
+
if (!GetModuleHandleExA(0, filename, &hMod)) {
|
84
|
+
set_errmsg2("Cannot get module %s: ", filename);
|
85
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
86
|
+
}
|
87
|
+
return plthook_open_real(plthook_out, hMod);
|
88
|
+
}
|
89
|
+
|
90
|
+
int plthook_open_by_address(plthook_t **plthook_out, void *address)
|
91
|
+
{
|
92
|
+
HMODULE hMod;
|
93
|
+
|
94
|
+
*plthook_out = NULL;
|
95
|
+
if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &hMod)) {
|
96
|
+
set_errmsg2("Cannot get module at address %p: ", address);
|
97
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
98
|
+
}
|
99
|
+
return plthook_open_real(plthook_out, hMod);
|
100
|
+
}
|
101
|
+
|
102
|
+
static int plthook_open_real(plthook_t **plthook_out, HMODULE hMod)
|
103
|
+
{
|
104
|
+
plthook_t *plthook;
|
105
|
+
ULONG ulSize;
|
106
|
+
IMAGE_IMPORT_DESCRIPTOR *desc_head, *desc;
|
107
|
+
size_t num_entries = 0;
|
108
|
+
size_t ordinal_name_buflen = 0;
|
109
|
+
size_t idx;
|
110
|
+
char *ordinal_name_buf;
|
111
|
+
|
112
|
+
desc_head = (IMAGE_IMPORT_DESCRIPTOR*)ImageDirectoryEntryToData(hMod, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
|
113
|
+
if (desc_head == NULL) {
|
114
|
+
set_errmsg2("ImageDirectoryEntryToData error: ");
|
115
|
+
return PLTHOOK_INTERNAL_ERROR;
|
116
|
+
}
|
117
|
+
|
118
|
+
/* Calculate size to allocate memory. */
|
119
|
+
for (desc = desc_head; desc->Name != 0; desc++) {
|
120
|
+
IMAGE_THUNK_DATA *name_thunk = (IMAGE_THUNK_DATA*)((char*)hMod + desc->OriginalFirstThunk);
|
121
|
+
IMAGE_THUNK_DATA *addr_thunk = (IMAGE_THUNK_DATA*)((char*)hMod + desc->FirstThunk);
|
122
|
+
int is_winsock2_dll = (stricmp((char *)hMod + desc->Name, "WS2_32.DLL") == 0);
|
123
|
+
|
124
|
+
while (addr_thunk->u1.Function != 0) {
|
125
|
+
if (IMAGE_SNAP_BY_ORDINAL(name_thunk->u1.Ordinal)) {
|
126
|
+
int ordinal = IMAGE_ORDINAL(name_thunk->u1.Ordinal);
|
127
|
+
const char *name = NULL;
|
128
|
+
if (is_winsock2_dll) {
|
129
|
+
name = winsock2_ordinal2name(ordinal);
|
130
|
+
}
|
131
|
+
if (name == NULL) {
|
132
|
+
char buf[64];
|
133
|
+
ordinal_name_buflen += sprintf(buf, "#%d", ordinal) + 1;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
num_entries++;
|
137
|
+
name_thunk++;
|
138
|
+
addr_thunk++;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
plthook = calloc(1, offsetof(plthook_t, entries) + sizeof(import_address_entry_t) * num_entries + ordinal_name_buflen);
|
143
|
+
if (plthook == NULL) {
|
144
|
+
set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", sizeof(plthook_t));
|
145
|
+
return PLTHOOK_OUT_OF_MEMORY;
|
146
|
+
}
|
147
|
+
plthook->hMod = hMod;
|
148
|
+
plthook->num_entries = num_entries;
|
149
|
+
|
150
|
+
ordinal_name_buf = (char*)plthook + offsetof(plthook_t, entries) + sizeof(import_address_entry_t) * num_entries;
|
151
|
+
idx = 0;
|
152
|
+
for (desc = desc_head; desc->Name != 0; desc++) {
|
153
|
+
IMAGE_THUNK_DATA *name_thunk = (IMAGE_THUNK_DATA*)((char*)hMod + desc->OriginalFirstThunk);
|
154
|
+
IMAGE_THUNK_DATA *addr_thunk = (IMAGE_THUNK_DATA*)((char*)hMod + desc->FirstThunk);
|
155
|
+
int is_winsock2_dll = (stricmp((char *)hMod + desc->Name, "WS2_32.DLL") == 0);
|
156
|
+
|
157
|
+
while (addr_thunk->u1.Function != 0) {
|
158
|
+
const char *name = NULL;
|
159
|
+
|
160
|
+
if (IMAGE_SNAP_BY_ORDINAL(name_thunk->u1.Ordinal)) {
|
161
|
+
int ordinal = IMAGE_ORDINAL(name_thunk->u1.Ordinal);
|
162
|
+
if (is_winsock2_dll) {
|
163
|
+
name = winsock2_ordinal2name(ordinal);
|
164
|
+
}
|
165
|
+
if (name == NULL) {
|
166
|
+
ordinal_name_buf += sprintf(ordinal_name_buf, "#%d", ordinal) + 1;
|
167
|
+
}
|
168
|
+
} else {
|
169
|
+
name = (char*)((PIMAGE_IMPORT_BY_NAME)((char*)hMod + name_thunk->u1.AddressOfData))->Name;
|
170
|
+
}
|
171
|
+
plthook->entries[idx].mod_name = (char *)hMod + desc->Name;
|
172
|
+
plthook->entries[idx].name = name;
|
173
|
+
plthook->entries[idx].addr = (void**)&addr_thunk->u1.Function;
|
174
|
+
idx++;
|
175
|
+
name_thunk++;
|
176
|
+
addr_thunk++;
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
*plthook_out = plthook;
|
181
|
+
return 0;
|
182
|
+
}
|
183
|
+
|
184
|
+
int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out)
|
185
|
+
{
|
186
|
+
if (*pos >= plthook->num_entries) {
|
187
|
+
*name_out = NULL;
|
188
|
+
*addr_out = NULL;
|
189
|
+
return EOF;
|
190
|
+
}
|
191
|
+
*name_out = plthook->entries[*pos].name;
|
192
|
+
*addr_out = plthook->entries[*pos].addr;
|
193
|
+
(*pos)++;
|
194
|
+
return 0;
|
195
|
+
}
|
196
|
+
|
197
|
+
static void replace_funcaddr(void **addr, void *newfunc, void **oldfunc)
|
198
|
+
{
|
199
|
+
DWORD dwOld;
|
200
|
+
DWORD dwDummy;
|
201
|
+
|
202
|
+
if (oldfunc != NULL) {
|
203
|
+
*oldfunc = *addr;
|
204
|
+
}
|
205
|
+
VirtualProtect(addr, sizeof(void *), PAGE_EXECUTE_READWRITE, &dwOld);
|
206
|
+
*addr = newfunc;
|
207
|
+
VirtualProtect(addr, sizeof(void *), dwOld, &dwDummy);
|
208
|
+
}
|
209
|
+
|
210
|
+
int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, void **oldfunc)
|
211
|
+
{
|
212
|
+
#ifndef _WIN64
|
213
|
+
size_t funcnamelen = strlen(funcname);
|
214
|
+
#endif
|
215
|
+
unsigned int pos = 0;
|
216
|
+
const char *name;
|
217
|
+
void **addr;
|
218
|
+
int rv;
|
219
|
+
|
220
|
+
if (plthook == NULL) {
|
221
|
+
set_errmsg("invalid argument: The first argument is null.");
|
222
|
+
return PLTHOOK_INVALID_ARGUMENT;
|
223
|
+
}
|
224
|
+
while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) {
|
225
|
+
#ifdef _WIN64
|
226
|
+
if (strcmp(name, funcname) == 0) {
|
227
|
+
replace_funcaddr(addr, funcaddr, oldfunc);
|
228
|
+
return 0;
|
229
|
+
}
|
230
|
+
#else
|
231
|
+
/* Function names may be decorated in Windows 32-bit applications. */
|
232
|
+
if (strncmp(name, funcname, funcnamelen) == 0) {
|
233
|
+
if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') {
|
234
|
+
replace_funcaddr(addr, funcaddr, oldfunc);
|
235
|
+
return 0;
|
236
|
+
}
|
237
|
+
}
|
238
|
+
if (name[0] == '_' || name[0] == '@') {
|
239
|
+
name++;
|
240
|
+
if (strncmp(name, funcname, funcnamelen) == 0) {
|
241
|
+
if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') {
|
242
|
+
replace_funcaddr(addr, funcaddr, oldfunc);
|
243
|
+
return 0;
|
244
|
+
}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
#endif
|
248
|
+
}
|
249
|
+
if (rv == EOF) {
|
250
|
+
set_errmsg("no such function: %s", funcname);
|
251
|
+
rv = PLTHOOK_FUNCTION_NOT_FOUND;
|
252
|
+
}
|
253
|
+
return rv;
|
254
|
+
}
|
255
|
+
|
256
|
+
void plthook_close(plthook_t *plthook)
|
257
|
+
{
|
258
|
+
if (plthook != NULL) {
|
259
|
+
free(plthook);
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|
263
|
+
const char *plthook_error(void)
|
264
|
+
{
|
265
|
+
return errbuf;
|
266
|
+
}
|
267
|
+
|
268
|
+
static void set_errmsg(const char *fmt, ...)
|
269
|
+
{
|
270
|
+
va_list ap;
|
271
|
+
va_start(ap, fmt);
|
272
|
+
vsnprintf(errbuf, sizeof(errbuf) - 1, fmt, ap);
|
273
|
+
va_end(ap);
|
274
|
+
}
|
275
|
+
|
276
|
+
static void set_errmsg2(const char *fmt, ...)
|
277
|
+
{
|
278
|
+
va_list ap;
|
279
|
+
size_t len;
|
280
|
+
|
281
|
+
va_start(ap, fmt);
|
282
|
+
vsnprintf(errbuf, sizeof(errbuf) - 1, fmt, ap);
|
283
|
+
va_end(ap);
|
284
|
+
len = strlen(errbuf);
|
285
|
+
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
|
286
|
+
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
287
|
+
errbuf + len, sizeof(errbuf) - len - 1, NULL);
|
288
|
+
}
|
289
|
+
|
290
|
+
static const char *winsock2_ordinal2name(int ordinal)
|
291
|
+
{
|
292
|
+
switch (ordinal) {
|
293
|
+
case 1: return "accept";
|
294
|
+
case 2: return "bind";
|
295
|
+
case 3: return "closesocket";
|
296
|
+
case 4: return "connect";
|
297
|
+
case 5: return "getpeername";
|
298
|
+
case 6: return "getsockname";
|
299
|
+
case 7: return "getsockopt";
|
300
|
+
case 8: return "htonl";
|
301
|
+
case 9: return "htons";
|
302
|
+
case 10: return "inet_addr";
|
303
|
+
case 11: return "inet_ntoa";
|
304
|
+
case 12: return "ioctlsocket";
|
305
|
+
case 13: return "listen";
|
306
|
+
case 14: return "ntohl";
|
307
|
+
case 15: return "ntohs";
|
308
|
+
case 16: return "recv";
|
309
|
+
case 17: return "recvfrom";
|
310
|
+
case 18: return "select";
|
311
|
+
case 19: return "send";
|
312
|
+
case 20: return "sendto";
|
313
|
+
case 21: return "setsockopt";
|
314
|
+
case 22: return "shutdown";
|
315
|
+
case 23: return "socket";
|
316
|
+
case 24: return "MigrateWinsockConfiguration";
|
317
|
+
case 51: return "gethostbyaddr";
|
318
|
+
case 52: return "gethostbyname";
|
319
|
+
case 53: return "getprotobyname";
|
320
|
+
case 54: return "getprotobynumber";
|
321
|
+
case 55: return "getservbyname";
|
322
|
+
case 56: return "getservbyport";
|
323
|
+
case 57: return "gethostname";
|
324
|
+
case 101: return "WSAAsyncSelect";
|
325
|
+
case 102: return "WSAAsyncGetHostByAddr";
|
326
|
+
case 103: return "WSAAsyncGetHostByName";
|
327
|
+
case 104: return "WSAAsyncGetProtoByNumber";
|
328
|
+
case 105: return "WSAAsyncGetProtoByName";
|
329
|
+
case 106: return "WSAAsyncGetServByPort";
|
330
|
+
case 107: return "WSAAsyncGetServByName";
|
331
|
+
case 108: return "WSACancelAsyncRequest";
|
332
|
+
case 109: return "WSASetBlockingHook";
|
333
|
+
case 110: return "WSAUnhookBlockingHook";
|
334
|
+
case 111: return "WSAGetLastError";
|
335
|
+
case 112: return "WSASetLastError";
|
336
|
+
case 113: return "WSACancelBlockingCall";
|
337
|
+
case 114: return "WSAIsBlocking";
|
338
|
+
case 115: return "WSAStartup";
|
339
|
+
case 116: return "WSACleanup";
|
340
|
+
case 151: return "__WSAFDIsSet";
|
341
|
+
case 500: return "WEP";
|
342
|
+
case 1000: return "WSApSetPostRoutine";
|
343
|
+
case 1001: return "WsControl";
|
344
|
+
case 1002: return "closesockinfo";
|
345
|
+
case 1003: return "Arecv";
|
346
|
+
case 1004: return "Asend";
|
347
|
+
case 1005: return "WSHEnumProtocols";
|
348
|
+
case 1100: return "inet_network";
|
349
|
+
case 1101: return "getnetbyname";
|
350
|
+
case 1102: return "rcmd";
|
351
|
+
case 1103: return "rexec";
|
352
|
+
case 1104: return "rresvport";
|
353
|
+
case 1105: return "sethostname";
|
354
|
+
case 1106: return "dn_expand";
|
355
|
+
case 1107: return "WSARecvEx";
|
356
|
+
case 1108: return "s_perror";
|
357
|
+
case 1109: return "GetAddressByNameA";
|
358
|
+
case 1110: return "GetAddressByNameW";
|
359
|
+
case 1111: return "EnumProtocolsA";
|
360
|
+
case 1112: return "EnumProtocolsW";
|
361
|
+
case 1113: return "GetTypeByNameA";
|
362
|
+
case 1114: return "GetTypeByNameW";
|
363
|
+
case 1115: return "GetNameByTypeA";
|
364
|
+
case 1116: return "GetNameByTypeW";
|
365
|
+
case 1117: return "SetServiceA";
|
366
|
+
case 1118: return "SetServiceW";
|
367
|
+
case 1119: return "GetServiceA";
|
368
|
+
case 1120: return "GetServiceW";
|
369
|
+
case 1130: return "NPLoadNameSpaces";
|
370
|
+
case 1131: return "NSPStartup";
|
371
|
+
case 1140: return "TransmitFile";
|
372
|
+
case 1141: return "AcceptEx";
|
373
|
+
case 1142: return "GetAcceptExSockaddrs";
|
374
|
+
}
|
375
|
+
return NULL;
|
376
|
+
}
|
data/ext/oci8/stmt.c
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
* stmt.c - part of ruby-oci8
|
4
4
|
* implement the methods of OCIStmt.
|
5
5
|
*
|
6
|
-
* Copyright (C) 2002-
|
6
|
+
* Copyright (C) 2002-2015 Kubo Takehiro <kubo@jiubao.org>
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
#include "oci8.h"
|
10
10
|
|
11
|
-
VALUE cOCIStmt;
|
11
|
+
static VALUE cOCIStmt;
|
12
12
|
|
13
|
-
#define TO_STMT(obj) ((oci8_stmt_t *)
|
13
|
+
#define TO_STMT(obj) ((oci8_stmt_t *)oci8_check_typeddata((obj), &oci8_stmt_data_type, 1))
|
14
14
|
|
15
15
|
typedef struct {
|
16
16
|
oci8_base_t base;
|
@@ -31,28 +31,44 @@ static void oci8_stmt_free(oci8_base_t *base)
|
|
31
31
|
if (stmt->use_stmt_release) {
|
32
32
|
OCIStmtRelease(base->hp.stmt, oci8_errhp, NULL, 0, OCI_DEFAULT);
|
33
33
|
base->type = 0;
|
34
|
+
base->closed = 1;
|
34
35
|
stmt->use_stmt_release = 0;
|
35
36
|
}
|
36
37
|
}
|
37
38
|
|
38
|
-
static
|
39
|
-
|
39
|
+
static const oci8_handle_data_type_t oci8_stmt_data_type = {
|
40
|
+
{
|
41
|
+
"OCI8::Cursor",
|
42
|
+
{
|
43
|
+
(RUBY_DATA_FUNC)oci8_stmt_mark,
|
44
|
+
oci8_handle_cleanup,
|
45
|
+
oci8_handle_size,
|
46
|
+
},
|
47
|
+
&oci8_handle_data_type.rb_data_type, NULL,
|
48
|
+
#ifdef RUBY_TYPED_WB_PROTECTED
|
49
|
+
RUBY_TYPED_WB_PROTECTED,
|
50
|
+
#endif
|
51
|
+
},
|
40
52
|
oci8_stmt_free,
|
41
53
|
sizeof(oci8_stmt_t),
|
42
54
|
};
|
43
55
|
|
56
|
+
static VALUE oci8_stmt_alloc(VALUE klass)
|
57
|
+
{
|
58
|
+
return oci8_allocate_typeddata(klass, &oci8_stmt_data_type);
|
59
|
+
}
|
60
|
+
|
44
61
|
/*
|
45
|
-
*
|
46
|
-
* __initialize(connection, sql_statement)
|
62
|
+
* @overload __initialize(connection, sql_statement)
|
47
63
|
*
|
48
|
-
*
|
49
|
-
*
|
64
|
+
* @param [OCI8] connection
|
65
|
+
* @param [String] sql_statement
|
50
66
|
*
|
51
|
-
*
|
67
|
+
* @private
|
52
68
|
*/
|
53
69
|
static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
|
54
70
|
{
|
55
|
-
oci8_stmt_t *stmt =
|
71
|
+
oci8_stmt_t *stmt = TO_STMT(self);
|
56
72
|
oci8_svcctx_t *svcctx;
|
57
73
|
sword rv;
|
58
74
|
|
@@ -81,36 +97,33 @@ static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
|
|
81
97
|
}
|
82
98
|
}
|
83
99
|
}
|
84
|
-
stmt->svc
|
100
|
+
RB_OBJ_WRITE(stmt->base.self, &stmt->svc, svc);
|
85
101
|
|
86
|
-
oci8_link_to_parent(
|
102
|
+
oci8_link_to_parent(&stmt->base, &svcctx->base);
|
87
103
|
return Qnil;
|
88
104
|
}
|
89
105
|
|
90
106
|
/*
|
91
|
-
*
|
92
|
-
* __define(position, bindobj)
|
107
|
+
* @overload __define(position, bindobj)
|
93
108
|
*
|
94
|
-
*
|
95
|
-
*
|
109
|
+
* @param [Integer] position
|
110
|
+
* @param [OCI8::BindType::Base] bindobj
|
96
111
|
*
|
97
|
-
*
|
112
|
+
* @private
|
98
113
|
*/
|
99
114
|
static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
|
100
115
|
{
|
101
116
|
oci8_stmt_t *stmt = TO_STMT(self);
|
102
|
-
ub4 position;
|
103
|
-
oci8_bind_t *obind;
|
104
|
-
const
|
117
|
+
ub4 position = NUM2INT(vposition);
|
118
|
+
oci8_bind_t *obind = TO_BIND(vbindobj);
|
119
|
+
const oci8_bind_data_type_t *data_type;
|
105
120
|
sword status;
|
106
121
|
|
107
|
-
position = NUM2INT(vposition); /* 1 */
|
108
|
-
obind = oci8_get_bind(vbindobj); /* 2 */
|
109
122
|
if (obind->base.hp.dfn != NULL) {
|
110
123
|
oci8_base_free(&obind->base); /* TODO: OK? */
|
111
124
|
}
|
112
|
-
|
113
|
-
status = OCIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, obind->valuep, obind->value_sz,
|
125
|
+
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
126
|
+
status = OCIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, obind->valuep, obind->value_sz, data_type->dty, NIL_P(obind->tdo) ? obind->u.inds : NULL, NULL, 0, OCI_DEFAULT);
|
114
127
|
if (status != OCI_SUCCESS) {
|
115
128
|
chker3(status, &stmt->base, stmt->base.hp.ptr);
|
116
129
|
}
|
@@ -122,20 +135,19 @@ static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
|
|
122
135
|
if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
|
123
136
|
chker2(OCIDefineArrayOfStruct(obind->base.hp.dfn, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0), &stmt->base);
|
124
137
|
}
|
125
|
-
if (
|
126
|
-
|
138
|
+
if (data_type->post_bind_hook != NULL) {
|
139
|
+
data_type->post_bind_hook(obind);
|
127
140
|
}
|
128
141
|
return obind->base.self;
|
129
142
|
}
|
130
143
|
|
131
144
|
/*
|
132
|
-
*
|
133
|
-
* __bind(placeholder, bindobj)
|
145
|
+
* @overload __bind(placeholder, bindobj)
|
134
146
|
*
|
135
|
-
*
|
136
|
-
*
|
147
|
+
* @param [Integer, String or Symbol] placeholder
|
148
|
+
* @param [OCI8::BindType::Base] bindobj
|
137
149
|
*
|
138
|
-
*
|
150
|
+
* @private
|
139
151
|
*/
|
140
152
|
static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
141
153
|
{
|
@@ -144,7 +156,7 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
144
156
|
ub4 placeholder_len = 0;
|
145
157
|
ub4 position = 0;
|
146
158
|
oci8_bind_t *obind;
|
147
|
-
const
|
159
|
+
const oci8_bind_data_type_t *data_type;
|
148
160
|
sword status;
|
149
161
|
void *indp;
|
150
162
|
|
@@ -152,8 +164,17 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
152
164
|
placeholder_ptr = NULL;
|
153
165
|
placeholder_len = 0;
|
154
166
|
} else if (SYMBOL_P(vplaceholder)) {
|
167
|
+
#ifdef HAVE_RB_SYM2STR
|
168
|
+
/* Don't use SYM2ID on ruby 2.2.0 or later.
|
169
|
+
* Symbols passed to SYM2ID are not GC'ed.
|
170
|
+
*/
|
171
|
+
VALUE symval = rb_sym2str(vplaceholder);
|
172
|
+
const char *symname = RSTRING_PTR(symval);
|
173
|
+
size_t len = RSTRING_LEN(symval);
|
174
|
+
#else
|
155
175
|
const char *symname = rb_id2name(SYM2ID(vplaceholder));
|
156
176
|
size_t len = strlen(symname);
|
177
|
+
#endif
|
157
178
|
placeholder_ptr = ALLOCA_N(char, len + 1);
|
158
179
|
placeholder_len = len + 1;
|
159
180
|
placeholder_ptr[0] = ':';
|
@@ -165,17 +186,17 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
165
186
|
placeholder_ptr = RSTRING_PTR(vplaceholder);
|
166
187
|
placeholder_len = RSTRING_LEN(vplaceholder);
|
167
188
|
}
|
168
|
-
obind =
|
189
|
+
obind = TO_BIND(vbindobj); /* 2 */
|
169
190
|
if (obind->base.hp.bnd != NULL) {
|
170
191
|
oci8_base_free(&obind->base); /* TODO: OK? */
|
171
192
|
}
|
172
|
-
|
193
|
+
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
173
194
|
|
174
195
|
indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
|
175
196
|
if (placeholder_ptr == (char*)-1) {
|
176
|
-
status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, obind->valuep, obind->value_sz,
|
197
|
+
status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, obind->valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
|
177
198
|
} else {
|
178
|
-
status = OCIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, obind->valuep, obind->value_sz,
|
199
|
+
status = OCIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, obind->valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
|
179
200
|
}
|
180
201
|
if (status != OCI_SUCCESS) {
|
181
202
|
chker3(status, &stmt->base, stmt->base.hp.stmt);
|
@@ -189,8 +210,8 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
189
210
|
chker2(OCIBindArrayOfStruct(obind->base.hp.bnd, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0),
|
190
211
|
&stmt->base);
|
191
212
|
}
|
192
|
-
if (
|
193
|
-
|
213
|
+
if (data_type->post_bind_hook != NULL) {
|
214
|
+
data_type->post_bind_hook(obind);
|
194
215
|
}
|
195
216
|
return obind->base.self;
|
196
217
|
}
|
@@ -213,12 +234,11 @@ static sword oci8_call_stmt_execute(oci8_svcctx_t *svcctx, oci8_stmt_t *stmt, ub
|
|
213
234
|
}
|
214
235
|
|
215
236
|
/*
|
216
|
-
*
|
217
|
-
* __execute(iteration_count)
|
237
|
+
* @overload __execute(iteration_count)
|
218
238
|
*
|
219
|
-
*
|
239
|
+
* @param [Integer] iteration_count
|
220
240
|
*
|
221
|
-
*
|
241
|
+
* @private
|
222
242
|
*/
|
223
243
|
static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
|
224
244
|
{
|
@@ -232,13 +252,15 @@ static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
|
|
232
252
|
}
|
233
253
|
|
234
254
|
/*
|
235
|
-
*
|
236
|
-
*
|
255
|
+
* @overload __fetch(connection)
|
256
|
+
*
|
257
|
+
* Fetches one row and set the result to <code>@define_handles</code>.
|
258
|
+
* This is called by private methods of OCI8::Cursor.
|
237
259
|
*
|
238
|
-
*
|
239
|
-
*
|
260
|
+
* @param [OCI8] connection
|
261
|
+
* @return [true or false] true on success and false when all rows are fetched.
|
240
262
|
*
|
241
|
-
*
|
263
|
+
* @private
|
242
264
|
*/
|
243
265
|
static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
|
244
266
|
{
|
@@ -246,15 +268,15 @@ static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
|
|
246
268
|
oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
|
247
269
|
sword rv;
|
248
270
|
oci8_bind_t *obind;
|
249
|
-
const
|
271
|
+
const oci8_bind_data_type_t *data_type;
|
250
272
|
|
251
273
|
if (stmt->base.children != NULL) {
|
252
274
|
obind = (oci8_bind_t *)stmt->base.children;
|
253
275
|
do {
|
254
276
|
if (obind->base.type == OCI_HTYPE_DEFINE) {
|
255
|
-
|
256
|
-
if (
|
257
|
-
|
277
|
+
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
278
|
+
if (data_type->pre_fetch_hook != NULL) {
|
279
|
+
data_type->pre_fetch_hook(obind, stmt->svc);
|
258
280
|
}
|
259
281
|
}
|
260
282
|
obind = (oci8_bind_t *)obind->base.next;
|
@@ -269,13 +291,14 @@ static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
|
|
269
291
|
}
|
270
292
|
|
271
293
|
/*
|
272
|
-
*
|
273
|
-
* __paramGet(pos)
|
294
|
+
* @overload __paramGet(pos)
|
274
295
|
*
|
275
|
-
*
|
276
|
-
* @return [OCI8::Metadata::Base]
|
296
|
+
* Returns the definition of column specified by <i>pos</i>
|
277
297
|
*
|
278
|
-
*
|
298
|
+
* @param [Fixnum] pos Column position which starts from one
|
299
|
+
* @return [OCI8::Metadata::Base]
|
300
|
+
*
|
301
|
+
* @private
|
279
302
|
*/
|
280
303
|
static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
|
281
304
|
{
|
@@ -292,19 +315,19 @@ static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
|
|
292
315
|
}
|
293
316
|
|
294
317
|
/*
|
295
|
-
*
|
296
|
-
*
|
318
|
+
* Gets the rowid of the last inserted, updated or deleted row.
|
319
|
+
* This cannot be used for select statements.
|
297
320
|
*
|
298
|
-
*
|
299
|
-
*
|
300
|
-
*
|
301
|
-
*
|
321
|
+
* @example
|
322
|
+
* cursor = conn.parse('INSERT INTO foo_table values(:1, :2)', 1, 2)
|
323
|
+
* cursor.exec
|
324
|
+
* cursor.rowid # => "AAAFlLAAEAAAAG9AAA", the inserted row's rowid
|
302
325
|
*
|
303
|
-
*
|
326
|
+
* @return [String]
|
304
327
|
*/
|
305
328
|
static VALUE oci8_stmt_get_rowid(VALUE self)
|
306
329
|
{
|
307
|
-
oci8_base_t *base =
|
330
|
+
oci8_base_t *base = oci8_check_typeddata(self, &oci8_stmt_data_type, 1);
|
308
331
|
return oci8_get_rowid_attr(base, OCI_ATTR_ROWID, base->hp.stmt);
|
309
332
|
}
|
310
333
|
|
@@ -321,12 +344,9 @@ VALUE oci8_stmt_get(oci8_bind_t *obind, void *data, void *null_struct)
|
|
321
344
|
static void bind_stmt_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
|
322
345
|
{
|
323
346
|
oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
h = DATA_PTR(val);
|
328
|
-
oho->hp = h->hp.ptr;
|
329
|
-
oho->obj = val;
|
347
|
+
oci8_stmt_t *stmt = TO_STMT(val);
|
348
|
+
oho->hp = stmt->base.hp.ptr;
|
349
|
+
RB_OBJ_WRITE(obind->base.self, &oho->obj, val);
|
330
350
|
}
|
331
351
|
|
332
352
|
static void bind_stmt_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
|
@@ -343,14 +363,26 @@ static void bind_stmt_init_elem(oci8_bind_t *obind, VALUE svc)
|
|
343
363
|
|
344
364
|
do {
|
345
365
|
oho[idx].obj = rb_class_new_instance(1, &svc, cOCIStmt);
|
366
|
+
RB_OBJ_WRITTEN(obind->base.self, Qundef, oho[idx].obj);
|
346
367
|
h = DATA_PTR(oho[idx].obj);
|
347
368
|
oho[idx].hp = h->hp.ptr;
|
348
369
|
} while (++idx < obind->maxar_sz);
|
349
370
|
}
|
350
371
|
|
351
|
-
static const
|
372
|
+
static const oci8_bind_data_type_t bind_stmt_data_type = {
|
352
373
|
{
|
353
|
-
|
374
|
+
{
|
375
|
+
"OCI8::BindType::Cursor",
|
376
|
+
{
|
377
|
+
(RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
|
378
|
+
oci8_handle_cleanup,
|
379
|
+
oci8_handle_size,
|
380
|
+
},
|
381
|
+
&oci8_bind_data_type.rb_data_type, NULL,
|
382
|
+
#ifdef RUBY_TYPED_WB_PROTECTED
|
383
|
+
RUBY_TYPED_WB_PROTECTED,
|
384
|
+
#endif
|
385
|
+
},
|
354
386
|
oci8_bind_free,
|
355
387
|
sizeof(oci8_bind_t)
|
356
388
|
},
|
@@ -362,6 +394,11 @@ static const oci8_bind_vtable_t bind_stmt_vtable = {
|
|
362
394
|
SQLT_RSET
|
363
395
|
};
|
364
396
|
|
397
|
+
static VALUE bind_stmt_alloc(VALUE klass)
|
398
|
+
{
|
399
|
+
return oci8_allocate_typeddata(klass, &bind_stmt_data_type.base);
|
400
|
+
}
|
401
|
+
|
365
402
|
void Init_oci8_stmt(VALUE cOCI8)
|
366
403
|
{
|
367
404
|
#if 0
|
@@ -369,7 +406,7 @@ void Init_oci8_stmt(VALUE cOCI8)
|
|
369
406
|
cOCI8 = rb_define_class("OCI8", cOCIHandle);
|
370
407
|
cOCIStmt = rb_define_class_under(cOCI8, "Cursor", cOCIHandle);
|
371
408
|
#endif
|
372
|
-
cOCIStmt = oci8_define_class_under(cOCI8, "Cursor", &
|
409
|
+
cOCIStmt = oci8_define_class_under(cOCI8, "Cursor", &oci8_stmt_data_type, oci8_stmt_alloc);
|
373
410
|
|
374
411
|
rb_define_private_method(cOCIStmt, "__initialize", oci8_stmt_initialize, 2);
|
375
412
|
rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2);
|
@@ -379,5 +416,5 @@ void Init_oci8_stmt(VALUE cOCI8)
|
|
379
416
|
rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1);
|
380
417
|
rb_define_method(cOCIStmt, "rowid", oci8_stmt_get_rowid, 0);
|
381
418
|
|
382
|
-
oci8_define_bind_class("Cursor", &
|
419
|
+
oci8_define_bind_class("Cursor", &bind_stmt_data_type, bind_stmt_alloc);
|
383
420
|
}
|