ruby-oci8 2.0.6 → 2.1.0

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.
Files changed (59) hide show
  1. data/ChangeLog +366 -19
  2. data/Makefile +2 -8
  3. data/NEWS +111 -0
  4. data/README +4 -85
  5. data/VERSION +1 -1
  6. data/dist-files +9 -2
  7. data/ext/oci8/.document +1 -0
  8. data/ext/oci8/apiwrap.c.tmpl +12 -2
  9. data/ext/oci8/apiwrap.yml +37 -21
  10. data/ext/oci8/attr.c +23 -74
  11. data/ext/oci8/bind.c +93 -225
  12. data/ext/oci8/connection_pool.c +201 -0
  13. data/ext/oci8/encoding.c +117 -24
  14. data/ext/oci8/env.c +5 -10
  15. data/ext/oci8/error.c +171 -189
  16. data/ext/oci8/extconf.rb +6 -2
  17. data/ext/oci8/lob.c +81 -79
  18. data/ext/oci8/metadata.c +42 -177
  19. data/ext/oci8/object.c +55 -28
  20. data/ext/oci8/oci8.c +426 -294
  21. data/ext/oci8/oci8.h +84 -51
  22. data/ext/oci8/oci8lib.c +75 -53
  23. data/ext/oci8/ocidatetime.c +67 -88
  24. data/ext/oci8/ocihandle.c +78 -37
  25. data/ext/oci8/ocinumber.c +166 -109
  26. data/ext/oci8/oraconf.rb +68 -157
  27. data/ext/oci8/oradate.c +2 -7
  28. data/ext/oci8/stmt.c +40 -183
  29. data/ext/oci8/thread_util.c +85 -0
  30. data/ext/oci8/thread_util.h +30 -0
  31. data/lib/oci8.rb.in +19 -13
  32. data/lib/oci8/.document +2 -0
  33. data/lib/oci8/bindtype.rb +62 -45
  34. data/lib/oci8/connection_pool.rb +118 -0
  35. data/lib/oci8/datetime.rb +304 -320
  36. data/lib/oci8/encoding-init.rb +62 -30
  37. data/lib/oci8/encoding.yml +3 -3
  38. data/lib/oci8/metadata.rb +552 -497
  39. data/lib/oci8/object.rb +9 -9
  40. data/lib/oci8/oci8.rb +161 -2
  41. data/lib/oci8/ocihandle.rb +427 -0
  42. data/lib/oci8/properties.rb +31 -1
  43. data/ruby-oci8.gemspec +10 -3
  44. data/test/README +41 -3
  45. data/test/config.rb +16 -0
  46. data/test/test_all.rb +3 -0
  47. data/test/test_bind_string.rb +106 -0
  48. data/test/test_break.rb +33 -7
  49. data/test/test_clob.rb +13 -10
  50. data/test/test_connection_pool.rb +125 -0
  51. data/test/test_connstr.rb +2 -2
  52. data/test/test_datetime.rb +26 -66
  53. data/test/test_encoding.rb +7 -3
  54. data/test/test_error.rb +88 -0
  55. data/test/test_metadata.rb +1356 -204
  56. data/test/test_oci8.rb +27 -8
  57. data/test/test_oranumber.rb +41 -0
  58. metadata +34 -9
  59. data/ext/oci8/xmldb.c +0 -383
@@ -80,15 +80,17 @@ static VALUE oci8_tdo_setup(VALUE self, VALUE svc, VALUE md_obj)
80
80
  OCIObjectUnpin(oci8_envhp, oci8_errhp, tdo->hp.tdo);
81
81
  tdo->hp.tdo = NULL;
82
82
  }
83
- oci_lc(OCIAttrGet(md->hp.ptr, OCI_DTYPE_PARAM, &tdo_ref, NULL, OCI_ATTR_REF_TDO, oci8_errhp));
83
+ chker2(OCIAttrGet(md->hp.ptr, OCI_DTYPE_PARAM, &tdo_ref, NULL, OCI_ATTR_REF_TDO, oci8_errhp),
84
+ &svcctx->base);
84
85
  if (tdo_ref == NULL)
85
86
  return Qnil;
86
- oci_lc(OCIObjectPin_nb(svcctx, oci8_envhp, oci8_errhp, tdo_ref, 0, OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, &tdo->hp.ptr));
87
+ chker2(OCIObjectPin_nb(svcctx, oci8_envhp, oci8_errhp, tdo_ref, 0, OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE, &tdo->hp.ptr),
88
+ &svcctx->base);
87
89
  oci8_link_to_parent(tdo, &svcctx->base);
88
90
  return self;
89
91
  }
90
92
 
91
- static oci8_base_class_t oci8_tdo_class = {
93
+ static oci8_base_vtable_t oci8_tdo_vtable = {
92
94
  oci8_tdo_mark,
93
95
  oci8_tdo_free,
94
96
  sizeof(oci8_base_t)
@@ -233,11 +235,11 @@ static VALUE oci8_named_coll_get_coll_element(VALUE self, VALUE datatype, VALUE
233
235
  if (*ind) {
234
236
  return Qnil;
235
237
  }
236
- oci_lc(OCICollSize(oci8_envhp, oci8_errhp, coll, &size));
238
+ chker2(OCICollSize(oci8_envhp, oci8_errhp, coll, &size), &obj->base);
237
239
  ary = rb_ary_new2(size);
238
240
  for (idx = 0; idx < size; idx++) {
239
241
  boolean exists;
240
- oci_lc(OCICollGetElem(oci8_envhp, oci8_errhp, coll, idx, &exists, &data, (dvoid**)&ind));
242
+ chker2(OCICollGetElem(oci8_envhp, oci8_errhp, coll, idx, &exists, &data, (dvoid**)&ind), &obj->base);
241
243
  if (exists) {
242
244
  void *tmp;
243
245
  if (datatype == INT2FIX(ATTR_NAMED_COLLECTION)) {
@@ -330,11 +332,13 @@ static VALUE oci8_named_coll_set_coll_element(VALUE self, VALUE datatype, VALUE
330
332
  cb_data.coll = (OCIColl*)*obj->instancep;
331
333
  switch (FIX2INT(datatype)) {
332
334
  case ATTR_STRING:
333
- oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_VARCHAR2, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr));
335
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_VARCHAR2, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
336
+ svcctx);
334
337
  cb_data.indp = &cb_data.ind;
335
338
  break;
336
339
  case ATTR_RAW:
337
- oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_RAW, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr));
340
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_RAW, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
341
+ svcctx);
338
342
  cb_data.indp = &cb_data.ind;
339
343
  break;
340
344
  case ATTR_OCINUMBER:
@@ -357,14 +361,18 @@ static VALUE oci8_named_coll_set_coll_element(VALUE self, VALUE datatype, VALUE
357
361
  case ATTR_NAMED_TYPE:
358
362
  Check_Object(typeinfo, cOCI8TDO);
359
363
  tdo = DATA_PTR(typeinfo);
360
- oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_OBJECT, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr));
361
- oci_lc(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp));
364
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_OBJECT, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
365
+ svcctx);
366
+ chker2(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp),
367
+ svcctx);
362
368
  break;
363
369
  case ATTR_NAMED_COLLECTION:
364
370
  Check_Object(typeinfo, cOCI8TDO);
365
371
  tdo = DATA_PTR(typeinfo);
366
- oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_NAMEDCOLLECTION, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr));
367
- oci_lc(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp));
372
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_NAMEDCOLLECTION, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
373
+ svcctx);
374
+ chker2(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp),
375
+ svcctx);
368
376
  break;
369
377
  case ATTR_CLOB:
370
378
  case ATTR_NCLOB:
