ruby-oci8 2.2.4.1 → 2.2.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +311 -1
  3. data/NEWS +278 -46
  4. data/README.md +5 -2
  5. data/dist-files +8 -4
  6. data/docs/bind-array-to-in_cond.md +1 -1
  7. data/docs/install-instant-client.md +2 -1
  8. data/docs/install-on-osx.md +29 -116
  9. data/docs/ldap-auth-and-function-interposition.md +123 -0
  10. data/docs/number-type-mapping.md +79 -0
  11. data/ext/oci8/apiwrap.c.tmpl +2 -5
  12. data/ext/oci8/apiwrap.rb +6 -1
  13. data/ext/oci8/apiwrap.yml +34 -22
  14. data/ext/oci8/attr.c +4 -2
  15. data/ext/oci8/bind.c +366 -6
  16. data/ext/oci8/connection_pool.c +3 -3
  17. data/ext/oci8/error.c +18 -33
  18. data/ext/oci8/extconf.rb +7 -4
  19. data/ext/oci8/hook_funcs.c +128 -51
  20. data/ext/oci8/lob.c +31 -75
  21. data/ext/oci8/metadata.c +2 -2
  22. data/ext/oci8/object.c +72 -27
  23. data/ext/oci8/oci8.c +27 -119
  24. data/ext/oci8/oci8.h +21 -3
  25. data/ext/oci8/oci8lib.c +50 -37
  26. data/ext/oci8/ocihandle.c +2 -2
  27. data/ext/oci8/ocinumber.c +22 -16
  28. data/ext/oci8/oraconf.rb +130 -257
  29. data/ext/oci8/oradate.c +1 -1
  30. data/ext/oci8/plthook_elf.c +384 -300
  31. data/ext/oci8/plthook_osx.c +10 -10
  32. data/ext/oci8/stmt.c +51 -16
  33. data/ext/oci8/win32.c +4 -22
  34. data/lib/oci8/bindtype.rb +1 -15
  35. data/lib/oci8/check_load_error.rb +57 -10
  36. data/lib/oci8/cursor.rb +48 -17
  37. data/lib/oci8/metadata.rb +9 -1
  38. data/lib/oci8/object.rb +10 -0
  39. data/lib/oci8/oci8.rb +26 -25
  40. data/lib/oci8/oracle_version.rb +11 -1
  41. data/lib/oci8/version.rb +1 -1
  42. data/lib/oci8.rb +11 -4
  43. data/lib/ruby-oci8.rb +0 -3
  44. data/ruby-oci8.gemspec +2 -3
  45. data/setup.rb +11 -2
  46. data/test/README.md +37 -0
  47. data/test/config.rb +1 -1
  48. data/test/setup_test_object.sql +21 -13
  49. data/test/setup_test_package.sql +59 -0
  50. data/test/test_all.rb +1 -0
  51. data/test/test_bind_boolean.rb +99 -0
  52. data/test/test_break.rb +11 -9
  53. data/test/test_clob.rb +4 -16
  54. data/test/test_datetime.rb +8 -3
  55. data/test/test_object.rb +33 -9
  56. data/test/test_oci8.rb +169 -45
  57. data/test/test_oranumber.rb +12 -6
  58. data/test/test_package_type.rb +15 -3
  59. data/test/test_properties.rb +17 -0
  60. metadata +40 -57
  61. data/docs/osx-install-dev-tools.png +0 -0
  62. data/test/README +0 -42
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * hook.c
4
4
  *
5
- * Copyright (C) 2015 Kubo Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2015-2018 Kubo Takehiro <kubo@jiubao.org>
6
6
  */
7
7
  #if defined(_WIN32) || defined(__CYGWIN__)
8
8
  #define WINDOWS
@@ -12,15 +12,19 @@
12
12
  #include "plthook.h"
13
13
  #ifdef __CYGWIN__
14
14
  #undef boolean /* boolean defined in oratypes.h coflicts with that in windows.h */
