ruby-oci8 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@
3
3
  * attr.c
4
4
  *
5
5
  * $Author: kubo $
6
- * $Date: 2009-01-12 00:11:09 +0900 (Mon, 12 Jan 2009) $
6
+ * $Date: 2009-05-17 22:07:16 +0900 (Sun, 17 May 2009) $
7
7
  *
8
8
  * Copyright (C) 2002-2007 KUBO Takehiro <kubo@jiubao.org>
9
9
  */
@@ -106,7 +106,8 @@ static VALUE get_rowid_attr(rowid_arg_t *arg)
106
106
  * Oracle Server.
107
107
  */
108
108
  oci8_base_t *svc;
109
- oci8_exec_sql_var_t bind_vars[2];
109
+ oci8_exec_sql_var_t define_var;
110
+ oci8_exec_sql_var_t bind_var;
110
111
 
111
112
  /* search a connection from the handle */
112
113
  svc = base;
@@ -117,19 +118,19 @@ static VALUE get_rowid_attr(rowid_arg_t *arg)
117
118
  }
118
119
  }
119
120
  /* :strval */
120
- bind_vars[0].valuep = buf;
121
- bind_vars[0].value_sz = sizeof(buf);
122
- bind_vars[0].dty = SQLT_CHR;
123
- bind_vars[0].indp = NULL;
124
- bind_vars[0].alenp = &buflen;
121
+ define_var.valuep = buf;
122
+ define_var.value_sz = sizeof(buf);
123
+ define_var.dty = SQLT_CHR;
124
+ define_var.indp = NULL;
125
+ define_var.alenp = &buflen;
125
126
  /* :rowid */
126
- bind_vars[1].valuep = &arg->ridp;
127
- bind_vars[1].value_sz = sizeof(void *);
128
- bind_vars[1].dty = SQLT_RDD;
129
- bind_vars[1].indp = NULL;
130
- bind_vars[1].alenp = NULL;
127
+ bind_var.valuep = &arg->ridp;
128
+ bind_var.value_sz = sizeof(void *);
129
+ bind_var.dty = SQLT_RDD;
130
+ bind_var.indp = NULL;
131
+ bind_var.alenp = NULL;
131
132
  /* convert the rowid descriptor to a string value by querying Oracle server. */
132
- oci8_exec_sql((oci8_svcctx_t*)svc, "BEGIN :strval := :rowid; END;", 0, NULL, 2, bind_vars, 1);
133
+ oci8_exec_sql((oci8_svcctx_t*)svc, "SELECT :rid FROM dual", 1, &define_var, 1, &bind_var, 1);
133
134
  if (buflen == 0) {
134
135
  return Qnil;
135
136
  }
@@ -3,7 +3,7 @@
3
3
  * bind.c
4
4
  *
5
5
  * $Author: kubo $
6
- * $Date: 2009-02-10 22:50:40 +0900 (Tue, 10 Feb 2009) $
6
+ * $Date: 2009-05-17 22:07:16 +0900 (Sun, 17 May 2009) $
7
7
  *
8
8
  * Copyright (C) 2002-2008 KUBO Takehiro <kubo@jiubao.org>
9
9
  */
@@ -46,7 +46,7 @@ static void bind_string_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE len
46
46
  } else {
47
47
  sz = NUM2INT(length);
48
48
  }