@@ -381,6 +389,7 @@ static VALUE oci8_named_coll_set_coll_element(VALUE self, VALUE datatype, VALUE
381
389
  set_coll_element_func(&cb_data);
382
390
  set_coll_element_ensure(&cb_data);
383
391
  #endif
392
+ *ind = 0;
384
393
  return Qnil;
385
394
  }
386
395
 
@@ -395,9 +404,9 @@ static VALUE set_coll_element_func(set_coll_element_cb_data_t *cb_data)
395
404
  sb4 idx;
396
405
  void *elem_ptr;
397
406
 
398
- oci_lc(OCICollSize(oci8_envhp, oci8_errhp, coll, &size));
407
+ chkerr(OCICollSize(oci8_envhp, oci8_errhp, coll, &size));
399
408
  if (RARRAY_LEN(val) < size) {
400
- oci_lc(OCICollTrim(oci8_envhp, oci8_errhp, size - RARRAY_LEN(val), coll));
409
+ chkerr(OCICollTrim(oci8_envhp, oci8_errhp, size - RARRAY_LEN(val), coll));
401
410
  }
402
411
  for (idx = 0; idx < RARRAY_LEN(val); idx++) {
403
412
  switch (FIX2INT(datatype)) {
@@ -422,9 +431,9 @@ static VALUE set_coll_element_func(set_coll_element_cb_data_t *cb_data)
422
431
  break;
423
432
  }
424
433
  if (idx < size) {
425
- oci_lc(OCICollAssignElem(oci8_envhp, oci8_errhp, idx, elem_ptr, cb_data->indp, cb_data->coll));
434
+ chkerr(OCICollAssignElem(oci8_envhp, oci8_errhp, idx, elem_ptr, cb_data->indp, cb_data->coll));
426
435
  } else {
427
- oci_lc(OCICollAppend(oci8_envhp, oci8_errhp, elem_ptr, cb_data->indp, coll));
436
+ chkerr(OCICollAppend(oci8_envhp, oci8_errhp, elem_ptr, cb_data->indp, coll));
428
437
  }
429
438
  }
430
439
  return Qnil;
@@ -468,13 +477,13 @@ static void set_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *data
468
477
  switch (FIX2INT(datatype)) {
469
478
  case ATTR_STRING:
470
479
  OCI8StringValue(val);
471
- oci_lc(OCIStringAssignText(oci8_envhp, oci8_errhp,
480
+ chkerr(OCIStringAssignText(oci8_envhp, oci8_errhp,
472
481
  RSTRING_ORATEXT(val), RSTRING_LEN(val),
473
482
  (OCIString **)data));
474
483
  break;
475
484
  case ATTR_RAW:
476
485
  StringValue(val);
477
- oci_lc(OCIRawAssignBytes(oci8_envhp, oci8_errhp,
486
+ chkerr(OCIRawAssignBytes(oci8_envhp, oci8_errhp,
478
487
  RSTRING_ORATEXT(val), RSTRING_LEN(val),
479
488
  (OCIRaw **)data));
480
489
  break;
@@ -536,7 +545,7 @@ static void set_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *data
536
545
  *ind = 0;
537
546
  }
538
547
 
539
- static oci8_base_class_t oci8_named_type_class = {
548
+ static oci8_base_vtable_t oci8_named_type_vtable = {
540
549
  oci8_named_type_mark,
541
550
  oci8_named_type_free,
542
551
  sizeof(oci8_named_type_t)
@@ -624,13 +633,32 @@ static void bind_named_type_init_elem(oci8_bind_t *obind, VALUE svc)
624
633
  obj->null_structp = (char**)&obind->u.null_structs[idx];
625
634
  oci8_link_to_parent(&obj->base, &obind->base);
626
635
 
627
- oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->base.hp.svc, tc, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, (dvoid**)obj->instancep));
628
- oci_lc(OCIObjectGetInd(oci8_envhp, oci8_errhp, (dvoid*)*obj->instancep, (dvoid**)obj->null_structp));
636
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->base.hp.svc, tc, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, (dvoid**)obj->instancep),
637
+ &svcctx->base);
638
+ chker2(OCIObjectGetInd(oci8_envhp, oci8_errhp, (dvoid*)*obj->instancep, (dvoid**)obj->null_structp),
639
+ &svcctx->base);
629
640
  *(OCIInd*)*obj->null_structp = -1;
630
641
  } while (++idx < obind->maxar_sz);
631
642
  }
632
643
 
