ruby-oci8 2.1.7 → 2.1.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|