49
- if (sz <= 0) {
49
+ if (sz < 0) {
50
50
  rb_raise(rb_eArgError, "invalid bind length %d", sz);
51
51
  }
52
52
  sz += sizeof(sb4);
@@ -284,8 +284,8 @@ static VALUE bind_float_get(oci8_bind_t *obind, void *data, void *null_struct)
284
284
 
285
285
  static void bind_float_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
286
286
  {
287
- Check_Type(val, T_FLOAT);
288
- *(double*)data = RFLOAT_VALUE(val);
287
+ /* val is converted to Float if it isn't Float. */
288
+ *(double*)data = RFLOAT_VALUE(rb_Float(val));
289
289
  }
290
290
 
291
291
  static void bind_float_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
@@ -45,7 +45,7 @@ VALUE oci8_charset_id2name(VALUE svc, VALUE csid)
45
45
  char buf[OCI_NLS_MAXBUFSZ];
46
46
  sword rv;
47
47
 
48
- rv = OCINlsCharSetIdToName(oci8_envhp, TO_ORATEXT(buf), sizeof(buf), FIX2INT(csid));
48
+ rv = OCINlsCharSetIdToName(oci8_envhp, TO_ORATEXT(buf), sizeof(buf), (ub2)FIX2INT(csid));
49
49
  if (rv != OCI_SUCCESS) {
50
50
  return Qnil;
51
51
  }
@@ -1,10 +1,9 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
- env.c - part of ruby-oci8
4
-
5
- Copyright (C) 2002-2008 KUBO Takehiro <kubo@jiubao.org>
6
-
7
- */
3
+ * env.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2002-2009 KUBO Takehiro <kubo@jiubao.org>
6
+ */
8
7
  #include "oci8.h"
9
8
 
10
9
  #if !defined(RUBY_VM)
@@ -12,7 +11,37 @@
12
11
  #include <util.h>
13
12
  #endif
14
13
 
15
- OCIEnv *oci8_envhp;
14
+ #ifdef _WIN32
15
+ #ifdef HAVE_RUBY_WIN32_H
16
+ #include <ruby/win32.h> /* for rb_w32_getenv() */
17
+ #else
18
+ #include <win32/win32.h> /* for rb_w32_getenv() */
19
+ #endif
20
+ #endif
21
+
22
+ #ifdef HAVE_RUBY_UTIL_H
23
+ #include <ruby/util.h>
24
+ #endif
25
+
26
+ #ifdef RUBY_VM
27
+ ub4 oci8_env_mode = OCI_OBJECT | OCI_THREADED;
28
+ #else
29
+ ub4 oci8_env_mode = OCI_OBJECT;
30
+ #endif
31
+
32
+ OCIEnv *oci8_global_envhp;
33
+
34
+ OCIEnv *oci8_make_envhp(void)
35
+ {
36
+ sword rv;
37
+
38
+ rv = OCIEnvCreate(&oci8_global_envhp, oci8_env_mode, NULL, NULL, NULL, NULL, 0, NULL);
39
+ if (rv != OCI_SUCCESS) {
40
+ oci8_raise_init_error();
41
+ }
42
+ return oci8_global_envhp;
43
+ }
44
+
16
45
  #ifdef RUBY_VM
17
46
  /*
18
47
  * oci8_errhp is a thread local object in ruby 1.9.
@@ -53,17 +82,23 @@ OCIError *oci8_make_errhp(void)
53
82
  /*
54
83
  * oci8_errhp is global in ruby 1.8.
55
84
  */
56
- OCIError *oci8_errhp;
85
+ OCIError *oci8_global_errhp;
86
+
87
+ OCIError *oci8_make_errhp(void)
88
+ {
89
+ sword rv;
90
+
91
+ rv = OCIHandleAlloc(oci8_envhp, (dvoid *)&oci8_global_errhp, OCI_HTYPE_ERROR, 0, NULL);
92
+ if (rv != OCI_SUCCESS)
93
+ oci8_env_raise(oci8_envhp, rv);
94
+ return oci8_global_errhp;
95
+ }
57
96
  #endif
58
97
 
59
98
  void Init_oci8_env(void)
60
99
  {
61
- sword rv;
62
100
  #ifdef RUBY_VM
63
- ub4 mode = OCI_OBJECT | OCI_THREADED;
64
101
  int error;
65
- #else
66
- ub4 mode = OCI_OBJECT;
67
102
  #endif
68
103
 
69
104
  #if !defined(RUBY_VM) && !defined(_WIN32)
@@ -85,23 +120,38 @@ void Init_oci8_env(void)
85
120
  }
86
121
  }
87
122
  #endif /* WIN32 */