633
- static const oci8_bind_class_t bind_named_type_class = {
644
+ static void bind_name_type_post_bind_hook(oci8_bind_t *obind)
645
+ {
646
+ oci8_base_t *tdo = DATA_PTR(obind->tdo);
647
+ switch (obind->base.type) {
648
+ case OCI_HTYPE_DEFINE:
649
+ chker2(OCIDefineObject(obind->base.hp.dfn, oci8_errhp, tdo->hp.tdo,
650
+ obind->valuep, 0, obind->u.null_structs, 0),
651
+ &obind->base);
652
+ break;
653
+ case OCI_HTYPE_BIND:
654
+ chker2(OCIBindObject(obind->base.hp.bnd, oci8_errhp, tdo->hp.tdo,
655
+ obind->valuep, 0, obind->u.null_structs, 0),
656
+ &obind->base);
657
+ break;
658
+ }
659
+ }
660
+
661
+ static const oci8_bind_vtable_t bind_named_type_vtable = {
634
662
  {
635
663
  bind_named_type_mark,
636
664
  bind_named_type_free,
@@ -641,9 +669,8 @@ static const oci8_bind_class_t bind_named_type_class = {
641
669
  bind_named_type_init,
642
670
  bind_named_type_init_elem,
643
671
  NULL,
644
- NULL,
645
- NULL,
646
- SQLT_NTY
672
+ SQLT_NTY,
673
+ bind_name_type_post_bind_hook,
647
674
  };
648
675
 
649
676
  void Init_oci_object(VALUE cOCI8)
@@ -652,7 +679,7 @@ void Init_oci_object(VALUE cOCI8)
652
679
  id_set_attributes = rb_intern("attributes=");
653
680
 
654
681
  /* OCI8::TDO */
655
- cOCI8TDO = oci8_define_class_under(cOCI8, "TDO", &oci8_tdo_class);
682
+ cOCI8TDO = oci8_define_class_under(cOCI8, "TDO", &oci8_tdo_vtable);
656
683
  rb_define_private_method(cOCI8TDO, "setup", oci8_tdo_setup, 2);
657
684
  rb_define_const(cOCI8TDO, "ATTR_STRING", INT2FIX(ATTR_STRING));
658
685
  rb_define_const(cOCI8TDO, "ATTR_RAW", INT2FIX(ATTR_RAW));
@@ -681,7 +708,7 @@ void Init_oci_object(VALUE cOCI8)
681
708
  rb_define_const(cOCI8TDO, "ALIGNMENT_OF_DOUBLE", INT2FIX(ALIGNMENT_OF(double)));
682
709
 
683
710
  /* OCI8::NamedType */
684
- cOCI8NamedType = oci8_define_class_under(cOCI8, "NamedType", &oci8_named_type_class);
711
+ cOCI8NamedType = oci8_define_class_under(cOCI8, "NamedType", &oci8_named_type_vtable);
685
712
  rb_define_method(cOCI8NamedType, "initialize", oci8_named_type_initialize, 0);
686
713
  rb_define_method(cOCI8NamedType, "tdo", oci8_named_type_tdo, 0);
687
714
  rb_define_private_method(cOCI8NamedType, "get_attribute", oci8_named_type_get_attribute, 4);
@@ -690,12 +717,12 @@ void Init_oci_object(VALUE cOCI8)
690
717
  rb_define_method(cOCI8NamedType, "null=", oci8_named_type_set_null, 1);
691
718
 
692
719
  /* OCI8::NamedCollection */
693
- cOCI8NamedCollection = oci8_define_class_under(cOCI8, "NamedCollection", &oci8_named_type_class);
720
+ cOCI8NamedCollection = oci8_define_class_under(cOCI8, "NamedCollection", &oci8_named_type_vtable);
694
721
  rb_define_method(cOCI8NamedCollection, "initialize", oci8_named_type_initialize, 0);
695
722
  rb_define_method(cOCI8NamedCollection, "tdo", oci8_named_type_tdo, 0);
696
723
  rb_define_private_method(cOCI8NamedCollection, "get_coll_element", oci8_named_coll_get_coll_element, 2);
697
724
  rb_define_private_method(cOCI8NamedCollection, "set_coll_element", oci8_named_coll_set_coll_element, 3);
698
725
 
699
726
  /* OCI8::BindType::NamedType */
700
- cOCI8BindNamedType = oci8_define_bind_class("NamedType", &bind_named_type_class);
727
+ cOCI8BindNamedType = oci8_define_bind_class("NamedType", &bind_named_type_vtable);
701
728
  }
@@ -2,10 +2,11 @@
2
2
  /*
3
3
  * oci8.c - part of ruby-oci8
4
4
  *
5
- * Copyright (C) 2002-2009 KUBO Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
6
6
  *
7
7
  */
8
8
  #include "oci8.h"
9
+ #include <errno.h>
9
10
  #ifdef HAVE_UNISTD_H
10
11
  #include <unistd.h> /* getpid() */
11
12
  #endif
@@ -30,33 +31,107 @@ extern rb_pid_t rb_w32_getpid(void);
30
31
  #define OCI_ATTR_CLIENT_INFO 368
31
32
  #endif
32
33
 
34
+ #define OCI8_STATE_SESSION_BEGIN_WAS_CALLED 0x01
35
+ #define OCI8_STATE_SERVER_ATTACH_WAS_CALLED 0x02
36
+ #define OCI8_STATE_CPOOL 0x04
37
+
33
38
  static VALUE cOCI8;
39
+ static VALUE cSession;
40
+ static VALUE cServer;
41
+ static ID id_at_session_handle;
42
+ static ID id_at_server_handle;
43
+
44
+ typedef struct oci8_svcctx_associate {
45
+ oci8_base_t base;
46
+ oci8_svcctx_t *svcctx;
47
+ } oci8_svcctx_associate_t;
48
+
49
+ static void oci8_svcctx_associate_free(oci8_base_t *base)
50
+ {
51
+ base->type = 0;
52
+ base->hp.ptr = NULL;
53
+ }
54
+
55
+ static oci8_base_vtable_t oci8_svcctx_associate_vtable = {
56
+ NULL,
57
+ oci8_svcctx_associate_free,
58
+ sizeof(oci8_svcctx_associate_t),
59
+ };
60
+
61
+ static void copy_session_handle(oci8_svcctx_t *svcctx)
62
+ {
63
+ VALUE obj = rb_ivar_get(svcctx->base.self, id_at_session_handle);
64
+ oci8_base_t *base;
65
+
66
+ Check_Handle(obj, cSession, base);
67
+ base->type = OCI_HTYPE_SESSION;
68
+ base->hp.usrhp = svcctx->usrhp;
69
+ }
70
+
71
+ static void copy_server_handle(oci8_svcctx_t *svcctx)
72
+ {
73
+ VALUE obj = rb_ivar_get(svcctx->base.self, id_at_server_handle);
74
+ oci8_base_t *base;
75
+
76
+ Check_Handle(obj, cServer, base);
77
+ base->type = OCI_HTYPE_SERVER;
78
+ base->hp.srvhp = svcctx->srvhp;
79
+ }
34
80
 
35
81
  static void oci8_svcctx_free(oci8_base_t *base)
36
82
  {
37
83
  oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
38
-
39
- if (svcctx->authhp) {
40
- OCIHandleFree(svcctx->authhp, OCI_HTYPE_SESSION);
41
- svcctx->authhp = NULL;
42
- }
43
- if (svcctx->srvhp) {
44
- OCIHandleFree(svcctx->srvhp, OCI_HTYPE_SERVER);
45
- svcctx->srvhp = NULL;
84
+ if (svcctx->logoff_strategy != NULL) {
85
+ const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
86
+ void *data = strategy->prepare(svcctx);
87
+ int rv;
88
+ svcctx->base.type = 0;
89
+ svcctx->logoff_strategy = NULL;
90
+ rv = oci8_run_native_thread(strategy->execute, data);
91
+ if (rv != 0) {
92
+ errno = rv;
93
+ #ifdef WIN32
94
+ rb_sys_fail("_beginthread");
95
+ #else
96
+ rb_sys_fail("pthread_create");
97
+ #endif
98
+ }
46
99
  }
100
+ svcctx->base.type = 0;
47
101
  }
48
102
 
49
- static oci8_base_class_t oci8_svcctx_class = {
103
+ static void oci8_svcctx_init(oci8_base_t *base)
104
+ {
105
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
106
+ VALUE obj;
107
+
108
+ svcctx->executing_thread = Qnil;
109
+ /* set session handle */
110
+ obj = rb_obj_alloc(cSession);
111
+ rb_ivar_set(base->self, id_at_session_handle, obj);
112
+ oci8_link_to_parent(DATA_PTR(obj), base);
113
+ /* set server handle */
114
+ obj = rb_obj_alloc(cServer);
115
+ rb_ivar_set(base->self, id_at_server_handle, obj);
116
+ oci8_link_to_parent(DATA_PTR(obj), base);
117
+
118
+ svcctx->pid = getpid();
119
+ svcctx->is_autocommit = 0;
120
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
121
+ svcctx->non_blocking = 1;
122
+ #endif
123
+ svcctx->long_read_len = INT2FIX(65535);
124
+ }
125
+
126
+ static oci8_base_vtable_t oci8_svcctx_vtable = {
50
127
  NULL,
51
128
  oci8_svcctx_free,
52
- sizeof(oci8_svcctx_t)
129
+ sizeof(oci8_svcctx_t),
130
+ oci8_svcctx_init,
53
131
  };
54
132
 
55
133
  static VALUE oracle_client_vernum; /* Oracle client version number */
56
- static VALUE sym_SYSDBA;
57
- static VALUE sym_SYSOPER;
58
134
  static ID id_at_prefetch_rows;
59
- static ID id_at_username;
60
135
  static ID id_set_prefetch_rows;
61
136
 
62
137
  static VALUE oci8_s_oracle_client_vernum(VALUE klass)
@@ -64,6 +139,27 @@ static VALUE oci8_s_oracle_client_vernum(VALUE klass)
64
139
  return oracle_client_vernum;
65
140
  }
66
141
 
142
+ static VALUE oci8_s_set_property(VALUE klass, VALUE name, VALUE val)
143
+ {
144
+ const char *name_str;
145
+
146
+ Check_Type(name, T_SYMBOL);
147
+ name_str = rb_id2name(SYM2ID(name));
148
+ if (strcmp(name_str, "float_conversion_type") == 0) {
149
+ const char *val_str;
150
+ Check_Type(val, T_SYMBOL);
151
+ val_str = rb_id2name(SYM2ID(val));
152
+ if (strcmp(val_str, "ruby") == 0) {
153
+ oci8_float_conversion_type_is_ruby = 1;
154
+ } else if (strcmp(val_str, "oracle") == 0) {
155
+ oci8_float_conversion_type_is_ruby = 0;
156
+ } else {
157
+ rb_raise(rb_eArgError, "float_conversion_type's value should be either :ruby or :oracle.");
158
+ }
159
+ }
160
+ return Qnil;
161
+ }
162
+
67
163
  /*
68
164
  * call-seq:
69
165
  * OCI8.error_message(message_no) -> string
@@ -87,7 +183,7 @@ static VALUE oci8_s_error_message(VALUE klass, VALUE msgid)
87
183
  }
88
184
 
89
185
  #define CONN_STR_REGEX "/^([^(\\s|\\@)]*)\\/([^(\\s|\\@)]*)(?:\\@(\\S+))?(?:\\s+as\\s+(\\S*)\\s*)?$/i"
90
- static void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode)
186
+ void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode)
91
187
  {
92
188
  static VALUE re = Qnil;
93
189
  if (NIL_P(re)) {
@@ -106,14 +202,7 @@ static void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pas
106
202
  *pass = Qnil;
107
203
  }
108
204
  if (!NIL_P(*mode)) {
109
- char *ptr;
110
- SafeStringValue(*mode);
111
- ptr = RSTRING_PTR(*mode);
112
- if (strcasecmp(ptr, "SYSDBA") == 0) {
113
- *mode = sym_SYSDBA;
114
- } else if (strcasecmp(ptr, "SYSOPER") == 0) {
115
- *mode = sym_SYSOPER;
116
- }
205
+ *mode = ID2SYM(rb_to_id(rb_funcall(*mode, rb_intern("upcase"), 0)));
117
206
  }
118
207
  } else {
119
208
  rb_raise(rb_eArgError, "invalid connect string \"%s\" (expect \"username/password[@(tns_name|//host[:port]/service_name)][ as (sysdba|sysoper)]\"", RSTRING_PTR(conn_str));
@@ -143,184 +232,291 @@ static VALUE oci8_parse_connect_string(VALUE self, VALUE conn_str)
143
232
  return rb_ary_new3(4, user, pass, dbname, mode);
144
233
  }
145
234
 
235
+ /*
236
+ * Logoff strategy for sessions connected by OCILogon.
237
+ */
238
+ typedef struct {
239
+ OCISvcCtx *svchp;
240
+ OCISession *usrhp;
241
+ OCIServer *srvhp;
242
+ } simple_logoff_arg_t;
243
+
244
+ static void *simple_logoff_prepare(oci8_svcctx_t *svcctx)
245
+ {
246
+ simple_logoff_arg_t *sla = xmalloc(sizeof(simple_logoff_arg_t));
247
+ sla->svchp = svcctx->base.hp.svc;
248
+ sla->usrhp = svcctx->usrhp;
249
+ sla->srvhp = svcctx->srvhp;
250
+ svcctx->usrhp = NULL;
251
+ svcctx->srvhp = NULL;
252
+ return sla;
253
+ }
254
+
255
+ static VALUE simple_logoff_execute(void *arg)
256
+ {
257
+ simple_logoff_arg_t *sla = (simple_logoff_arg_t *)arg;
258
+ OCIError *errhp = oci8_errhp;
259
+ sword rv;
260
+
261
+ OCITransRollback(sla->svchp, errhp, OCI_DEFAULT);
262
+ rv = OCILogoff(sla->svchp, errhp);
263
+ xfree(sla);
264
+ return (VALUE)rv;
265
+ }
266
+
267
+ static const oci8_logoff_strategy_t simple_logoff = {
268
+ simple_logoff_prepare,
269
+ simple_logoff_execute,
270
+ };
271
+
272
+ /*
273
+ * Logoff strategy for sessions connected by OCIServerAttach and OCISessionBegin.
274
+ */
275
+
276
+ typedef struct {
277
+ OCISvcCtx *svchp;
278
+ OCISession *usrhp;
279
+ OCIServer *srvhp;
280
+ unsigned char state;
281
+ } complex_logoff_arg_t;
282
+
283
+ static void *complex_logoff_prepare(oci8_svcctx_t *svcctx)
284
+ {
285
+ complex_logoff_arg_t *cla = xmalloc(sizeof(complex_logoff_arg_t));
286
+ cla->svchp = svcctx->base.hp.svc;
287
+ cla->usrhp = svcctx->usrhp;
288
+ cla->srvhp = svcctx->srvhp;
289
+ cla->state = svcctx->state;
290
+ svcctx->usrhp = NULL;
291
+ svcctx->srvhp = NULL;
292
+ svcctx->state = 0;
293
+ return cla;
294
+ }
295
+
296
+ static VALUE complex_logoff_execute(void *arg)
297
+ {
298
+ complex_logoff_arg_t *cla = (complex_logoff_arg_t *)arg;
299
+ OCIError *errhp = oci8_errhp;
300
+ sword rv = OCI_SUCCESS;
301
+
302
+ OCITransRollback(cla->svchp, errhp, OCI_DEFAULT);
303
+
304
+ if (cla->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
305
+ rv = OCISessionEnd(cla->svchp, oci8_errhp, cla->usrhp, OCI_DEFAULT);
306
+ cla->state &= ~OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
307
+ }
308
+ if (cla->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
309
+ rv = OCIServerDetach(cla->srvhp, oci8_errhp, OCI_DEFAULT);
310
+ cla->state &= ~OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
311
+ }
312
+ if (cla->usrhp != NULL) {
313
+ OCIHandleFree(cla->usrhp, OCI_HTYPE_SESSION);
314
+ }
315
+ if (cla->srvhp != NULL) {
316
+ OCIHandleFree(cla->srvhp, OCI_HTYPE_SERVER);
317
+ }
318
+ if (cla->svchp != NULL) {
319
+ OCIHandleFree(cla->svchp, OCI_HTYPE_SVCCTX);
320
+ }
321
+ xfree(cla);
322
+ return (VALUE)rv;
323
+ }
324
+
325
+ static const oci8_logoff_strategy_t complex_logoff = {
326
+ complex_logoff_prepare,
327
+ complex_logoff_execute,
328
+ };
329
+
146
330
  /*
147
331
  * call-seq:
148
- * new(username, password, dbname = nil, privilege = nil)
149
- *
150
- * Connects to an Oracle database server by +username+ and +password+
151
- * at +dbname+ as +privilege+.
152
- *
153
- * === connecting to the local server
154
- *
155
- * Set +username+ and +password+ or pass "username/password" as a
156
- * single argument.
157
- *
158
- * OCI8.new('scott', 'tiger')
159
- * or
160
- * OCI8.new('scott/tiger')
161
- *
162
- * === connecting to a remote server
163
- *
164
- * Set +username+, +password+ and +dbname+ or pass
165
- * "username/password@dbname" as a single argument.
332
+ * logon(username, password, dbname) -> connection
166
333
  *
167
- * OCI8.new('scott', 'tiger', 'orcl.world')
168
- * or
169
- * OCI8.new('scott/tiger@orcl.world')
334
+ * <b>internal use only</b>
170
335
  *
171
- * The +dbname+ is a net service name or an easy connectection
172
- * identifier. The former is a name listed in the file tnsnames.ora.
173
- * Ask to your DBA if you don't know what it is. The latter has the
174
- * syntax as "//host:port/service_name".
175
- *
176
- * OCI8.new('scott', 'tiger', '//remote-host:1521/XE')
177
- * or
178
- * OCI8.new('scott/tiger@//remote-host:1521/XE')
179
- *
180
- * === connecting as a privileged user
181
- *
182
- * Set :SYSDBA or :SYSOPER to +privilege+, otherwise
183
- * "username/password as sysdba" or "username/password as sysoper"
184
- * as a single argument.
336
+ * Creates a simple logon session by the OCI function OCILogon().
337
+ */
338
+ static VALUE oci8_logon(VALUE self, VALUE username, VALUE password, VALUE dbname)
339
+ {
340
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
341
+
342
+ if (svcctx->logoff_strategy != NULL) {
343
+ rb_raise(rb_eRuntimeError, "Could not reuse the session.");
344
+ }
345
+
346
+ /* check arugmnets */
347
+ OCI8SafeStringValue(username);
348
+ OCI8SafeStringValue(password);
349
+ if (!NIL_P(dbname)) {
350
+ OCI8SafeStringValue(dbname);
351
+ }
352
+
353
+ /* logon */
354
+ svcctx->base.type = OCI_HTYPE_SVCCTX;
355
+ chker2(OCILogon_nb(svcctx, oci8_envhp, oci8_errhp, &svcctx->base.hp.svc,
356
+ RSTRING_ORATEXT(username), RSTRING_LEN(username),
357
+ RSTRING_ORATEXT(password), RSTRING_LEN(password),
358
+ NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
359
+ NIL_P(dbname) ? 0 : RSTRING_LEN(dbname)),
360
+ &svcctx->base);
361
+ svcctx->logoff_strategy = &simple_logoff;
362
+
363
+ /* setup the session handle */
364
+ chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->usrhp, 0, OCI_ATTR_SESSION, oci8_errhp),
365
+ &svcctx->base);
366
+ copy_session_handle(svcctx);
367
+
368
+ /* setup the server handle */
369
+ chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp),
370
+ &svcctx->base);
371
+ copy_server_handle(svcctx);
372
+
373
+ return Qnil;
374
+ }
375
+
376
+ /*
377
+ * call-seq:
378
+ * allocate_handles()
185
379
  *
186
- * OCI8.new('sys', 'change_on_install', nil, :SYSDBA)
187
- * or
188
- * OCI8.new('sys/change_on_install as sysdba')
380
+ * <b>internal use only</b>
189
381
  *
190
- * === external OS authentication
382
+ * Allocates a service context handle, a session handle and a
383
+ * server handle to use explicit attach and begin-session calls.
384
+ */
385
+ static VALUE oci8_allocate_handles(VALUE self)
386
+ {
387
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
388
+ sword rv;
389
+
390
+ if (svcctx->logoff_strategy != NULL) {
391
+ rb_raise(rb_eRuntimeError, "Could not reuse the session.");
392
+ }
393
+ svcctx->logoff_strategy = &complex_logoff;
394
+ svcctx->state = 0;
395
+
396
+ /* allocate a service context handle */
397
+ rv = OCIHandleAlloc(oci8_envhp, &svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, 0, 0);
398
+ if (rv != OCI_SUCCESS)
399
+ oci8_env_raise(oci8_envhp, rv);
400
+ svcctx->base.type = OCI_HTYPE_SVCCTX;
401
+
402
+ /* alocalte a session handle */
403
+ rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->usrhp, OCI_HTYPE_SESSION, 0, 0);
404
+ if (rv != OCI_SUCCESS)
405
+ oci8_env_raise(oci8_envhp, rv);
406
+ copy_session_handle(svcctx);
407
+
408
+ /* alocalte a server handle */
409
+ rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0);
410
+ if (rv != OCI_SUCCESS)
411
+ oci8_env_raise(oci8_envhp, rv);
412
+ copy_server_handle(svcctx);
413
+ return self;
414
+ }
415
+
416
+ /*
417
+ * call-seq:
418
+ * session_handle -> a session handle
191
419
  *
192
- * Set nil to +username+ and +password+, or "/" as a single argument.
420
+ * <b>internal use only</b>
193
421
  *
194
- * OCI8.new(nil, nil)
195
- * or
196
- * OCI8.new('/')
422
+ * Returns a session handle associated with the service context handle.
423
+ */
424
+ static VALUE oci8_get_session_handle(VALUE self)
425
+ {
426
+ return rb_ivar_get(self, id_at_session_handle);
427
+ }
428
+
429
+ /*
430
+ * call-seq:
431
+ * server_handle -> a server handle
197
432
  *
198
- * To connect to a remote host:
433
+ * <b>internal use only</b>
199
434
  *
200
- * OCI8.new(nil, nil, 'dbname')
201
- * or
202
- * OCI8.new('/@dbname')
435
+ * Returns a server handle associated with the service context handle.
436
+ */
437
+ static VALUE oci8_get_server_handle(VALUE self)
438
+ {
439
+ return rb_ivar_get(self, id_at_server_handle);
440
+ }
441
+
442
+ /*
443
+ * call-seq:
444
+ * server_attach(dbname, mode)
203
445
  *
204
- * === proxy authentication
446
+ * <b>internal use only</b>
205
447
  *
206
- * Enclose end user's username with square brackets and add it at the
207
- * end of proxy user's username.
448
+ * Attachs to the server by the OCI function OCIServerAttach().
449
+ */
450
+ static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE attach_mode)
451
+ {
452
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
453
+ ub4 mode = NUM2UINT(attach_mode);
454
+
455
+ if (svcctx->logoff_strategy != &complex_logoff) {
456
+ rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle().");
457
+ }
458
+ if (svcctx->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
459
+ rb_raise(rb_eRuntimeError, "Could not use this method twice.");
460
+ }
461
+
462
+ /* check arguments */
463
+ if (!NIL_P(dbname)) {
464
+ OCI8SafeStringValue(dbname);
465
+ }
466
+
467
+ /* attach to the server */
468
+ chker2(OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp,
469
+ NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
470
+ NIL_P(dbname) ? 0 : RSTRING_LEN(dbname),
471
+ mode),
472
+ &svcctx->base);
473
+ chker2(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX,
474
+ svcctx->srvhp, 0, OCI_ATTR_SERVER,
475
+ oci8_errhp),
476
+ &svcctx->base);
477
+ svcctx->state |= OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
478
+ if (mode & OCI_CPOOL) {
479
+ svcctx->state |= OCI8_STATE_CPOOL;
480
+ }
481
+ return self;
482
+ }
483
+
484
+ /*
485
+ * call-seq:
486
+ * session_begin(cred, mode)
208
487
  *
209
- * OCI8.new('proxy_user_name[end_user_name]', 'proxy_password')
210
- * or
211
- * OCI8.new('proxy_user_name[end_user_name]/proxy_password')
488
+ * <b>internal use only</b>
212
489
  *
490
+ * Begins the session by the OCI function OCISessionBegin().
213
491
  */
