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.
@@ -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
  }