ruby-oci8 2.0.6 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)