214
- static VALUE oci8_svcctx_initialize(int argc, VALUE *argv, VALUE self)
492
+ static VALUE oci8_session_begin(VALUE self, VALUE cred, VALUE mode)
215
493
  {
216
- VALUE vusername;
217
- VALUE vpassword;
218
- VALUE vdbname;
219
- VALUE vmode;
220
494
  oci8_svcctx_t *svcctx = DATA_PTR(self);
221
- sword rv;
222
- enum logon_type_t logon_type = T_IMPLICIT;
223
- ub4 cred = OCI_CRED_RDBMS;
224
- ub4 mode = OCI_DEFAULT;
225
- OCISvcCtx *svchp = NULL;
226
495
 
227
- svcctx->executing_thread = Qnil;
228
- if (argc == 1) {
229
- oci8_do_parse_connect_string(argv[0], &vusername, &vpassword, &vdbname, &vmode);
230
- } else {
231
- rb_scan_args(argc, argv, "22", &vusername, &vpassword, &vdbname, &vmode);
496
+ if (svcctx->logoff_strategy != &complex_logoff) {
497
+ rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle().");
232
498
  }
233
-
234
- rb_ivar_set(self, id_at_prefetch_rows, Qnil);
235
- rb_ivar_set(self, id_at_username, Qnil);
236
- if (NIL_P(vusername) && NIL_P(vpassword)) {
237
- /* external credential */
238
- logon_type = T_EXPLICIT;
239
- cred = OCI_CRED_EXT;
240
- } else {
241
- /* RDBMS credential */
242
- OCI8SafeStringValue(vusername); /* 1 */
243
- OCI8SafeStringValue(vpassword); /* 2 */
244
- }
245
- if (!NIL_P(vdbname)) {
246
- OCI8SafeStringValue(vdbname); /* 3 */
247
- }
248
- if (!NIL_P(vmode)) { /* 4 */
249
- logon_type = T_EXPLICIT;
250
- Check_Type(vmode, T_SYMBOL);
251
- if (vmode == sym_SYSDBA) {
252
- mode = OCI_SYSDBA;
253
- } else if (vmode == sym_SYSOPER) {
254
- mode = OCI_SYSOPER;
255
- } else {
256
- rb_raise(rb_eArgError, "invalid privilege name %s (expect :SYSDBA or :SYSOPER)", rb_id2name(SYM2ID(vmode)));
257
- }
499
+ if (svcctx->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
500
+ rb_raise(rb_eRuntimeError, "Could not use this method twice.");
258
501
  }
259
- switch (logon_type) {
260
- case T_IMPLICIT:
261
- rv = OCILogon_nb(svcctx, oci8_envhp, oci8_errhp, &svchp,
262
- RSTRING_ORATEXT(vusername), RSTRING_LEN(vusername),
263
- RSTRING_ORATEXT(vpassword), RSTRING_LEN(vpassword),
264
- NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname),
265
- NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname));
266
- if (IS_OCI_ERROR(rv)) {
267
- oci8_raise(oci8_errhp, rv, NULL);
268
- }
269
- svcctx->base.hp.svc = svchp;
270
- svcctx->base.type = OCI_HTYPE_SVCCTX;
271
- svcctx->logon_type = T_IMPLICIT;
272
- break;
273
- case T_EXPLICIT:
274
- /* allocate OCI handles. */
275
- rv = OCIHandleAlloc(oci8_envhp, &svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, 0, 0);
276
- if (rv != OCI_SUCCESS)
277
- oci8_env_raise(oci8_envhp, rv);
278
- svcctx->base.type = OCI_HTYPE_SVCCTX;
279
- rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->authhp, OCI_HTYPE_SESSION, 0, 0);
280
- if (rv != OCI_SUCCESS)
281
- oci8_env_raise(oci8_envhp, rv);
282
- rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0);
283
- if (rv != OCI_SUCCESS)
284
- oci8_env_raise(oci8_envhp, rv);
285
-
286
- /* set username and password to OCISession. */
287
- if (cred == OCI_CRED_RDBMS) {
288
- oci_lc(OCIAttrSet(svcctx->authhp, OCI_HTYPE_SESSION,
289
- RSTRING_PTR(vusername), RSTRING_LEN(vusername),
290
- OCI_ATTR_USERNAME, oci8_errhp));
291
- oci_lc(OCIAttrSet(svcctx->authhp, OCI_HTYPE_SESSION,
292
- RSTRING_PTR(vpassword), RSTRING_LEN(vpassword),
293
- OCI_ATTR_PASSWORD, oci8_errhp));
294
- }
295
502
 