88
- rv = OCIInitialize(mode, NULL, NULL, NULL, NULL);
89
- if (rv != OCI_SUCCESS) {
90
- oci8_raise_init_error();
91
- }
92
- rv = OCIEnvInit(&oci8_envhp, OCI_DEFAULT, 0, NULL);
93
- if (rv != OCI_SUCCESS) {
94
- oci8_raise_init_error();
123
+
124
+ /* workaround code.
125
+ *
126
+ * When ORACLE_HOME ends with '/' and the Oracle client is
127
+ * an instant client lower than 10.2.0.3, OCIEvnCreate()
128
+ * doesn't work even though the combination of OCIInitialize()
129
+ * and OCIEnvInit() works fine. Delete the last slash for
130
+ * a workaround.
131
+ */
132
+ if (oracle_client_version < ORAVERNUM(10, 2, 0, 3, 0)) {
133
+ #ifdef _WIN32
134
+ #define DIR_SEP '\\'
135
+ #else
136
+ #define DIR_SEP '/'
137
+ #endif
138
+ char *home = getenv("ORACLE_HOME");
139
+ if (home != NULL) {
140
+ size_t homelen = strlen(home);
141
+ if (homelen > 0 && home[homelen - 1] == DIR_SEP) {
142
+ home = ruby_strdup(home);
143
+ home[homelen - 1] = '\0';
144
+ ruby_setenv("ORACLE_HOME", home);
145
+ xfree(home);
146
+ }
147
+ }
95
148
  }
149
+
96
150
  #ifdef RUBY_VM
97
151
  id_thread_key = rb_intern("__oci8_errhp__");
98
152
  error = oci8_tls_key_init(&oci8_tls_key);
99
153
  if (error != 0) {
100
154
  rb_raise(rb_eRuntimeError, "Cannot create thread local key (errno = %d)", error);
101
155
  }
102
- #else /* RUBY_VM */
103
- rv = OCIHandleAlloc(oci8_envhp, (dvoid *)&oci8_errhp, OCI_HTYPE_ERROR, 0, NULL);
104
- if (rv != OCI_SUCCESS)
105
- oci8_env_raise(oci8_envhp, rv);
106
156
  #endif
107
157
  }
@@ -157,7 +157,7 @@ static void set_backtrace_and_raise(VALUE exc, const char *file, int line)
157
157
  #endif
158
158
  backtrace = rb_funcall(rb_cObject, oci8_id_caller, 0);
159
159
  if (TYPE(backtrace) == T_ARRAY) {
160
- snprintf(errmsg, sizeof(errmsg), "%s:%d:in oci8lib.so", file, line);
160
+ snprintf(errmsg, sizeof(errmsg), "%s:%d:in " STRINGIZE(oci8lib) DLEXT, file, line);
161
161
  errmsg[sizeof(errmsg) - 1] = '\0';
162
162
  rb_ary_unshift(backtrace, rb_usascii_str_new_cstr(errmsg));
163
163
  rb_funcall(exc, oci8_id_set_backtrace, 1, backtrace);
@@ -61,7 +61,13 @@ funcs.keys.sort.each do |version|
61
61
  puts "checking for Oracle #{verstr} API - #{result}"
62
62
  break if result == 'fail'
63
63
  end
64
- $defs << "-DACTUAL_ORACLE_CLIENT_VERSION=#{format('0x%08x', oci_actual_client_version)}"
64
+
65
+ have_type('oratext', 'ociap.h')
66
+ have_type('OCIDateTime*', 'ociap.h')
67
+ have_type('OCIInterval*', 'ociap.h')
68
+ have_type('OCICallbackLobRead2', 'ociap.h')
69
+ have_type('OCICallbackLobWrite2', 'ociap.h')
70
+ have_type('OCIAdmin*', 'ociap.h')
65
71
 
66
72
  if with_config('oracle-version')
67
73
  oci_client_version = with_config('oracle-version').to_i
@@ -97,7 +103,6 @@ have_func("localtime_r")
97
103
  have_header("intern.h")
98
104
  have_header("util.h")
99
105
  # ruby 1.9 headers
100
- have_header("ruby/util.h")
101
106
  have_type('rb_encoding', ['ruby/ruby.h', 'ruby/encoding.h'])
102
107
 
103
108
  # $! in C API
@@ -122,6 +127,7 @@ else
122
127
  raise 'unsupported ruby version: ' + RUBY_VERSION
123
128
  end
124
129
  $defs << "-DInit_oci8lib=Init_#{so_basename}"
130
+ $defs << "-Doci8lib=#{so_basename}"
125
131
 
126
132
  create_header()
127
133
 
@@ -26,6 +26,7 @@ typedef struct {
26
26
  ub4 pos;
27
27
  int char_width;
28
28
  ub1 csfrm;
29
+ ub1 lobtype;
29
30
  enum state state;
30
31
  } oci8_lob_t;
31
32
 
@@ -149,6 +150,7 @@ static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm
149
150
  lob->pos = 0;
150
151
  lob->char_width = 1;
151
152
  lob->csfrm = csfrm;
153
+ lob->lobtype = lobtype;
152
154
  lob->state = S_NO_OPEN_CLOSE;
153
155
  oci8_link_to_parent((oci8_base_t*)lob, (oci8_base_t*)DATA_PTR(svc));
154
156
  if (!NIL_P(val)) {
@@ -360,8 +362,14 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
360
362
  }
361
363
  v = rb_ary_join(v, Qnil);
362
364
  OBJ_TAINT(v);
363
- rb_enc_associate(v, oci8_encoding);
364
- return rb_str_conv_enc(v, oci8_encoding, rb_default_internal_encoding());
365
+ if (lob->lobtype == OCI_TEMP_CLOB) {
366
+ /* set encoding */
367
+ rb_enc_associate(v, oci8_encoding);
368
+ return rb_str_conv_enc(v, oci8_encoding, rb_default_internal_encoding());
369
+ } else {
370
+ /* ASCII-8BIT */
371
+ return v;
372
+ }
365
373
  }