15
+ #define stricmp strcasecmp
16
+ #define strnicmp strncasecmp
15
17
  #endif
16
18
  #ifdef WINDOWS
17
19
  #include <windows.h>
18
20
  #include <mstcpip.h>
21
+ #include <tlhelp32.h>
19
22
  #else
20
23
  #include <unistd.h>
21
24
  #include <sys/socket.h>
22
25
  #include <netinet/in.h>
23
26
  #include <netinet/tcp.h>
27
+ #include <dlfcn.h>
24
28
  #endif
25
29
 
26
30
  #ifdef WINDOWS
@@ -59,6 +63,7 @@ static int WSAAPI hook_setsockopt(SOCKET sockfd, int level, int optname, const v
59
63
  int oci8_tcp_keepalive_time = -1;
60
64
  #endif
61
65
 
66
+ static char hook_errmsg[512];
62
67
 
63
68
  typedef struct {
64
69
  const char *func_name;
@@ -95,35 +100,35 @@ static void socket_entry_clear(socket_entry_t *entry)
95
100
  UNLOCK(&lock);
96
101
  }
97
102
 
98
- static int replace_functions(const char * const *files, hook_func_entry_t *functions)
103
+ static int replace_functions(void *addr, const char *file, hook_func_entry_t *functions)
99
104
  {
105
+ plthook_t *ph;
100
106
  int i;
107
+ int rv = 0;
101
108
 
102
- for (i = 0; files[i] != NULL; i++) {
103
- const char *file = files[i];
104
- plthook_t *ph;
105
- if (plthook_open(&ph, file) == 0) {
106
- int j;
107
- int rv = 0;
108
-
109
- /* install hooks */
110
- for (j = 0; functions[j].func_name != NULL ; j++) {
111
- hook_func_entry_t *function = &functions[j];
112
- rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
113
- if (rv != 0) {
114
- while (--j >= 0) {
115
- /*restore hooked fuction address */
116
- plthook_replace(ph, functions[j].func_name, functions[j].old_func_addr, NULL);
117
- }
118
- plthook_close(ph);
119
- rb_raise(rb_eRuntimeError, "Could not replace function %s in %s", function->func_name, file);
120
- }
109
+ if (plthook_open_by_address(&ph, addr) != 0) {
110
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
111
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
112
+ return -1;
113
+ }
114
+
115
+ /* install hooks */
116
+ for (i = 0; functions[i].func_name != NULL ; i++) {
117
+ hook_func_entry_t *function = &functions[i];
118
+ rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
119
+ if (rv != 0) {
120
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
121
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
122
+ while (--i >= 0) {
123
+ /*restore hooked fuction address */
124
+ plthook_replace(ph, functions[i].func_name, functions[i].old_func_addr, NULL);
121
125
  }
122
- plthook_close(ph);
123
- return 0;
126
+ snprintf(hook_errmsg, sizeof(hook_errmsg), "Could not replace function %s in %s", function->func_name, file);
127
+ break;
124
128
  }
125
129
  }
126
- return -1;
130
+ plthook_close(ph);
131
+ return rv;
127
132
  }
128
133
 
129
134
  #ifdef WINDOWS
@@ -142,23 +147,6 @@ static int locK_is_initialized;
142
147
 
143
148
  static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
144
149
 
145
- static const char * const tcp_func_files[] = {
146
- /* full client */
147
- "orantcp12.dll",
148
- "orantcp11.dll",
149
- "orantcp10.dll",
150
- "orantcp9.dll",
151
- /* instant client basic */
152
- "oraociei12.dll",
153
- "oraociei11.dll",
154
- "oraociei10.dll",
155
- /* instant client basic lite */
156
- "oraociicus12.dll",
157
- "oraociicus11.dll",
158
- "oraociicus10.dll",
159
- NULL,
160
- };
161
-
162
150
  static hook_func_entry_t tcp_functions[] = {
163
151
  {"WSARecv", (void*)hook_WSARecv, NULL},
164
152
  {"setsockopt", (void*)hook_setsockopt, NULL},
@@ -182,6 +170,38 @@ static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount
182
170
  return rv;
183
171
  }
184
172
 
173
+ static int is_target_dll(MODULEENTRY32 *me)
174
+ {
175
+ static const char *basenames[] = {
176
+ "orantcp", // ORACLE_HOME-based client
177
+ "oraociei", // instant client basic
178
+ "oraociicus", // instant client basic lite
179
+ NULL,
180
+ };
181
+ const char **basename = basenames;
182
+ while (*basename != NULL) {
183
+ if (strnicmp(me->szModule, *basename, strlen(*basename)) == 0) {
184
+ break;
185
+ }
186
+ basename++;
187
+ }
188
+ if (*basename == NULL) {
189
+ return 0;
190
+ }
191
+ // basename{zero_or_more_digits}.dll
192
+ const char *p = me->szModule + strlen(*basename);
193
+ while ('0' <= *p && *p <= '9') {
194
+ p++;
195
+ }
196
+ if (stricmp(p, ".dll") != 0) {
197
+ return 0;
198
+ }
199
+ if (GetProcAddress((HMODULE)me->modBaseAddr, "nttini") == NULL) {
200
+ return 0;
201
+ }
202
+ return 1;
203
+ }
204
+
185
205
  void oci8_install_hook_functions()
186
206
  {
187
207
  static int hook_functions_installed = 0;
@@ -190,6 +210,9 @@ void oci8_install_hook_functions()
190
210
  DWORD data;
191
211
  DWORD cbData = sizeof(data);
192
212
  const char *reg_key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
213
+ HANDLE hSnapshot;
214
+ MODULEENTRY32 me;
215
+ BOOL module_found = FALSE;
193
216
 
194
217
  if (hook_functions_installed) {
195
218
  return;
@@ -222,7 +245,21 @@ void oci8_install_hook_functions()
222
245
  }
223
246
  RegCloseKey(hKey);
224
247
 
225
- if (replace_functions(tcp_func_files, tcp_functions) != 0) {
248
+ hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
249
+ me.dwSize = sizeof(me);
250
+ if (Module32First(hSnapshot, &me)) {
251
+ do {
252
+ if (is_target_dll(&me)) {
253
+ module_found = TRUE;
254
+ if (replace_functions(me.modBaseAddr, me.szExePath, tcp_functions) != 0) {
255
+ CloseHandle(hSnapshot);
256
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
257
+ }
258
+ }
259
+ } while (Module32Next(hSnapshot, &me));
260
+ }
261
+ CloseHandle(hSnapshot);
262
+ if (!module_found) {
226
263
  rb_raise(rb_eRuntimeError, "No DLL is found to hook.");
227
264
  }
228
265
  hook_functions_installed = 1;
@@ -247,14 +284,6 @@ static ssize_t hook_read(int fd, void *buf, size_t count);
247
284
  #define SO_EXT "so"
248
285
  #endif
249
286
 
250
- static const char * const files[] = {
251
- "libclntsh." SO_EXT ".12.1",
252
- "libclntsh." SO_EXT ".11.1",
253
- "libclntsh." SO_EXT ".10.1",
254
- "libclntsh." SO_EXT ".9.0",
255
- NULL,
256
- };
257
-
258
287
  static hook_func_entry_t functions[] = {
259
288
  {"read", (void*)hook_read, NULL},
260
289
  #ifdef SUPPORT_TCP_KEEPALIVE_TIME
@@ -279,16 +308,64 @@ static ssize_t hook_read(int fd, void *buf, size_t count)
279
308
  return rv;
280
309
  }
281
310
 
311
+ static void *ocifunc_addr(void *dlsym_handle, const char **file)
312
+ {
313
+ void *addr = dlsym(dlsym_handle, "OCIEnvCreate");
314
+ Dl_info dli;
315
+
316
+ if (addr == NULL) {
317
+ return NULL;
318
+ }
319
+ if (dladdr(addr, &dli) == 0) {
320
+ return NULL;
321
+ }
322
+ if (strstr(dli.dli_fname, "/libclntsh." SO_EXT) == NULL) {
323
+ return NULL;
324
+ }
325
+ *file = dli.dli_fname;
326
+ return addr;
327
+ }
328
+
329
+ #ifdef __linux__
330
+ #include <link.h>
331
+ static void *ocifunc_addr_linux(const char **file)
332
+ {
333
+ struct link_map *lm;
334
+ for (lm = _r_debug.r_map; lm != NULL; lm = lm->l_next) {
335
+ if (strstr(lm->l_name, "/libclntsh." SO_EXT) != NULL) {
336
+ *file = lm->l_name;
337
+ return (void*)lm->l_addr;
338
+ }
339
+ }
340
+ return NULL;
341
+ }
342
+ #endif
343
+
282
344
  void oci8_install_hook_functions(void)
283
345
  {
284
346
  static int hook_functions_installed = 0;
347
+ void *addr;
348
+ const char *file;
285
349
 
286
350
  if (hook_functions_installed) {
287
351
  return;
288
352
  }
289
- if (replace_functions(files, functions) != 0) {
353
+ addr = ocifunc_addr(RTLD_DEFAULT, &file);
354
+ if (addr == NULL) {
355
+ /* OCI symbols may be hooked by LD_PRELOAD. */
356
+ addr = ocifunc_addr(RTLD_NEXT, &file);
357
+ }
358
+ #ifdef __linux__
359
+ if (addr == NULL) {
360
+ addr = ocifunc_addr_linux(&file);
361
+ }
362
+ #endif
363
+ if (addr == NULL) {
290
364
  rb_raise(rb_eRuntimeError, "No shared library is found to hook.");
291
365
  }
366
+ if (replace_functions(addr, file, functions) != 0) {
367
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
368
+ }
292
369
  hook_functions_installed = 1;
293
370
  }
294
371
 
data/ext/oci8/lob.c CHANGED
@@ -26,8 +26,6 @@ static VALUE seek_end;
26
26
 
27
27
  enum state {
28
28
  S_NO_OPEN_CLOSE,
29
- S_OPEN,
30
- S_CLOSE,
31
29
  S_BFILE_CLOSE,
32
30
  S_BFILE_OPEN,
33
31
  };
@@ -266,28 +264,6 @@ static ub8 oci8_lob_get_length(oci8_lob_t *lob)
266
264
  return len;
267
265
  }
268
266
 
269
- static void lob_open(oci8_lob_t *lob)
270
- {
271
- if (lob->state == S_CLOSE) {
272
- oci8_svcctx_t *svcctx = check_svcctx(lob);
273
-
274
- chker2(OCILobOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_DEFAULT),
275
- &svcctx->base);
276
- lob->state = S_OPEN;
277
- }
278
- }
279
-
280
- static void lob_close(oci8_lob_t *lob)
281
- {
282
- if (lob->state == S_OPEN) {
283
- oci8_svcctx_t *svcctx = check_svcctx(lob);
284
-
285
- chker2(OCILobClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob),
286
- &svcctx->base);
287
- lob->state = S_CLOSE;
288
- }
289
- }
290
-
291
267
  static void bfile_close(oci8_lob_t *lob)
292
268
  {
293
269
  if (lob->state == S_BFILE_OPEN) {
@@ -368,7 +344,6 @@ static void bfile_close(oci8_lob_t *lob)
368
344
  static VALUE oci8_lob_close(VALUE self)
369
345
  {
370
346
  oci8_lob_t *lob = TO_LOB(self);
371
- lob_close(lob);
372
347
  oci8_base_free(&lob->base);
373
348
  return self;
374
349
  }
@@ -591,7 +566,6 @@ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
591
566
  oci8_lob_t *lob = TO_LOB(self);
592
567
  oci8_svcctx_t *svcctx = check_svcctx(lob);
593
568
 
594
- lob_open(lob);
595
569
  chker2(OCILobTrim2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2ULL(len)),
596
570
  &svcctx->base);
597
571
  return self;
@@ -665,10 +639,9 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
665
639
  {
666
640
  oci8_lob_t *lob = TO_LOB(self);
667
641
  oci8_svcctx_t *svcctx = check_svcctx(lob);
668
- ub8 lob_length;
669
- ub8 read_len;
670
642
  ub8 pos = lob->pos;
671
- long strbufsiz;
643
+ long strbufsiz = 512;
644
+ ub8 sz;
672
645
  ub8 byte_amt;
673
646
  ub8 char_amt;
674
647
  sword rv;
@@ -678,36 +651,21 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
678
651
  ub1 piece = OCI_FIRST_PIECE;
679
652
 
680
653
  rb_scan_args(argc, argv, "01", &size);
681
- lob_length = oci8_lob_get_length(lob);
682
- if (lob_length == 0 && NIL_P(size)) {
683
- return rb_usascii_str_new("", 0);
684
- }
685
- if (lob_length <= pos) /* EOF */
686
- return Qnil;
687
654
  if (NIL_P(size)) {
688
- read_len = lob_length - pos;
655
+ sz = UB4MAXVAL;
689
656
  } else {
690
- ub8 sz = NUM2ULL(size);
691
- read_len = MIN(sz, lob_length - pos);
657
+ sz = NUM2ULL(size);
658
+ }
659
+ if (lob->state == S_BFILE_CLOSE) {
660
+ open_bfile(svcctx, lob, errhp);
692
661
  }
662
+ read_more_data:
693
663
  if (lob->lobtype == OCI_TEMP_CLOB) {
694
664
  byte_amt = 0;
695
- char_amt = read_len;
696
- if (oci8_nls_ratio == 1) {
697
- strbufsiz = MIN(read_len, ULONG_MAX);
698
- } else {
699
- strbufsiz = MIN(read_len + read_len / 8, ULONG_MAX);
700
- }
701
- if (strbufsiz <= 10) {
702
- strbufsiz = 10;
703
- }
665
+ char_amt = sz;
704
666
  } else {
705
- byte_amt = read_len;
667
+ byte_amt = sz;
706
668
  char_amt = 0;
707
- strbufsiz = MIN(read_len, ULONG_MAX);
708
- }
709
- if (lob->state == S_BFILE_CLOSE) {
710
- open_bfile(svcctx, lob, errhp);
711
669
  }
712
670
  do {
713
671
  VALUE strbuf = rb_str_buf_new(strbufsiz);
@@ -737,23 +695,30 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
737
695
  }
738
696
  rb_str_set_len(strbuf, byte_amt);
739
697
  rb_ary_push(v, strbuf);
698
+ if (strbufsiz < 128 * 1024 * 1024) {
699
+ strbufsiz *= 2;
700
+ }
740
701
  } while (rv == OCI_NEED_DATA);
741
702
 
742
- if (pos >= lob_length) {
743
- lob_close(lob);
744
- bfile_close(lob);
703
+ if (NIL_P(size) && pos - lob->pos == sz) {
704
+ lob->pos = pos;
705
+ piece = OCI_FIRST_PIECE;
706
+ goto read_more_data;
745
707
  }
746
708
  lob->pos = pos;
747
709
  switch (RARRAY_LEN(v)) {
748
710
  case 0:
749
- return Qnil;
711
+ if (NIL_P(size) && pos == 0) {
712
+ return rb_usascii_str_new("", 0);
713
+ } else {
714
+ return Qnil;
715
+ }
750
716
  case 1:
751
717
  v = RARRAY_AREF(v, 0);
752
718
  break;
753
719
  default:
754
720
  v = rb_ary_join(v, Qnil);
755
721
  }
756
- OBJ_TAINT(v);
757
722
  if (lob->lobtype == OCI_TEMP_CLOB) {
758
723
  /* set encoding */
759
724
  rb_enc_associate(v, oci8_encoding);
@@ -781,7 +746,6 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
781
746
  ub8 byte_amt;
782
747
  ub8 char_amt;
783
748
 
784
- lob_open(lob);
785
749
  if (TYPE(data) != T_STRING) {
786
750
  str = rb_obj_as_string(data);
787
751
  } else {
@@ -801,48 +765,40 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
801
765
  RB_GC_GUARD(str);
802
766
  if (lob->lobtype == OCI_TEMP_CLOB) {
803
767
  lob->pos += char_amt;
804
- return UINT2NUM(char_amt);
768
+ return ULL2NUM(char_amt);
805
769
  } else {
806
770
  lob->pos += byte_amt;
807
- return UINT2NUM(byte_amt);
771
+ return ULL2NUM(byte_amt);
808
772
  }
809
773
  }
810
774
 
811
775
  /*
812
- * @deprecated I'm not sure that this is what the name indicates.
776
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
813
777
  * @private
814
778
  */
815
779
  static VALUE oci8_lob_get_sync(VALUE self)
816
780
  {
817
- oci8_lob_t *lob = TO_LOB(self);
818
- return (lob->state == S_NO_OPEN_CLOSE) ? Qtrue : Qfalse;
781
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
782
+ return Qfalse;
819
783
  }
820
784
 
821
785
  /*
822
- * @deprecated I'm not sure that this is what the name indicates.
786
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
823
787
  * @private
824
788
  */
825
789
  static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
826
790
  {
827
- oci8_lob_t *lob = TO_LOB(self);
828
- if (RTEST(b)) {
829
- lob_close(lob);
830
- lob->state = S_NO_OPEN_CLOSE;
831
- } else {
832
- if (lob->state == S_NO_OPEN_CLOSE)
833
- lob->state = S_CLOSE;
834
- }
791
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
835
792
  return b;
836
793
  }
837
794
 
838
795
  /*
839
- * @deprecated I'm not sure that this is what the name indicates.
796
+ * @deprecated LOB#flush had not worked by mistake. Do nothing now.
840
797
  * @private
841
798
  */
842
799
  static VALUE oci8_lob_flush(VALUE self)
843
800
  {
844
- oci8_lob_t *lob = TO_LOB(self);
845
- lob_close(lob);
801
+ rb_warning("LOB#flush had not worked by mistake. Do nothing now.");
846
802
  return self;
847
803
  }
848
804
 
data/ext/oci8/metadata.c CHANGED
@@ -195,7 +195,7 @@ VALUE oci8_do_describe(VALUE self, void *objptr, ub4 objlen, ub1 objtype, VALUE
195
195
  static VALUE oci8_describe(VALUE self, VALUE name, VALUE klass, VALUE check_public)
196
196
  {
197
197
  char *str;
198
- size_t idx, len;
198
+ int idx, len;
199
199
  VALUE metadata;
200
200
  VALUE obj_link = Qnil;
201
201
 
@@ -204,7 +204,7 @@ static VALUE oci8_describe(VALUE self, VALUE name, VALUE klass, VALUE check_publ
204
204
  rb_raise(rb_eArgError, "empty string is set.");
205
205
  }
206
206
  str = RSTRING_PTR(name);
207
- len = RSTRING_LEN(name);
207
+ len = RSTRING_LENINT(name);
208
208
  for (idx = 0; idx < len; idx++) {
209
209
  if (str[idx] == '@') {
210
210
  obj_link = rb_enc_str_new(str + idx + 1, len - idx - 1, oci8_encoding);