296
- /* attach to server and set to OCISvcCtx. */
297
- rv = OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp,
298
- NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname),
299
- NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname), OCI_DEFAULT);
300
- if (rv != OCI_SUCCESS)
301
- oci8_raise(oci8_errhp, rv, NULL);
302
- oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp));
303
-
304
- /* begin session. */
305
- rv = OCISessionBegin_nb(svcctx, svcctx->base.hp.ptr, oci8_errhp, svcctx->authhp, cred, mode);
306
- if (rv != OCI_SUCCESS)
307
- oci8_raise(oci8_errhp, rv, NULL);
308
- oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->authhp, 0, OCI_ATTR_SESSION, oci8_errhp));
309
- svcctx->logon_type = T_EXPLICIT;
310
- break;
311
- default:
312
- break;
313
- }
314
- svcctx->pid = getpid();
315
- svcctx->is_autocommit = 0;
316
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
317
- svcctx->non_blocking = 1;
318
- #endif
319
- svcctx->long_read_len = INT2FIX(65535);
503
+ /* check arguments */
504
+ Check_Type(cred, T_FIXNUM);
505
+ Check_Type(mode, T_FIXNUM);
506
+
507
+ /* begin session */
508
+ chker2(OCISessionBegin_nb(svcctx, svcctx->base.hp.ptr, oci8_errhp,
509
+ svcctx->usrhp, FIX2UINT(cred),
510
+ FIX2UINT(mode)),
511
+ &svcctx->base);
512
+ chker2(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX,
513
+ svcctx->usrhp, 0, OCI_ATTR_SESSION,
514
+ oci8_errhp),
515
+ &svcctx->base);
516
+ svcctx->state |= OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
320
517
  return Qnil;
