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.
@@ -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
+ }
@@ -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-2012 KUBO Takehiro <kubo@jiubao.org>
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 *)oci8_get_handle((obj), cOCIStmt))
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 oci8_base_vtable_t oci8_stmt_vtable = {
39
- oci8_stmt_mark,
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
- * call-seq:
46
- * __initialize(connection, sql_statement)
62
+ * @overload __initialize(connection, sql_statement)
47
63
  *
48
- * @param [OCI8] connection
49
- * @param [String] sql_statement
64
+ * @param [OCI8] connection
65
+ * @param [String] sql_statement
50
66
  *
51
- * @private
67
+ * @private
52
68
  */
53
69
  static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
54
70
  {
55
- oci8_stmt_t *stmt = DATA_PTR(self);
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 = svc;
100
+ RB_OBJ_WRITE(stmt->base.self, &stmt->svc, svc);
85
101
 
86
- oci8_link_to_parent((oci8_base_t*)stmt, (oci8_base_t*)DATA_PTR(svc));
102
+ oci8_link_to_parent(&stmt->base, &svcctx->base);
87
103
  return Qnil;
88
104
  }
89
105
 
90
106
  /*
91
- * call-seq:
92
- * __define(position, bindobj)
107
+ * @overload __define(position, bindobj)
93
108
  *
94
- * @param [Integer] position
95
- * @param [OCI8::BindType::Base] bindobj
109
+ * @param [Integer] position
110
+ * @param [OCI8::BindType::Base] bindobj
96
111
  *
97
- * @private
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 oci8_bind_vtable_t *vptr;
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
- vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
113
- status = OCIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, obind->valuep, obind->value_sz, vptr->dty, NIL_P(obind->tdo) ? obind->u.inds : NULL, NULL, 0, OCI_DEFAULT);
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 (vptr->post_bind_hook != NULL) {
126
- vptr->post_bind_hook(obind);
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
- * call-seq:
133
- * __bind(placeholder, bindobj)
145
+ * @overload __bind(placeholder, bindobj)
134
146
  *
135
- * @param [Integer, String or Symbol] placeholder
136
- * @param [OCI8::BindType::Base] bindobj
147
+ * @param [Integer, String or Symbol] placeholder
148
+ * @param [OCI8::BindType::Base] bindobj
137
149
  *
138
- * @private
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 oci8_bind_vtable_t *vptr;
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 = oci8_get_bind(vbindobj); /* 2 */
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
- vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
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, vptr->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
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, vptr->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
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 (vptr->post_bind_hook != NULL) {
193
- vptr->post_bind_hook(obind);
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
- * call-seq:
217
- * __execute(iteration_count)
237
+ * @overload __execute(iteration_count)
218
238
  *
219
- * @param [Integer] iteration_count
239
+ * @param [Integer] iteration_count
220
240
  *
221
- * @private
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
- * call-seq:
236
- * __fetch(connection)
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
- * @param [OCI8] connection
239
- * @return [true or false] true on success and false when all rows are fetched.
260
+ * @param [OCI8] connection
261
+ * @return [true or false] true on success and false when all rows are fetched.
240
262
  *
241
- * @private
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 oci8_bind_vtable_t *vptr;
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
- vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
256
- if (vptr->pre_fetch_hook != NULL) {
257
- vptr->pre_fetch_hook(obind, stmt->svc);
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
- * call-seq:
273
- * __paramGet(pos)
294
+ * @overload __paramGet(pos)
274
295
  *
275
- * @param [Fixnum] pos Column position which starts from one
276
- * @return [OCI8::Metadata::Base]
296
+ * Returns the definition of column specified by <i>pos</i>
277
297
  *
278
- * @private
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
- * Get the rowid of the last inserted, updated or deleted row.
296
- * This cannot be used for select statements.
318
+ * Gets the rowid of the last inserted, updated or deleted row.
319
+ * This cannot be used for select statements.
297
320
  *
298
- * @example
299
- * cursor = conn.parse('INSERT INTO foo_table values(:1, :2)', 1, 2)
300
- * cursor.exec
301
- * cursor.rowid # => "AAAFlLAAEAAAAG9AAA", the inserted row's rowid
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
- * @return [String]
326
+ * @return [String]
304
327
  */
305
328
  static VALUE oci8_stmt_get_rowid(VALUE self)
306
329
  {
307
- oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
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
- oci8_base_t *h;
325
- if (!rb_obj_is_instance_of(val, cOCIStmt))
326
- rb_raise(rb_eArgError, "Invalid argument: %s (expect OCIStmt)", rb_class2name(CLASS_OF(val)));
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 oci8_bind_vtable_t bind_stmt_vtable = {
372
+ static const oci8_bind_data_type_t bind_stmt_data_type = {
352
373
  {
353
- oci8_bind_hp_obj_mark,
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", &oci8_stmt_vtable);
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", &bind_stmt_vtable);
419
+ oci8_define_bind_class("Cursor", &bind_stmt_data_type, bind_stmt_alloc);
383
420
  }