366
374
 
367
375
  static VALUE oci8_lob_write(VALUE self, VALUE data)
@@ -371,7 +379,11 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
371
379
  ub4 amt;
372
380
 
373
381
  lob_open(lob);
374
- OCI8StringValue(data);
382
+ if (lob->lobtype == OCI_TEMP_CLOB) {
383
+ OCI8StringValue(data);
384
+ } else {
385
+ StringValue(data);
386
+ }
375
387
  amt = RSTRING_LEN(data);
376
388
  oci_lc(OCILobWrite_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, RSTRING_PTR(data), amt, OCI_ONE_PIECE, NULL, NULL, 0, lob->csfrm));
377
389
  lob->pos += amt;
@@ -483,9 +495,15 @@ static void oci8_bfile_set_name(VALUE self, VALUE dir_alias, VALUE filename)
483
495
  oci8_lob_t *lob = DATA_PTR(self);
484
496
 
485
497
  bfile_close(lob);
498
+ if (RSTRING_LEN(dir_alias) > UB2MAXVAL) {
499
+ rb_raise(rb_eRuntimeError, "dir_alias is too long.");
500
+ }
501
+ if (RSTRING_LEN(filename) > UB2MAXVAL) {
502
+ rb_raise(rb_eRuntimeError, "filename is too long.");
503
+ }
486
504
  oci_lc(OCILobFileSetName(oci8_envhp, oci8_errhp, &lob->base.hp.lob,
487
- RSTRING_ORATEXT(dir_alias), RSTRING_LEN(dir_alias),
488
- RSTRING_ORATEXT(filename), RSTRING_LEN(filename)));
505
+ RSTRING_ORATEXT(dir_alias), (ub2)RSTRING_LEN(dir_alias),
506
+ RSTRING_ORATEXT(filename), (ub2)RSTRING_LEN(filename)));
489
507
  }
490
508
 
491
509
  static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
@@ -503,6 +521,7 @@ static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
503
521
  lob->pos = 0;
504
522
  lob->char_width = 1;
505
523
  lob->csfrm = SQLCS_IMPLICIT;
524
+ lob->lobtype = OCI_TEMP_BLOB;
506
525
  lob->state = S_BFILE_CLOSE;
507
526
  if (argc != 1) {
508
527
  OCI8SafeStringValue(dir_alias);
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * metadata.c
4
4
  *
5
- * Copyright (C) 2006-2007 KUBO Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2006-2009 KUBO Takehiro <kubo@jiubao.org>
6
6
  *
7
7
  * implement private methods of classes in OCI8::Metadata module.
8
8
  *
@@ -210,7 +210,7 @@ static VALUE metadata_get_oraint(VALUE self, VALUE idx)
210
210
  memset(&on, 0, sizeof(on));
211
211
  on.OCINumberPart[0] = size;
212
212
  memcpy(&on.OCINumberPart[1], value, size);
213
- return oci8_make_integer(&on);
213
+ return oci8_make_integer(&on, oci8_errhp);
214
214
  }
215
215
 
216
216
  static VALUE metadata_get_param(VALUE self, VALUE idx)