321
518
  }
322
519
 
323
-
324
520
  /*
325
521
  * call-seq:
326
522
  * logoff
@@ -331,54 +527,20 @@ static VALUE oci8_svcctx_initialize(int argc, VALUE *argv, VALUE self)
331
527
  static VALUE oci8_svcctx_logoff(VALUE self)
332
528
  {
333
529
  oci8_svcctx_t *svcctx = (oci8_svcctx_t *)DATA_PTR(self);
334
- sword rv;
335
530
 
336
531
  while (svcctx->base.children != NULL) {
337
532
  oci8_base_free(svcctx->base.children);
338
533
  }
339
- switch (svcctx->logon_type) {
340
- case T_IMPLICIT:
341
- oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
342
- rv = OCILogoff_nb(svcctx, svcctx->base.hp.svc, oci8_errhp);
534
+ if (svcctx->logoff_strategy != NULL) {
535
+ const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
536
+ void *data = strategy->prepare(svcctx);
343
537
  svcctx->base.type = 0;
344
- svcctx->logon_type = T_NOT_LOGIN;
345
- if (rv != OCI_SUCCESS)
346
- oci8_raise(oci8_errhp, rv, NULL);
347
- svcctx->authhp = NULL;
348
- svcctx->srvhp = NULL;
349
- break;
350
- case T_EXPLICIT:
351
- oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
352
- rv = OCISessionEnd_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, svcctx->authhp, OCI_DEFAULT);
353
- if (rv == OCI_SUCCESS) {
354
- rv = OCIServerDetach_nb(svcctx, svcctx->srvhp, oci8_errhp, OCI_DEFAULT);
355
- }
356
- svcctx->logon_type = T_NOT_LOGIN;
357
- if (rv != OCI_SUCCESS)
358
- oci8_raise(oci8_errhp, rv, NULL);
359
- break;
360
- case T_NOT_LOGIN:
361
- break;
538
+ svcctx->logoff_strategy = NULL;
539
+ chker2(oci8_blocking_region(svcctx, strategy->execute, data), &svcctx->base);
362
540
  }
363
541
  return Qtrue;
364
542
  }
365
543
 
366
- /*
367
- * call-seq:
368
- * parse(sql_text) -> an instance of OCI8::Cursor
369
- *
370
- * Prepares the SQL statement and returns a new OCI8::Cursor.
371
- */
372
- static VALUE oci8_svcctx_parse(VALUE self, VALUE sql)
373
- {
374
- VALUE obj = rb_funcall(cOCIStmt, oci8_id_new, 2, self, sql);
375
- VALUE prefetch_rows = rb_ivar_get(self, id_at_prefetch_rows);
376
- if (!NIL_P(prefetch_rows)) {
377
- rb_funcall(obj, id_set_prefetch_rows, 1, prefetch_rows);
378
- }
379
- return obj;
380
- }
381
-
382
544
  /*
383
545
  * call-seq:
384
546
  * commit
@@ -388,7 +550,7 @@ static VALUE oci8_svcctx_parse(VALUE self, VALUE sql)
388
550
  static VALUE oci8_commit(VALUE self)
389
551
  {
390
552
  oci8_svcctx_t *svcctx = DATA_PTR(self);
391
- oci_lc(OCITransCommit_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
553
+ chker2(OCITransCommit_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT), &svcctx->base);
392
554
  return self;
393
555
  }
394
556
 
@@ -401,7 +563,7 @@ static VALUE oci8_commit(VALUE self)
401
563
  static VALUE oci8_rollback(VALUE self)
402
564
  {
403
565
  oci8_svcctx_t *svcctx = DATA_PTR(self);
404
- oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
566
+ chker2(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT), &svcctx->base);
405
567
  return self;
406
568
  }
407
569
 
@@ -422,10 +584,7 @@ static VALUE oci8_non_blocking_p(VALUE self)
422
584
  #else
423
585
  sb1 non_blocking;
424
586
 
425
- if (svcctx->srvhp == NULL) {
426
- oci_lc(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp));
427
- }
428
- oci_lc(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp));
587
+ chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
429
588
  return non_blocking ? Qtrue : Qfalse;
430
589
  #endif
431
590
  }
@@ -475,13 +634,13 @@ static VALUE oci8_set_non_blocking(VALUE self, VALUE val)
475
634
  #else
476
635
  sb1 non_blocking;
477
636
 
478
- if (svcctx->srvhp == NULL) {
479
- oci_lc(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp));
637
+ if (svcctx->state & OCI8_STATE_CPOOL) {
638
+ rb_raise(rb_eRuntimeError, "Could not set non-blocking mode to a connection allocated from OCI8::ConnectionPool.");
480
639
  }
481
- oci_lc(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp));
640
+ chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
482
641
  if ((RTEST(val) && !non_blocking) || (!RTEST(val) && non_blocking)) {
483
642
  /* toggle blocking / non-blocking. */
484
- oci_lc(OCIAttrSet(svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp));
643
+ chker2(OCIAttrSet(svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
485
644
  }
486
645
  #endif
487
646
  return val;
@@ -560,17 +719,12 @@ static VALUE oci8_set_long_read_len(VALUE self, VALUE val)
560
719
  static VALUE oci8_break(VALUE self)
561
720
  {
562
721
  oci8_svcctx_t *svcctx = DATA_PTR(self);
563
- #ifndef HAVE_RB_THREAD_BLOCKING_REGION
564
- sword rv;
565
- #endif
566
722
 
567
723
  if (NIL_P(svcctx->executing_thread)) {
568
724
  return Qfalse;
569
725
  }
570
726
  #ifndef HAVE_RB_THREAD_BLOCKING_REGION
571
- rv = OCIBreak(svcctx->base.hp.ptr, oci8_errhp);
572
- if (rv != OCI_SUCCESS)
573
- oci8_raise(oci8_errhp, rv, NULL);
727
+ chker2(OCIBreak(svcctx->base.hp.ptr, oci8_errhp), &svcctx->base);
574
728
  #endif
575
729
  rb_thread_wakeup(svcctx->executing_thread);
576
730
  return Qtrue;
@@ -608,26 +762,9 @@ static VALUE oci8_oracle_server_vernum(VALUE self)
608
762
  oci8_svcctx_t *svcctx = DATA_PTR(self);
609
763
  char buf[100];
610
764
  ub4 version;
611
- char *p;
612
765
 
613
- if (have_OCIServerRelease) {
614
- /* Oracle 9i or later */
615
- oci_lc(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type, &version));
616
- return UINT2NUM(version);
617
- } else {
618
- /* Oracle 8.x */
619
- oci_lc(OCIServerVersion(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type));
620
- if ((p = strchr(buf, '.')) != NULL) {
621
- unsigned int major, minor, update, patch, port_update;
622
- while (p >= buf && *p != ' ') {
623
- p--;
624
- }
625
- if (sscanf(p + 1, "%u.%u.%u.%u.%u", &major, &minor, &update, &patch, &port_update) == 5) {
626
- return INT2FIX(ORAVERNUM(major, minor, update, patch, port_update));
627
- }
628
- }
629
- return Qnil;
630
- }
766
+ chker2(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type, &version), &svcctx->base);
767
+ return UINT2NUM(version);
631
768
  }
632
769
 
633
770
  /*
@@ -693,9 +830,8 @@ static VALUE oci8_ping(VALUE self)
693
830
  */
694
831
  static VALUE oci8_set_client_identifier(VALUE self, VALUE val)