@@ -277,7 +277,7 @@ static VALUE oci8_do_describe(VALUE self, void *objptr, ub4 objlen, ub1 objtype,
277
277
  oci_lc(OCIAttrSet(desc->hp.dschp, OCI_HTYPE_DESCRIBE, &val, 0, OCI_ATTR_DESC_PUBLIC, oci8_errhp));
278
278
  }
279
279
  oci_lc(OCIDescribeAny_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, objptr, objlen,
280
- objtype, OCI_DEFAULT, FIX2INT(type), desc->hp.dschp));
280
+ objtype, OCI_DEFAULT, (ub1)FIX2INT(type), desc->hp.dschp));
281
281
  oci_lc(OCIAttrGet(desc->hp.dschp, OCI_HTYPE_DESCRIBE, &parmhp, 0, OCI_ATTR_PARAM, oci8_errhp));
282
282
  return oci8_metadata_create(parmhp, self, obj);
283
283
  }
@@ -1,5 +1,10 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
+ * Copyright (C) 2002-2009 KUBO Takehiro <kubo@jiubao.org>
4
+ */
5
+
6
+ /*
7
+ *
3
8
  * Document-class: OCI8::TDO
4
9
  *
5
10
  * OCI8::TDO is the class for Type Descriptor Object, which describe
@@ -157,11 +162,11 @@ static VALUE get_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *dat
157
162
  return rb_str_new(TO_CHARPTR(OCIRawPtr(oci8_envhp, *(OCIRaw **)data)),
158
163
  OCIRawSize(oci8_envhp, *(OCIRaw **)data));
159
164
  case ATTR_OCINUMBER:
160
- return oci8_make_ocinumber((OCINumber *)data);
165
+ return oci8_make_ocinumber((OCINumber *)data, oci8_errhp);
161
166
  case ATTR_FLOAT:
162
- return oci8_make_float((OCINumber *)data);
167
+ return oci8_make_float((OCINumber *)data, oci8_errhp);
163
168
  case ATTR_INTEGER:
164
- return oci8_make_integer((OCINumber *)data);
169
+ return oci8_make_integer((OCINumber *)data, oci8_errhp);
165
170
  case ATTR_BINARY_DOUBLE:
166
171
  return rb_float_new(*(double*)data);
167
172
  case ATTR_BINARY_FLOAT:
@@ -431,10 +436,10 @@ static void set_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *data
431
436
  break;
432
437
  case ATTR_OCINUMBER:
433
438
  case ATTR_FLOAT:
434
- oci8_set_ocinumber((OCINumber*)data, val);
439
+ oci8_set_ocinumber((OCINumber*)data, val, oci8_errhp);
435
440
  break;
436
441
  case ATTR_INTEGER:
437
- oci8_set_integer((OCINumber*)data, val);
442
+ oci8_set_integer((OCINumber*)data, val, oci8_errhp);
438
443
  break;
439
444
  case ATTR_BINARY_DOUBLE:
440
445
  *(double*)data = NUM2DBL(val);
@@ -17,6 +17,10 @@ extern rb_pid_t rb_w32_getpid(void);
17
17
  #endif
18
18
  #endif
19
19
 
20
+ #ifndef OCI_ATTR_CLIENT_IDENTIFIER
21
+ #define OCI_ATTR_CLIENT_IDENTIFIER 278
22
+ #endif
23
+
20
24
  /*
21
25
  * Document-class: OCI8
22
26
  *
@@ -538,11 +542,11 @@ static VALUE oci8_oracle_server_vernum(VALUE self)
538
542
 
539
543
  if (have_OCIServerRelease) {
540
544
  /* Oracle 9i or later */
541
- oci_lc(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), svcctx->base.type, &version));
545
+ oci_lc(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type, &version));
542
546
  return UINT2NUM(version);
543
547
  } else {
544
548
  /* Oracle 8.x */
545
- oci_lc(OCIServerVersion(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), svcctx->base.type));
549
+ oci_lc(OCIServerVersion(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type));
546
550
  if ((p = strchr(buf, '.')) != NULL) {
547
551
  unsigned int major, minor, update, patch, port_update;
548
552
  while (p >= buf && *p != ' ') {
@@ -556,6 +560,85 @@ static VALUE oci8_oracle_server_vernum(VALUE self)
556
560
  }
557
561
  }
558
562
 