695
832
  {
696
- char *ptr;
833
+ const char *ptr;
697
834
  ub4 size;
698
- int use_attr_set = 1;
699
835
 
700
836
  if (!NIL_P(val)) {
701
837
  OCI8SafeStringValue(val);
@@ -706,24 +842,19 @@ static VALUE oci8_set_client_identifier(VALUE self, VALUE val)
706
842
  size = 0;
707
843
  }
708
844
 
709
- if (oracle_client_version < ORAVER_9_0) {
710
- use_attr_set = 0;
711
- } else if (oracle_client_version < ORAVERNUM(9, 2, 0, 3, 0) && size == 0) {
712
- /* Workaround for Bug 2449486 */
713
- use_attr_set = 0;
714
- }
715
-
716
- if (use_attr_set) {
845
+ if (oracle_client_version >= ORAVERNUM(9, 2, 0, 3, 0) || size > 0) {
717
846
  if (size > 0 && ptr[0] == ':') {
718
847
  rb_raise(rb_eArgError, "client identifier should not start with ':'.");
719
848
  }
720
- oci_lc(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
721
- size, OCI_ATTR_CLIENT_IDENTIFIER, oci8_errhp));
849
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, (dvoid*)ptr,
850
+ size, OCI_ATTR_CLIENT_IDENTIFIER, oci8_errhp),
851
+ DATA_PTR(self));
722
852
  } else {
853
+ /* Workaround for Bug 2449486 */
723
854
  oci8_exec_sql_var_t bind_vars[1];
724
855
 
725
856
  /* :client_id */
726
- bind_vars[0].valuep = ptr;
857
+ bind_vars[0].valuep = (dvoid*)ptr;
727
858
  bind_vars[0].value_sz = size;
728
859
  bind_vars[0].dty = SQLT_CHR;
729
860
  bind_vars[0].indp = NULL;
@@ -773,7 +904,7 @@ static VALUE oci8_set_client_identifier(VALUE self, VALUE val)
773
904
  */
774
905
  static VALUE oci8_set_module(VALUE self, VALUE val)
775
906
  {
776
- char *ptr;
907
+ const char *ptr;
777
908
  ub4 size;
778
909
 
779
910
  if (!NIL_P(val)) {
@@ -786,14 +917,15 @@ static VALUE oci8_set_module(VALUE self, VALUE val)
786
917
  }
787
918
  if (oracle_client_version >= ORAVER_10_1) {
788
919
  /* Oracle 10g or upper */
789
- oci_lc(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
790
- size, OCI_ATTR_MODULE, oci8_errhp));
920
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, (dvoid*)ptr,
921
+ size, OCI_ATTR_MODULE, oci8_errhp),
922
+ DATA_PTR(self));
791
923
  } else {
792
924
  /* Oracle 9i or lower */
793
925
  oci8_exec_sql_var_t bind_vars[1];
794
926
 
795
927
  /* :module */
796
- bind_vars[0].valuep = ptr;
928
+ bind_vars[0].valuep = (dvoid*)ptr;
797
929
  bind_vars[0].value_sz = size;
798
930
  bind_vars[0].dty = SQLT_CHR;
799
931
  bind_vars[0].indp = NULL;
@@ -842,7 +974,7 @@ static VALUE oci8_set_module(VALUE self, VALUE val)
842
974
  */
843
975
  static VALUE oci8_set_action(VALUE self, VALUE val)
844
976
  {
845
- char *ptr;
977
+ const char *ptr;
846
978
  ub4 size;
847
979
 
848
980
  if (!NIL_P(val)) {
@@ -855,14 +987,15 @@ static VALUE oci8_set_action(VALUE self, VALUE val)
855
987
  }
856
988
  if (oracle_client_version >= ORAVER_10_1) {
857
989
  /* Oracle 10g or upper */
858
- oci_lc(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
859
- size, OCI_ATTR_ACTION, oci8_errhp));
990
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, (dvoid*)ptr,
991
+ size, OCI_ATTR_ACTION, oci8_errhp),
992
+ DATA_PTR(self));
860
993
  } else {
861
994
  /* Oracle 9i or lower */
862
995
  oci8_exec_sql_var_t bind_vars[1];
863
996
 
864
997
  /* :action */
865
- bind_vars[0].valuep = ptr;
998
+ bind_vars[0].valuep = (dvoid*)ptr;
866
999
  bind_vars[0].value_sz = size;
867
1000
  bind_vars[0].dty = SQLT_CHR;
868
1001
  bind_vars[0].indp = NULL;
@@ -904,7 +1037,7 @@ static VALUE oci8_set_action(VALUE self, VALUE val)
904
1037
  */
905
1038
  static VALUE oci8_set_client_info(VALUE self, VALUE val)
906
1039
  {
907
- char *ptr;
1040
+ const char *ptr;
908
1041
  ub4 size;
909
1042
 
910
1043
  if (!NIL_P(val)) {
@@ -917,14 +1050,15 @@ static VALUE oci8_set_client_info(VALUE self, VALUE val)
917
1050
  }
918
1051
  if (oracle_client_version >= ORAVER_10_1) {
919
1052
  /* Oracle 10g or upper */
920
- oci_lc(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
921
- size, OCI_ATTR_CLIENT_INFO, oci8_errhp));
1053
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, (dvoid*)ptr,
1054
+ size, OCI_ATTR_CLIENT_INFO, oci8_errhp),
1055
+ DATA_PTR(self));
922
1056
  } else {
923
1057
  /* Oracle 9i or lower */
924
1058
  oci8_exec_sql_var_t bind_vars[1];
925
1059
 
926
1060
  /* :client_info */
927
- bind_vars[0].valuep = ptr;
1061
+ bind_vars[0].valuep = (dvoid*)ptr;
928
1062
  bind_vars[0].value_sz = size;
929
1063
  bind_vars[0].dty = SQLT_CHR;
930
1064
  bind_vars[0].indp = NULL;
@@ -941,14 +1075,14 @@ static VALUE oci8_set_client_info(VALUE self, VALUE val)
941
1075
  VALUE Init_oci8(void)
942
1076
  {
943
1077
  #if 0
944
- /*
945
- * OCIHandle is the abstract base class for all OCI handles and
946
- * descriptors which are opaque data types of Oracle Call Interface.
947
- */
948
1078
  oci8_cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
949
1079
  cOCI8 = rb_define_class("OCI8", oci8_cOCIHandle);
950
1080
  #endif
951
- cOCI8 = oci8_define_class("OCI8", &oci8_svcctx_class);
1081
+ cOCI8 = oci8_define_class("OCI8", &oci8_svcctx_vtable);
1082
+ cSession = oci8_define_class_under(cOCI8, "Session", &oci8_svcctx_associate_vtable);
1083
+ cServer = oci8_define_class_under(cOCI8, "Server", &oci8_svcctx_associate_vtable);
1084
+ id_at_session_handle = rb_intern("@session_handle");
1085
+ id_at_server_handle = rb_intern("@server_handle");
952
1086
 
953
1087
  oracle_client_vernum = INT2FIX(oracle_client_version);
954
1088
  if (have_OCIClientVersion) {
@@ -957,20 +1091,21 @@ VALUE Init_oci8(void)
957
1091
  oracle_client_vernum = INT2FIX(ORAVERNUM(major, minor, update, patch, port_update));
958
1092
  }
959
1093
 
960
- sym_SYSDBA = ID2SYM(rb_intern("SYSDBA"));
961
- sym_SYSOPER = ID2SYM(rb_intern("SYSOPER"));
962
1094
  id_at_prefetch_rows = rb_intern("@prefetch_rows");
963
- id_at_username = rb_intern("@username");
964
1095
  id_set_prefetch_rows = rb_intern("prefetch_rows=");
965
1096
 
1097
+ rb_define_const(cOCI8, "VERSION", rb_obj_freeze(rb_usascii_str_new_cstr(OCI8LIB_VERSION)));
966
1098
  rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0);
967
- if (have_OCIMessageOpen && have_OCIMessageGet) {
968
- rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
969
- }
1099
+ rb_define_singleton_method_nodoc(cOCI8, "__set_property", oci8_s_set_property, 2);
1100
+ rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
970
1101
  rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
971
- rb_define_method(cOCI8, "initialize", oci8_svcctx_initialize, -1);
1102
+ rb_define_private_method(cOCI8, "logon", oci8_logon, 3);
1103
+ rb_define_private_method(cOCI8, "allocate_handles", oci8_allocate_handles, 0);
1104
+ rb_define_private_method(cOCI8, "session_handle", oci8_get_session_handle, 0);
1105
+ rb_define_private_method(cOCI8, "server_handle", oci8_get_server_handle, 0);
1106
+ rb_define_private_method(cOCI8, "server_attach", oci8_server_attach, 2);
1107
+ rb_define_private_method(cOCI8, "session_begin", oci8_session_begin, 2);
972
1108
  rb_define_method(cOCI8, "logoff", oci8_svcctx_logoff, 0);
973
- rb_define_method(cOCI8, "parse", oci8_svcctx_parse, 1);
974
1109
  rb_define_method(cOCI8, "commit", oci8_commit, 0);
975
1110
  rb_define_method(cOCI8, "rollback", oci8_rollback, 0);
976
1111
  rb_define_method(cOCI8, "non_blocking?", oci8_non_blocking_p, 0);
@@ -987,6 +1122,7 @@ VALUE Init_oci8(void)
987
1122
  rb_define_method(cOCI8, "module=", oci8_set_module, 1);
988
1123
  rb_define_method(cOCI8, "action=", oci8_set_action, 1);
989
1124
  rb_define_method(cOCI8, "client_info=", oci8_set_client_info, 1);
1125
+ rb_define_attr(cOCI8, "last_error", 1, 1);
990
1126
  return cOCI8;
991
1127
  }
992
1128
 
@@ -1004,11 +1140,7 @@ OCISvcCtx *oci8_get_oci_svcctx(VALUE obj)
1004
1140
  OCISession *oci8_get_oci_session(VALUE obj)
1005
1141
  {
1006
1142
  oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
1007
-
1008
- if (svcctx->authhp == NULL) {
1009
- oci_lc(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->authhp, 0, OCI_ATTR_SESSION, oci8_errhp));
1010
- }
1011
- return svcctx->authhp;
1143
+ return svcctx->usrhp;
1012
1144
  }
1013
1145
 
1014
1146
  void oci8_check_pid_consistency(oci8_svcctx_t *svcctx)