563
+ /*
564
+ * call-seq:
565
+ * ping -> true or false
566
+ *
567
+ * Verifies that the Oracle connection is alive.
568
+ *
569
+ * OCI8#ping also can be used to flush all the pending OCI client-side calls
570
+ * to the server if any exist. See: OCI8#client_identifier=.
571
+ *
572
+ * For Oracle 10.2 client or upper, a dummy round trip call is made by a newly
573
+ * added OCI function in Oracle 10.2.
574
+ *
575
+ * For Oracle 10.1 client or lower, a simple PL/SQL block "BEGIN NULL; END;"
576
+ * is executed to make a round trip call.
577
+ */
578
+ static VALUE oci8_ping(VALUE self)
579
+ {
580
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
581
+ sword rv;
582
+
583
+ if (have_OCIPing_nb) {
584
+ /* Oracle 10.2 or upper */
585
+ rv = OCIPing_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT);
586
+ } else {
587
+ /* Oracle 10.1 or lower */
588
+ rv = oci8_exec_sql(svcctx, "BEGIN NULL; END;", 0U, NULL, 0U, NULL, 0);
589
+ }
590
+ return rv == OCI_SUCCESS ? Qtrue : FALSE;
591
+ }
592
+
593
+ /*
594
+ * call-seq:
595
+ * client_identifier = string
596
+ *
597
+ * Sets the CLIENT_IDENTIFIER column in the V$SESSION dictionary view.
598
+ * This can be up to 64 bytes long. The first character should not be ':'.
599
+ *
600
+ * If the Oracle client is 9i or upper, the change is not reflected to the
601
+ * server immediately. It is postponed until the next round trip call for
602
+ * example OCI8#exec, OCI8#ping, etc.
603
+ *
604
+ * This call is equivalent to "DBMS_SESSION.SET_IDENTIFIER(client_id VARCHAR2);"
605
+ * and available when the server is Oracle 9i or upper.
606
+ */
607
+ static VALUE oci8_set_client_identifier(VALUE self, VALUE val)
608
+ {
609
+ OCISession *sess = oci8_get_oci_session(self);
610
+ char *ptr;
611
+ ub4 size;
612
+
613
+ if (!NIL_P(val)) {
614
+ OCI8SafeStringValue(val);
615
+ ptr = RSTRING_PTR(val);
616
+ size = RSTRING_LEN(val);
617
+ } else {
618
+ ptr = "";
619
+ size = 0;
620
+ }
621
+ if (oracle_client_version >= 900) {
622
+ if (size > 0 && ptr[0] == ':') {
623
+ rb_raise(rb_eArgError, "client identifier should not start with ':'.");
624
+ }
625
+ oci_lc(OCIAttrSet(sess, OCI_HTYPE_SESSION, ptr,
626
+ size, OCI_ATTR_CLIENT_IDENTIFIER, oci8_errhp));
627
+ } else {
628
+ oci8_exec_sql_var_t bind_vars[1];
629
+
630
+ /* :client_id */
631
+ bind_vars[0].valuep = ptr;
632
+ bind_vars[0].value_sz = size;
633
+ bind_vars[0].dty = SQLT_CHR;
634
+ bind_vars[0].indp = NULL;
635
+ bind_vars[0].alenp = NULL;
636
+
637
+ oci8_exec_sql(oci8_get_svcctx(self), "BEGIN DBMS_SESSION.SET_IDENTIFIER(:client_id); END;", 0, NULL, 1, bind_vars, 1);
638
+ }
639
+ return val;
640
+ }
641
+
559
642
  VALUE Init_oci8(void)
560
643
  {
561
644
  cOCI8 = oci8_define_class("OCI8", &oci8_svcctx_class);
@@ -589,6 +672,8 @@ VALUE Init_oci8(void)
589
672
  rb_define_method(cOCI8, "break", oci8_break, 0);
590
673
  rb_define_method(cOCI8, "prefetch_rows=", oci8_set_prefetch_rows, 1);
591
674
  rb_define_private_method(cOCI8, "oracle_server_vernum", oci8_oracle_server_vernum, 0);
675
+ rb_define_method(cOCI8, "ping", oci8_ping, 0);
676
+ rb_define_method(cOCI8, "client_identifier=", oci8_set_client_identifier, 1);
592
677
  return cOCI8;
593
678
  }
594
679