ruby-oci8 2.1.3 → 2.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,53 @@
1
+ 2013-01-06 KUBO Takehiro <kubo@jiubao.org>
2
+ * NEWS: add changes between 2.1.4 and 2.1.3
3
+ * VERSION: change the version to 2.1.4.
4
+ * docs/platform-specific-issues.md: update solaris-specific document.
5
+ * ext/oci8/connection_pool.c, ext/oci8/encoding.c, ext/oci8/metadata.c,
6
+ ext/oci8/oci8.c,lib/oci8.rb.in, lib/oci8/metadata.rb, lib/oci8/oci8.rb,
7
+ lib/oci8/oracle_version.rb, lib/oci8/properties.rb: update comments for yard.
8
+ * test/test_clob.rb: change a lob size when ORA-24817 is raised to
9
+ pass tests on Windows.
10
+
11
+ 2013-01-03 KUBO Takehiro <kubo@jiubao.org>
12
+ * ext/oci8/oci8.c, lib/oci8/properties.rb: add OCI8.properties[:events_mode]
13
+ to support Fast Application Notification (FAN).
14
+
15
+ 2013-01-03 KUBO Takehiro <kubo@jiubao.org>
16
+ * ext/oci8/extconf.rb, lib/oci8.rb.in: add languange mode to the extension
17
+ library name when ths ruby engine is rubinius and explicitly claim that
18
+ jruby is not supported when it is jruby.
19
+
20
+ 2013-01-03 KUBO Takehiro <kubo@jiubao.org>
21
+ * ext/oci8/encoding.c, lib/oci8/encoding-init.rb: delete an internal method
22
+ OCI8.nls_ratio= when the ruby is 1.9 or greater. nls_ratio is set by
23
+ OCI8.encoding=.
24
+
25
+ 2012-12-23 KUBO Takehiro <kubo@jiubao.org>
26
+ * ext/oci8/lob.c, ext/oci8/oci8.h, ext/oci8/oci8lib.c, test/test_clob.rb:
27
+ fix SEGV when a temporary LOB is freed when OCILobRead returns OCI_NEED_DATA.
28
+ (github issue #20 reported by Edgars Beigarts)
29
+
30
+ 2012-12-18 KUBO Takehiro <kubo@jiubao.org>
31
+ * ext/oci8/error.c, lib/oci8/oci8.rb: change the OCIError constructor to
32
+ accept an Oracle error code as the first parameter and create a message
33
+ which depends on NLS_LANG.
34
+ * lib/oci8/metadata.rb: fix OCI8.describe_table not to follow synonyms
35
+ until stack overflow. Now the recursive level is limited to 20.
36
+ (github issue #26 reported by Brian Henderson)
37
+
38
+ 2012-12-16 KUBO Takehiro <kubo@jiubao.org>
39
+ * ext/oci8/extconf.rb, lib/oci8.rb.in: use RUBY_VERSION instead of
40
+ RbConfig::CONFIG['ruby_version'] to know the ruby ABI version.
41
+ The latter may be changed by the configure option --with-ruby-version.
42
+ (github issue #24 reported by suhrawardi)
43
+
44
+ 2012-12-03 KUBO Takehiro <kubo@jiubao.org>
45
+ * ext/oci8/oraconf.rb: add a script encoding magic comment for ruby 2.0.0 preview2.
46
+ (github issue #25 reported by aboltart)
47
+
48
+ 2012-12-02 KUBO Takehiro <kubo@jiubao.org>
49
+ * test/test_encoding.rb: fix to pass tests with ruby 2.0.0 preview2.
50
+
1
51
  2012-11-11 KUBO Takehiro <kubo@jiubao.org>
2
52
  * ext/oci8/lob.c: use OCILobLocatorAssign_nb (non-blocking version)
3
53
  instead of OCILobLocatorAssign (blocking version).
data/NEWS CHANGED
@@ -1,5 +1,46 @@
1
1
  # @markup markdown
2
2
 
3
+ 2.1.4
4
+ =====
5
+
6
+ New Features
7
+ ------------
8
+
9
+ ### Fast Application Notification (FAN) support
10
+
11
+ Look at {http://php.net/manual/en/oci8.connection.php} to know what is FAN.
12
+ [oci8.events](http://php.net/manual/en/oci8.configuration.php#ini.oci8.events) in PHP
13
+ corresponds to {OCI8.properties OCI8.properties[:events_mode]} in ruby-oci8.
14
+
15
+ Note: You need to set `OCI8.properties[:events_mode]` after `"require 'oci8'"` and before
16
+ any methods which call Oracle OCI functions.
17
+
18
+ Fixed Issues
19
+ ------------
20
+
21
+ - fix SEGV when a temporary LOB is freed when `OCILobRead` returns `OCI_NEED_DATA`.
22
+ See: [github issue #20](https://github.com/kubo/ruby-oci8/issues/20)
23
+
24
+ (reported by Edgars Beigarts)
25
+
26
+ - use `RUBY_VERSION` instead of `RbConfig::CONFIG['ruby_version']` to know the
27
+ ruby ABI version. The latter may be changed by the configure option
28
+ --with-ruby-version.
29
+ See: [github issue #24](https://github.com/kubo/ruby-oci8/issues/24)
30
+
31
+ (reported by suhrawardi)
32
+
33
+ - add a script encoding magic comment for ruby 2.0.0 preview2.
34
+ See: [github issue #25](https://github.com/kubo/ruby-oci8/issues/25)
35
+
36
+ (reported by aboltart)
37
+
38
+ - fix {OCI8#describe_table} not to follow synonyms until stack overflow.
39
+ Now the recursive level is limited to 20.
40
+ See: [github issue #26](https://github.com/kubo/ruby-oci8/issues/26)
41
+
42
+ (reported by Brian Henderson)
43
+
3
44
  2.1.3
4
45
  =====
5
46
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.3
1
+ 2.1.4
@@ -71,15 +71,23 @@ Solaris
71
71
  =======
72
72
 
73
73
  You need a same compiler which is used to make ruby itself.
74
-
75
- There are two ruby packages.
76
-
77
- * [Sunfreeware.com](http://www.sunfreeware.com/)
78
- * [Blastwave.org](http://www.blastwave.org/)
79
-
80
- The former is compiled by gcc. The latter is compiled by
81
- [Sun Studio](http://developers.sun.com/sunstudio/).
82
- The both compilers are freely available.
74
+ For example, if the ruby is compiled by gcc, you need gcc. If it is compiled by Oracle Solaris Studio
75
+ (formerly called as Sun Studio), you need Oracle Solaris Studio.
76
+
77
+ If ruby is compiled by gcc and "require 'oci8'" raises "OCI Library Initialization Error",
78
+ you may need to recompile ruby as follows:
79
+
80
+ $ bzip2 -dc ruby-1.9.3-pxxx.tar.bz2 | tar xvf -
81
+ $ cd ruby-1.9.3-pxxx
82
+ $ vi main.c # <- Add RUBY_FUNC_EXPORTED just before "int main(..)" as follows:
83
+ -------------
84
+ RUBY_FUNC_EXPORTED /* Add this line */
85
+ int
86
+ main(int argc, char **argv)
87
+ -------------
88
+ $ ./configure
89
+ $ make
90
+ $ make install
83
91
 
84
92
  If you use Blastwave.org's ruby and want not to install Sun Studio,
85
93
  you can edit rbconfig.rb by your self. [(look at here)](http://forum.textdrive.com/viewtopic.php?id=12630)
@@ -91,8 +99,8 @@ If you use Sunfreeware.com's ruby and
91
99
  prints "yes", you may need to edit rbconfig.rb distributed with the ruby
92
100
  as follows:
93
101
 
94
- from: CONFIG["LDFLAGS"] = "-L. -Wl,-E"
95
- to: CONFIG["LDFLAGS"] = "-L. "
102
+ from: CONFIG["LDFLAGS"] = "-L. -Wl,-E"
103
+ to: CONFIG["LDFLAGS"] = "-L. "
96
104
 
97
105
  FreeBSD
98
106
  =======
@@ -174,9 +174,9 @@ static VALUE oci8_cpool_reinitialize(VALUE self, VALUE conn_min, VALUE conn_max,
174
174
  * call-seq:
175
175
  * pool_name -> string
176
176
  *
177
- * <b>internal use only</b>
178
- *
179
177
  * Retruns the pool name.
178
+ *
179
+ * @private
180
180
  */
181
181
  static VALUE oci8_cpool_pool_name(VALUE self)
182
182
  {
@@ -185,12 +185,14 @@ static VALUE oci8_charset_name2id(VALUE svc, VALUE name)
185
185
  *
186
186
  * @return [Fixnum] NLS ratio
187
187
  * @since 2.1.0
188
+ * @private
188
189
  */
189
190
  static VALUE oci8_get_nls_ratio(VALUE klass)
190
191
  {
191
192
  return INT2NUM(oci8_nls_ratio);
192
193
  }
193
194
 
195
+ #ifndef HAVE_TYPE_RB_ENCODING
194
196
  /*
195
197
  * call-seq:
196
198
  * OCI8.nls_ratio = integer
@@ -201,6 +203,8 @@ static VALUE oci8_get_nls_ratio(VALUE klass)
201
203
  *
202
204
  * @param [Fixnum] integer NLS ratio
203
205
  * @since 2.1.0
206
+ * @private
207
+ * @note ruby 1.8 only
204
208
  */
205
209
  static VALUE oci8_set_nls_ratio(VALUE klass, VALUE val)
206
210
  {
@@ -211,6 +215,7 @@ static VALUE oci8_set_nls_ratio(VALUE klass, VALUE val)
211
215
  oci8_nls_ratio = v;
212
216
  return val;
213
217
  }
218
+ #endif
214
219
 
215
220
  #ifdef HAVE_TYPE_RB_ENCODING
216
221
 
@@ -224,6 +229,7 @@ static VALUE oci8_set_nls_ratio(VALUE klass, VALUE val)
224
229
  * are passed to Oracle, they are converted to +OCI8.encoding+
225
230
  * in advance.
226
231
  *
232
+ * @example
227
233
  * # When OCI8.encoding is ISO-8859-1,
228
234
  * conn.exec('insert into country_code values(:1, :2, :3)',
229
235
  * 'AT', 'Austria', "\u00d6sterreichs")
@@ -243,6 +249,8 @@ static VALUE oci8_set_nls_ratio(VALUE klass, VALUE val)
243
249
  *
244
250
  * @return [Encoding]
245
251
  * @since 2.0.0 and ruby 1.9
252
+ * @private
253
+ * @see OCI8.client_charset_name
246
254
  */
247
255
  static VALUE oci8_get_encoding(VALUE klass)
248
256
  {
@@ -259,13 +267,16 @@ static VALUE oci8_get_encoding(VALUE klass)
259
267
  *
260
268
  * @param [Encoding] enc
261
269
  * @since 2.0.0 and ruby 1.9
270
+ * @private
262
271
  */
263
272
  static VALUE oci8_set_encoding(VALUE klass, VALUE encoding)
264
273
  {
265
274
  if (NIL_P(encoding)) {
266
275
  oci8_encoding = NULL;
276
+ oci8_nls_ratio = 1;
267
277
  } else {
268
278
  oci8_encoding = rb_to_encoding(encoding);
279
+ oci8_nls_ratio = rb_enc_mbmaxlen(oci8_encoding);
269
280
  }
270
281
  return encoding;
271
282
  }
@@ -287,7 +298,9 @@ void Init_oci8_encoding(VALUE cOCI8)
287
298
  rb_define_method(cOCI8, "charset_name2id", oci8_charset_name2id, 1);
288
299
  rb_define_method(cOCI8, "charset_id2name", oci8_charset_id2name, 1);
289
300
  rb_define_singleton_method(cOCI8, "nls_ratio", oci8_get_nls_ratio, 0);
301
+ #ifndef HAVE_TYPE_RB_ENCODING
290
302
  rb_define_singleton_method(cOCI8, "nls_ratio=", oci8_set_nls_ratio, 1);
303
+ #endif
291
304
  #ifdef HAVE_TYPE_RB_ENCODING
292
305
  rb_define_singleton_method(cOCI8, "encoding", oci8_get_encoding, 0);
293
306
  rb_define_singleton_method(cOCI8, "encoding=", oci8_set_encoding, 1);
@@ -160,31 +160,6 @@ static VALUE set_backtrace(VALUE exc, const char *file, int line)
160
160
  return exc;
161
161
  }
162
162
 
163
- /*
164
- * call-seq:
165
- * initialize(message, code = nil, sql = nil, parse_error_offset = nil)
166
- *
167
- * Creates a new OCIError object.
168
- *
169
- * @example
170
- * OCIError.new("ORA-00001: unique constraint (%s.%s) violated", 1)
171
- * # => #<OCIError: ORA-00001: unique constraint (%s.%s) violated>
172
- */
173
- static VALUE oci8_error_initialize(int argc, VALUE *argv, VALUE self)
174
- {
175
- VALUE msg;
176
- VALUE code;
177
- VALUE sql;
178
- VALUE parse_error_offset;
179
-
180
- rb_scan_args(argc, argv, "04", &msg, &code, &sql, &parse_error_offset);
181
- rb_call_super(argc > 1 ? 1 : argc, argv);
182
- rb_ivar_set(self, oci8_id_at_code, code);
183
- rb_ivar_set(self, oci8_id_at_sql, sql);
184
- rb_ivar_set(self, oci8_id_at_parse_error_offset, parse_error_offset);
185
- return Qnil;
186
- }
187
-
188
163
  sb4 oci8_get_error_code(OCIError *errhp)
189
164
  {
190
165
  sb4 errcode = -1;
@@ -214,8 +189,6 @@ void Init_oci8_error(void)
214
189
  eOCIContinue = rb_define_class("OCIContinue", eOCIException);
215
190
  eOCISuccessWithInfo = rb_define_class("OCISuccessWithInfo", eOCIError);
216
191
 
217
- rb_define_method(eOCIError, "initialize", oci8_error_initialize, -1);
218
-
219
192
  /*
220
193
  * @attr_reader [Integer] code error code
221
194
  */
@@ -134,14 +134,57 @@ replace_keyword(File.dirname(__FILE__) + '/../../lib/oci8.rb.in', '../../lib/oci
134
134
  ruby_engine = (defined? RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
135
135
 
136
136
  so_basename = 'oci8lib_'
137
- if ruby_engine == 'ruby'
138
- # Config::CONFIG["ruby_version"] indicates the ruby API version.
139
- # 1.8 - ruby 1.8.x
140
- # 1.9.1 - ruby 1.9.1, 1.9.2
141
- # 2.0.0 - ruby 2.0.0
142
- so_basename += RbConfig::CONFIG["ruby_version"].gsub(/\W/, '')
137
+ case ruby_engine
138
+ when 'ruby'
139
+ # The extension library name includes the ruby ABI (application binary interface)
140
+ # version. It is for binary gems which contain more than one extension library
141
+ # and use correct one depending on the ABI version.
142
+ #
143
+ # ruby version | ABI version
144
+ # --------------+--------------
145
+ # 1.8.6 | 1.8
146
+ # 1.8.7 | 1.8
147
+ # --------------+--------------
148
+ # 1.9.0 | 1.9.0
149
+ # 1.9.1 | 1.9.1
150
+ # 1.9.2 | 1.9.1
151
+ # 1.9.3 | 1.9.1
152
+ # --------------+--------------
153
+ # 2.0.0 | 2.0.0
154
+ # 2.0.1 | 2.0.1 (See: [ruby-core:49578])
155
+ # ... | ...
156
+ #
157
+ # Note: The ruby ABI version is same with RbConfig::CONFIG['ruby_version']
158
+ # if it wasn't explicitly changed by the configure option --with-ruby-version.
159
+ #
160
+ case RUBY_VERSION
161
+ when /^2\.0/
162
+ so_basename += RUBY_VERSION.gsub(/\W/, '')
163
+ when /^1\.9\.0/
164
+ raise 'unsupported ruby version: 1.9.0'
165
+ when /^1\.9/
166
+ so_basename += '191'
167
+ when /^1\.8/
168
+ so_basename += '18'
169
+ else
170
+ raise 'unsupported ruby version: ' + RUBY_VERSION
171
+ end
172
+ when 'rbx'
173
+ # "rbx -X18" and "rbx -X19" use different C header files.
174
+ case RUBY_VERSION
175
+ when /^2\.0/
176
+ so_basename += 'rbx20'
177
+ when /^1\.9/
178
+ so_basename += 'rbx19'
179
+ when /^1\.8/
180
+ so_basename += 'rbx18'
181
+ else
182
+ raise 'unsupported language mode: ' + RUBY_VERSION
183
+ end
184
+ when 'jruby'
185
+ raise "Ruby-oci8 doesn't support jruby because its C extension support is in development in jruby 1.6 and deprecated in jruby 1.7."
143
186
  else
144
- so_basename += ruby_engine
187
+ raise 'unsupported ruby engine: ' + RUBY_ENGINE
145
188
  end
146
189
 
147
190
  $defs << "-DInit_oci8lib=Init_#{so_basename}"
@@ -554,12 +554,24 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
554
554
  /* initialize buf in zeros everytime to check a nul characters. */
555
555
  memset(buf, 0, sizeof(buf));
556
556
  rv = OCILobRead_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, buf, sizeof(buf), NULL, NULL, 0, lob->csfrm);
557
- if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22289) {
558
- /* ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB */
559
- if (lob->state == S_BFILE_CLOSE)
560
- continue;
561
- }
562
- if (rv != OCI_SUCCESS && rv != OCI_NEED_DATA) {
557
+ svcctx->suppress_free_temp_lobs = 0;
558
+ switch (rv) {
559
+ case OCI_SUCCESS:
560
+ break;
561
+ case OCI_NEED_DATA:
562
+ /* prevent OCILobFreeTemporary() from being called.
563
+ * See: https://github.com/kubo/ruby-oci8/issues/20
564
+ */
565
+ svcctx->suppress_free_temp_lobs = 1;
566
+ break;
567
+ case OCI_ERROR:
568
+ if (oci8_get_error_code(oci8_errhp) == 22289) {
569
+ /* ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB */
570
+ if (lob->state == S_BFILE_CLOSE)
571
+ continue;
572
+ }
573
+ /* FALLTHROUGH */
574
+ default:
563
575
  chker2(rv, &svcctx->base);
564
576
  }
565
577
 
@@ -159,6 +159,19 @@ static VALUE oci8_do_describe(VALUE self, void *objptr, ub4 objlen, ub1 objtype,
159
159
  return oci8_metadata_create(parmhp, self, obj);
160
160
  }
161
161
 
162
+ /*
163
+ * call-seq:
164
+ * __describe(name, klass, check_public)
165
+ *
166
+ * @param [String] name object name
167
+ * @param [subclass of OCI8::Metadata::Base] klass
168
+ * @param [Boolean] check_public +true+ to look up the object as a public synonym when
169
+ * the object does not exist in the current schema and
170
+ * the name includes no dots.
171
+ * @return [subclass of OCI8::Metadata::Base]
172
+ *
173
+ * @private
174
+ */
162
175
  static VALUE oci8_describe(VALUE self, VALUE name, VALUE klass, VALUE check_public)
163
176
  {
164
177
  OCI8SafeStringValue(name);
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * oci8.c - part of ruby-oci8
4
4
  *
5
- * Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2002-2013 KUBO Takehiro <kubo@jiubao.org>
6
6
  *
7
7
  */
8
8
  #include "oci8.h"
@@ -171,25 +171,56 @@ static VALUE oci8_s_oracle_client_vernum(VALUE klass)
171
171
  return oracle_client_vernum;
172
172
  }
173
173
 
174
- static VALUE oci8_s_set_property(VALUE klass, VALUE name, VALUE val)
174
+ /*
175
+ * call-seq:
176
+ * OCI8.__get_prop(key)
177
+ *
178
+ * @param [Fixnum] key 1 or 2
179
+ *
180
+ * @private
181
+ */
182
+ static VALUE oci8_s_get_prop(VALUE klass, VALUE key)
175
183
  {
176
- const char *name_str;
177
-
178
- Check_Type(name, T_SYMBOL);
179
- name_str = rb_id2name(SYM2ID(name));
180
- if (strcmp(name_str, "float_conversion_type") == 0) {
181
- const char *val_str;
182
- Check_Type(val, T_SYMBOL);
183
- val_str = rb_id2name(SYM2ID(val));
184
- if (strcmp(val_str, "ruby") == 0) {
185
- oci8_float_conversion_type_is_ruby = 1;
186
- } else if (strcmp(val_str, "oracle") == 0) {
187
- oci8_float_conversion_type_is_ruby = 0;
188
- } else {
189
- rb_raise(rb_eArgError, "float_conversion_type's value should be either :ruby or :oracle.");
184
+ switch (NUM2INT(key)) {
185
+ case 1:
186
+ return oci8_float_conversion_type_is_ruby ? Qtrue : Qfalse;
187
+ case 2:
188
+ return UINT2NUM(oci8_env_mode);
189
+ default:
190
+ rb_raise(rb_eArgError, "Unknown prop %d", NUM2INT(key));
191
+ }
192
+ }
193
+
194
+
195
+ /*
196
+ * call-seq:
197
+ * OCI8.__set_prop(key, value)
198
+ *
199
+ * @param [Fixnum] key 1 or 2
200
+ * @param [Object] value depends on +key+.
201
+ *
202
+ * @private
203
+ */
204
+ static VALUE oci8_s_set_prop(VALUE klass, VALUE key, VALUE val)
205
+ {
206
+ switch (NUM2INT(key)) {
207
+ case 1:
208
+ oci8_float_conversion_type_is_ruby = RTEST(val) ? 1 : 0;
209
+ break;
210
+ case 2:
211
+ /*
212
+ * Changes the OCI environment mode which will be passed to the second
213
+ * argument of the OCI function OCIEnvCreate.
214
+ */
215
+ if (oci8_global_envhp != NULL) {
216
+ rb_raise(rb_eRuntimeError, "The OCI Environment has been alreadly initialized. It cannot be changed after even one OCI function is called.");
190
217
  }
218
+ oci8_env_mode = NUM2UINT(val);
219
+ break;
220
+ default:
221
+ rb_raise(rb_eArgError, "Unknown prop %d", NUM2INT(key));
191
222
  }
192
- return Qnil;
223
+ return klass;
193
224
  }
194
225
 
195
226
  /*
@@ -254,6 +285,7 @@ void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALU
254
285
  * "scott/tiger@oradb.example.com" -> ["scott", "tiger", "oradb.example.com", nil]
255
286
  * "sys/change_on_install as sysdba" -> ["sys", "change_on_install", nil, :SYSDBA]
256
287
  *
288
+ * @private
257
289
  */
258
290
  static VALUE oci8_parse_connect_string(VALUE self, VALUE conn_str)
259
291
  {
@@ -365,9 +397,9 @@ static const oci8_logoff_strategy_t complex_logoff = {
365
397
  * call-seq:
366
398
  * logon2(username, password, dbname, mode) -> connection
367
399
  *
368
- * <b>internal use only</b>
369
- *
370
400
  * Creates a simple logon session by the OCI function OCILogon2().
401
+ *
402
+ * @private
371
403
  */
372
404
  static VALUE oci8_logon2(VALUE self, VALUE username, VALUE password, VALUE dbname, VALUE mode)
373
405
  {
@@ -417,10 +449,10 @@ static VALUE oci8_logon2(VALUE self, VALUE username, VALUE password, VALUE dbnam
417
449
  * call-seq:
418
450
  * allocate_handles()
419
451
  *
420
- * <b>internal use only</b>
421
- *
422
452
  * Allocates a service context handle, a session handle and a
423
453
  * server handle to use explicit attach and begin-session calls.
454
+ *
455
+ * @private
424
456
  */
425
457
  static VALUE oci8_allocate_handles(VALUE self)
426
458
  {
@@ -457,9 +489,9 @@ static VALUE oci8_allocate_handles(VALUE self)
457
489
  * call-seq:
458
490
  * server_attach(dbname, mode)
459
491
  *
460
- * <b>internal use only</b>
461
- *
462
492
  * Attachs to the server by the OCI function OCIServerAttach().
493
+ *
494
+ * @private
463
495
  */
464
496
  static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE attach_mode)
465
497
  {
@@ -499,9 +531,9 @@ static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE attach_mode)
499
531
  * call-seq:
500
532
  * session_begin(cred, mode)
501
533
  *
502
- * <b>internal use only</b>
503
- *
504
534
  * Begins the session by the OCI function OCISessionBegin().
535
+ *
536
+ * @private
505
537
  */
506
538
  static VALUE oci8_session_begin(VALUE self, VALUE cred, VALUE mode)
507
539
  {
@@ -767,9 +799,9 @@ static VALUE oci8_set_prefetch_rows(VALUE self, VALUE val)
767
799
  *
768
800
  * Returns a numerical format of the Oracle server version.
769
801
  *
770
- * See also: #oracle_server_version
771
- *
802
+ * @see OCI8#oracle_server_version
772
803
  * @since 2.0.1
804
+ * @private
773
805
  */
774
806
  static VALUE oci8_oracle_server_vernum(VALUE self)
775
807
  {
@@ -1121,7 +1153,8 @@ void Init_oci8(VALUE *out)
1121
1153
 
1122
1154
  rb_define_const(cOCI8, "VERSION", rb_obj_freeze(rb_usascii_str_new_cstr(OCI8LIB_VERSION)));
1123
1155
  rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0);
1124
- rb_define_singleton_method_nodoc(cOCI8, "__set_property", oci8_s_set_property, 2);
1156
+ rb_define_singleton_method(cOCI8, "__get_prop", oci8_s_get_prop, 1);
1157
+ rb_define_singleton_method(cOCI8, "__set_prop", oci8_s_set_prop, 2);
1125
1158
  rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
1126
1159
  rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
1127
1160
  rb_define_private_method(cOCI8, "logon2", oci8_logon2, 4);
@@ -1145,7 +1178,6 @@ void Init_oci8(VALUE *out)
1145
1178
  rb_define_method(cOCI8, "module=", oci8_set_module, 1);
1146
1179
  rb_define_method(cOCI8, "action=", oci8_set_action, 1);
1147
1180
  rb_define_method(cOCI8, "client_info=", oci8_set_client_info, 1);
1148
- rb_define_attr(cOCI8, "last_error", 1, 1);
1149
1181
  *out = cOCI8;
1150
1182
  }
1151
1183
 
@@ -361,6 +361,7 @@ typedef struct oci8_svcctx {
361
361
  rb_pid_t pid;
362
362
  unsigned char state;
363
363
  char is_autocommit;
364
+ char suppress_free_temp_lobs;
364
365
  #ifdef NATIVE_THREAD_WITH_GVL
365
366
  char non_blocking;
366
367
  #endif
@@ -229,44 +229,45 @@ static void *free_temp_lob(void *user_data)
229
229
  /* ruby 1.9 */
230
230
  sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data)
231
231
  {
232
- oci8_temp_lob_t *lob;
233
232
  OCIError *errhp = oci8_errhp;
234
233
 
235
234
  if (!NIL_P(svcctx->executing_thread)) {
236
235
  rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
237
236
  }
238
237
 
239
- lob = svcctx->temp_lobs;
240
- while (lob != NULL) {
241
- oci8_temp_lob_t *lob_next = lob->next;
238
+ if (!svcctx->suppress_free_temp_lobs) {
239
+ oci8_temp_lob_t *lob = svcctx->temp_lobs;
240
+ while (lob != NULL) {
241
+ oci8_temp_lob_t *lob_next = lob->next;
242
242
 
243
- if (svcctx->non_blocking) {
244
- free_temp_lob_arg_t arg;
245
- sword rv;
243
+ if (svcctx->non_blocking) {
244
+ free_temp_lob_arg_t arg;
245
+ sword rv;
246
246
 
247
- arg.svcctx = svcctx;
248
- arg.svchp = svcctx->base.hp.svc;
249
- arg.errhp = errhp;
250
- arg.lob = lob->lob;
247
+ arg.svcctx = svcctx;
248
+ arg.svchp = svcctx->base.hp.svc;
249
+ arg.errhp = errhp;
250
+ arg.lob = lob->lob;
251
251
 
252
- svcctx->executing_thread = rb_thread_current();
252
+ svcctx->executing_thread = rb_thread_current();
253
253
  #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
254
- rv = (sword)(VALUE)rb_thread_call_without_gvl(free_temp_lob, &arg, oci8_unblock_func, svcctx);
254
+ rv = (sword)(VALUE)rb_thread_call_without_gvl(free_temp_lob, &arg, oci8_unblock_func, svcctx);
255
255
  #else
256
- rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))free_temp_lob, &arg, oci8_unblock_func, svcctx);
256
+ rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))free_temp_lob, &arg, oci8_unblock_func, svcctx);
257
257
  #endif
258
- if (rv == OCI_ERROR) {
259
- if (oci8_get_error_code(errhp) == 1013) {
260
- rb_raise(eOCIBreak, "Canceled by user request.");
258
+ if (rv == OCI_ERROR) {
259
+ if (oci8_get_error_code(errhp) == 1013) {
260
+ rb_raise(eOCIBreak, "Canceled by user request.");
261
+ }
261
262
  }
263
+ } else {
264
+ OCILobFreeTemporary(svcctx->base.hp.svc, errhp, lob->lob);
262
265
  }
263
- } else {
264
- OCILobFreeTemporary(svcctx->base.hp.svc, errhp, lob->lob);
265
- }
266
- OCIDescriptorFree(lob->lob, OCI_DTYPE_LOB);
266
+ OCIDescriptorFree(lob->lob, OCI_DTYPE_LOB);
267
267
 
268
- xfree(lob);
269
- svcctx->temp_lobs = lob = lob_next;
268
+ xfree(lob);
269
+ svcctx->temp_lobs = lob = lob_next;
270
+ }
270
271
  }
271
272
 
272
273
  if (svcctx->non_blocking) {
@@ -1,3 +1,4 @@
1
+ # coding: ascii
1
2
  require 'mkmf'
2
3
 
3
4
  # compatibility for ruby-1.9
@@ -26,14 +26,34 @@ end
26
26
  ruby_engine = (defined? RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
27
27
 
28
28
  so_basename = 'oci8lib_'
29
- if ruby_engine == 'ruby'
30
- # The suffix number indicates the ruby API version.
31
- # 1.8 - ruby 1.8.x
32
- # 1.9.1 - ruby 1.9.1, 1.9.2
33
- # 2.0.0 - ruby 2.0.0-dev at the present time.
29
+ case ruby_engine
30
+ when 'ruby'
31
+ # The extension library name includes the ruby ABI (application binary interface)
32
+ # version. It is for binary gems which contain more than one extension library
33
+ # and use correct one depending on the ABI version.
34
+ #
35
+ # ruby version | ABI version
36
+ # --------------+--------------
37
+ # 1.8.6 | 1.8
38
+ # 1.8.7 | 1.8
39
+ # --------------+--------------
40
+ # 1.9.0 | 1.9.0
41
+ # 1.9.1 | 1.9.1
42
+ # 1.9.2 | 1.9.1
43
+ # 1.9.3 | 1.9.1
44
+ # --------------+--------------
45
+ # 2.0.0 | 2.0.0
46
+ # 2.0.1 | 2.0.1 (See: [ruby-core:49578])
47
+ # ... | ...
48
+ #
49
+ # Note: The ruby ABI version is same with RbConfig::CONFIG['ruby_version']
50
+ # if it wasn't explicitly changed by the configure option --with-ruby-version.
51
+ #
34
52
  case RUBY_VERSION
35
53
  when /^2\.0/
36
- so_basename += '200'
54
+ so_basename += RUBY_VERSION.gsub(/\W/, '')
55
+ when /^1\.9\.0/
56
+ raise 'unsupported ruby version: 1.9.0'
37
57
  when /^1\.9/
38
58
  so_basename += '191'
39
59
  when /^1\.8/
@@ -41,8 +61,22 @@ if ruby_engine == 'ruby'
41
61
  else
42
62
  raise 'unsupported ruby version: ' + RUBY_VERSION
43
63
  end
64
+ when 'rbx'
65
+ # "rbx -X18" and "rbx -X19" use different C header files.
66
+ case RUBY_VERSION
67
+ when /^2\.0/
68
+ so_basename += 'rbx20'
69
+ when /^1\.9/
70
+ so_basename += 'rbx19'
71
+ when /^1\.8/
72
+ so_basename += 'rbx18'
73
+ else
74
+ raise 'unsupported language mode: ' + RUBY_VERSION
75
+ end
76
+ when 'jruby'
77
+ raise "Ruby-oci8 doesn't support jruby because its C extension support is in development in jruby 1.6 and deprecated in jruby 1.7."
44
78
  else
45
- so_basename += ruby_engine
79
+ raise 'unsupported ruby engine: ' + RUBY_ENGINE
46
80
  end
47
81
  require so_basename
48
82
 
@@ -89,6 +123,7 @@ class OCI8
89
123
  # OCIClientVersion().
90
124
  #
91
125
  # @return [OCI8::OracleVersion] Oracle client version
126
+ # @see OCI8#oracle_server_version
92
127
  def self.oracle_client_version
93
128
  @@oracle_client_version
94
129
  end
@@ -39,26 +39,6 @@ class OCI8
39
39
  @@client_charset_name = 'US7ASCII'
40
40
  end
41
41
 
42
- # NLS ratio, maximum number of bytes per one chracter
43
- case @@client_charset_name
44
- when 'UTF8'
45
- OCI8.nls_ratio = 3
46
- when 'AL16UTF16'
47
- OCI8.nls_ratio = 4
48
- when /^[[:alpha:]]+(\d+)/
49
- # convert maximum number of bits per one chracter to NLS ratio.
50
- # charset name max bits max bytes
51
- # ------------ -------- ---------
52
- # US7ASCII 7 1
53
- # WE8ISO8859P1 8 1
54
- # JA16SJIS 16 2
55
- # AL32UTF8 32 4
56
- # ...
57
- OCI8.nls_ratio = (($1.to_i + 7) >> 3)
58
- else
59
- raise "Unknown NLS character set name format: #{@@client_charset_name}"
60
- end
61
-
62
42
  # Ruby encoding name for ruby 1.9.
63
43
  if OCI8.respond_to? :encoding
64
44
  if defined? DEFAULT_OCI8_ENCODING
@@ -75,5 +55,25 @@ class OCI8
75
55
  end
76
56
  end
77
57
  OCI8.encoding = enc
58
+ else
59
+ # NLS ratio, maximum number of bytes per one chracter
60
+ case @@client_charset_name
61
+ when 'UTF8'
62
+ OCI8.nls_ratio = 3
63
+ when 'AL16UTF16'
64
+ OCI8.nls_ratio = 4
65
+ when /^[[:alpha:]]+(\d+)/
66
+ # convert maximum number of bits per one chracter to NLS ratio.
67
+ # charset name max bits max bytes
68
+ # ------------ -------- ---------
69
+ # US7ASCII 7 1
70
+ # WE8ISO8859P1 8 1
71
+ # JA16SJIS 16 2
72
+ # AL32UTF8 32 4
73
+ # ...
74
+ OCI8.nls_ratio = (($1.to_i + 7) >> 3)
75
+ else
76
+ raise "Unknown NLS character set name format: #{@@client_charset_name}"
77
+ end
78
78
  end
79
79
  end
@@ -1985,72 +1985,115 @@ class OCI8
1985
1985
  =end
1986
1986
  end # OCI8::Metadata
1987
1987
 
1988
- # return a subclass of OCI8::Metadata::Base
1989
- # which has information about _object_name_.
1990
- # OCI8::Metadata::Table, OCI8::Metadata::View,
1991
- # OCI8::Metadata::Procedure, OCI8::Metadata::Function,
1992
- # OCI8::Metadata::Package, OCI8::Metadata::Type,
1993
- # OCI8::Metadata::Synonym or OCI8::Metadata::Sequence
1988
+ # Returns object information.
1989
+ #
1990
+ # The return type is depends on the object type.
1991
+ #
1992
+ # Oracle type:: Ruby type
1993
+ # Table:: {OCI8::Metadata::Table}
1994
+ # View:: {OCI8::Metadata::View}
1995
+ # Procedure:: {OCI8::Metadata::Procedure}
1996
+ # Function:: {OCI8::Metadata::Function}
1997
+ # Package:: {OCI8::Metadata::Package}
1998
+ # Type:: {OCI8::Metadata::Type}
1999
+ # Synonym:: {OCI8::Metadata::Synonym}
2000
+ # Sequence:: {OCI8::Metadata::Sequence}
2001
+ #
2002
+ # @param [String] object_name
2003
+ # @return [a subclass of OCI8::Metadata::Base]
1994
2004
  def describe_any(object_name)
1995
2005
  __describe(object_name, OCI8::Metadata::Unknown, true)
1996
2006
  end
1997
- # returns a OCI8::Metadata::Table or a OCI8::Metadata::View. If the
1998
- # name is a current schema's synonym name or a public synonym name,
1999
- # it returns a OCI8::Metadata::Table or a OCI8::Metadata::View which
2007
+ # Returns table or view information. If the name is a current schema's synonym
2008
+ # name or a public synonym name, it returns table or view information which
2000
2009
  # the synonym refers.
2001
2010
  #
2002
- # If the second argument is true, this returns a
2003
- # OCI8::Metadata::Table in the current schema.
2011
+ # If +table_only+ is true, it checks tables in the current schema.
2012
+ #
2013
+ # @param [String] table_name
2014
+ # @param [Boolean] table_only (default: false)
2015
+ # @return [OCI8::Metadata::Table or OCI8::Metadata::View]
2004
2016
  def describe_table(table_name, table_only = false)
2005
2017
  if table_only
2006
2018
  # check my own tables only.
2007
2019
  __describe(table_name, OCI8::Metadata::Table, false)
2008
2020
  else
2009
2021
  # check tables, views, synonyms and public synonyms.
2010
- metadata = __describe(table_name, OCI8::Metadata::Unknown, true)
2011
- case metadata
2012
- when OCI8::Metadata::Table, OCI8::Metadata::View
2013
- metadata
2014
- when OCI8::Metadata::Synonym
2015
- describe_table(metadata.translated_name)
2016
- else
2017
- raise OCIError.new("ORA-04043: object #{table_name} does not exist", 4043)
2022
+ recursive_level = 20
2023
+ recursive_level.times do
2024
+ metadata = __describe(table_name, OCI8::Metadata::Unknown, true)
2025
+ case metadata
2026
+ when OCI8::Metadata::Table, OCI8::Metadata::View
2027
+ return metadata
2028
+ when OCI8::Metadata::Synonym
2029
+ table_name = metadata.translated_name
2030
+ else
2031
+ raise OCIError.new(4043, table_name) # ORA-04043: object %s does not exist
2032
+ end
2018
2033
  end
2034
+ raise OCIError.new(36, recursive_level) # ORA-00036: maximum number of recursive SQL levels (%s) exceeded
2019
2035
  end
2020
2036
  end
2021
- # returns a OCI8::Metadata::View in the current schema.
2037
+ # Returns view information
2038
+ #
2039
+ # @param [String] view_name
2040
+ # @return [OCI8::Metadata::View]
2022
2041
  def describe_view(view_name)
2023
2042
  __describe(view_name, OCI8::Metadata::View, false)
2024
2043
  end
2025
- # returns a OCI8::Metadata::Procedure in the current schema.
2044
+ # Returns procedure information
2045
+ #
2046
+ # @param [String] procedure_name
2047
+ # @return [OCI8::Metadata::Procedure]
2026
2048
  def describe_procedure(procedure_name)
2027
2049
  __describe(procedure_name, OCI8::Metadata::Procedure, false)
2028
2050
  end
2029
- # returns a OCI8::Metadata::Function in the current schema.
2051
+ # Returns function information
2052
+ #
2053
+ # @param [String] function_name
2054
+ # @return [OCI8::Metadata::Function]
2030
2055
  def describe_function(function_name)
2031
2056
  __describe(function_name, OCI8::Metadata::Function, false)
2032
2057
  end
2033
- # returns a OCI8::Metadata::Package in the current schema.
2058
+ # Returns package information
2059
+ #
2060
+ # @param [String] package_name
2061
+ # @return [OCI8::Metadata::Package]
2034
2062
  def describe_package(package_name)
2035
2063
  __describe(package_name, OCI8::Metadata::Package, false)
2036
2064
  end
2037
- # returns a OCI8::Metadata::Type in the current schema.
2065
+ # Returns type information
2066
+ #
2067
+ # @param [String] type_name
2068
+ # @return [OCI8::Metadata::Type]
2038
2069
  def describe_type(type_name)
2039
2070
  __describe(type_name, OCI8::Metadata::Type, false)
2040
2071
  end
2041
- # returns a OCI8::Metadata::Synonym in the current schema.
2072
+ # Returns synonym information
2073
+ #
2074
+ # @param [String] synonym_name
2075
+ # @return [OCI8::Metadata::Synonym]
2042
2076
  def describe_synonym(synonym_name, check_public_also = true)
2043
2077
  __describe(synonym_name, OCI8::Metadata::Synonym, check_public_also)
2044
2078
  end
2045
- # returns a OCI8::Metadata::Sequence in the current schema.
2079
+ # Returns sequence information
2080
+ #
2081
+ # @param [String] sequence_name
2082
+ # @return [OCI8::Metadata::Sequence]
2046
2083
  def describe_sequence(sequence_name)
2047
2084
  __describe(sequence_name, OCI8::Metadata::Sequence, false)
2048
2085
  end
2049
- # returns a OCI8::Metadata::Schema in the database.
2086
+ # Returns schema information
2087
+ #
2088
+ # @param [String] schema_name
2089
+ # @return [OCI8::Metadata::Schema]
2050
2090
  def describe_schema(schema_name)
2051
2091
  __describe(schema_name, OCI8::Metadata::Schema, false)
2052
2092
  end
2053
- # returns a OCI8::Metadata::Database.
2093
+ # Returns database information
2094
+ #
2095
+ # @param [String] database_name
2096
+ # @return [OCI8::Metadata::Database]
2054
2097
  def describe_database(database_name)
2055
2098
  __describe(database_name, OCI8::Metadata::Database, false)
2056
2099
  end
@@ -26,8 +26,10 @@ require 'yaml'
26
26
  # value_for_the_second_parameter)
27
27
  class OCI8
28
28
 
29
- # call-seq:
30
- # new(username, password, dbname = nil, privilege = nil)
29
+ # @return [OCIError]
30
+ attr_accessor :last_error
31
+
32
+ # @overload initialize(username, password, dbname = nil, privilege = nil)
31
33
  #
32
34
  # Connects to an Oracle database server by +username+ and +password+
33
35
  # at +dbname+ as +privilege+.
@@ -337,14 +339,14 @@ class OCI8
337
339
  end
338
340
  end
339
341
 
342
+ # @private
340
343
  def inspect
341
344
  "#<OCI8:#{username}>"
342
345
  end
343
346
 
344
- # Returns an OCI8::OracleVersion of the Oracle server version.
345
- #
346
- # See also: OCI8.oracle_client_version
347
+ # Returns the Oracle server version.
347
348
  #
349
+ # @see OCI8.oracle_client_version
348
350
  # @return [OCI8::OracleVersion]
349
351
  def oracle_server_version
350
352
  unless defined? @oracle_server_version
@@ -365,7 +367,7 @@ class OCI8
365
367
  @oracle_server_version
366
368
  end
367
369
 
368
- # Returns the Oracle database character set name.
370
+ # Returns the Oracle database character set name such as AL32UTF8.
369
371
  #
370
372
  # @since 2.1.0
371
373
  # @return [String] Oracle database character set name
@@ -373,15 +375,74 @@ class OCI8
373
375
  charset_id2name(@server_handle.send(:attr_get_ub2, OCI_ATTR_CHARSET_ID))
374
376
  end
375
377
 
376
- # Returns the client-side Oracle character set name.
378
+ # Returns the client-side Oracle character set name such as AL32UTF8.
377
379
  #
378
380
  # @since 2.1.0
379
381
  # @return [String] client-side character set name
382
+ # @private
383
+ # @see OCI8.encoding
380
384
  def self.client_charset_name
381
385
  @@client_charset_name
382
386
  end
383
387
  end
384
388
 
389
+ class OCIError
390
+
391
+ # @overload initialize(message, error_code = nil, sql_stmt = nil, parse_error_offset = nil)
392
+ # Creates a new OCIError object with specified parameters.
393
+ #
394
+ # @param [String] message error message
395
+ # @param [Integer] error_code Oracle error code
396
+ # @param [String] sql_stmt SQL statement
397
+ # @param [Integer] parse_error_offset
398
+ #
399
+ # @example
400
+ # OCIError.new("ORA-00001: unique constraint (%s.%s) violated", 1, 'insert into table_name values (1)', )
401
+ # # => #<OCIError: ORA-00001: unique constraint (%s.%s) violated>
402
+ # #<OCIError: ORA-00923: FROM keyword not found where expected>
403
+ # "select sysdate"
404
+ # 923
405
+ # 14
406
+ #
407
+ # @overload initialize(error_code, *params)
408
+ # Creates a new OCIError object with the error message which corresponds to the specified
409
+ # Oracle error code.
410
+ #
411
+ # @param [Integer] error_code Oracle error code
412
+ # @param [String, ...] params parameters which replace '%s'
413
+ #
414
+ # @example
415
+ # # without parameters
416
+ # OCIError.new(4043)
417
+ # # When NLS_LANG=american_america.AL32UTF8
418
+ # # => #<OCIError: ORA-04043: object %s does not exist>
419
+ # # When NLS_LANG=german_germany.AL32UTF8
420
+ # # => #<OCIError: ORA-04043: Objekt %s ist nicht vorhanden>
421
+ #
422
+ # # with one parameter
423
+ # OCIError.new(4043, 'table_name')
424
+ # # When NLS_LANG=american_america.AL32UTF8
425
+ # # => #<OCIError: ORA-04043: object table_name does not exist>
426
+ # # When NLS_LANG=german_germany.AL32UTF8
427
+ # # => #<OCIError: ORA-04043: Objekt table_name ist nicht vorhanden>
428
+ #
429
+ def initialize(*args)
430
+ if args.length > 0
431
+ if args[0].is_a? Fixnum
432
+ @code = args.shift
433
+ super(OCI8.error_message(@code).gsub('%s') {|s| args.empty? ? '%s' : args.shift})
434
+ @sql = nil
435
+ @parse_error_offset = nil
436
+ else
437
+ msg, @code, @sql, @parse_error_offset = args
438
+ super(msg)
439
+ end
440
+ else
441
+ super()
442
+ end
443
+ end
444
+ end
445
+
385
446
  class OraDate
386
447
 
387
448
  # Returns a Time object which denotes self.
@@ -122,7 +122,7 @@ class OCI8
122
122
  # oraver = OCI8::OracleVersion.new('11.2.0.3')
123
123
  # oraver.to_s # => '11.2.0.3.0'
124
124
  #
125
- # @return [Integer]
125
+ # @return [String]
126
126
  def to_s
127
127
  format('%d.%d.%d.%d.%d', @major, @minor, @update, @patch, @port_update)
128
128
  end
@@ -1,26 +1,30 @@
1
1
  # properties.rb -- implements OCI8.properties
2
2
  #
3
- # Copyright (C) 2010-2012 KUBO Takehiro <kubo@jiubao.org>
3
+ # Copyright (C) 2010-2013 KUBO Takehiro <kubo@jiubao.org>
4
4
 
5
5
  #
6
6
  class OCI8
7
7
 
8
+ # @private
8
9
  @@properties = {
9
10
  :length_semantics => :byte,
10
11
  :bind_string_as_nchar => false,
11
- :float_conversion_type => :ruby,
12
+ :float_conversion_type => OCI8.__get_prop(1) ? :ruby : :oracle,
12
13
  :statement_cache_size => 0,
14
+ :events_mode => ((OCI8.__get_prop(2) & 4) != 0) # 4 <- OCI_EVENTS in oci.h
13
15
  }
14
16
 
15
17
  if OCI8.oracle_client_version < OCI8::ORAVER_9_2
16
18
  @@properties[:statement_cache_size] = nil
17
19
  end
18
20
 
21
+ # @private
19
22
  def @@properties.[](name)
20
23
  raise IndexError, "No such property name: #{name}" unless @@properties.has_key?(name)
21
24
  super(name)
22
25
  end
23
26
 
27
+ # @private
24
28
  def @@properties.[]=(name, val)
25
29
  raise IndexError, "No such property name: #{name}" unless @@properties.has_key?(name)
26
30
  case name
@@ -31,23 +35,31 @@ class OCI8
31
35
  when :bind_string_as_nchar
32
36
  val = val ? true : false
33
37
  when :float_conversion_type
34
- # handled by native code in oci8lib_xx.so.
35
- OCI8.__set_property(name, val)
38
+ case val
39
+ when :ruby
40
+ OCI8.__set_prop(1, true)
41
+ when :oracle
42
+ OCI8.__set_prop(1, false)
43
+ else
44
+ raise ArgumentError, "float_conversion_type's value should be either :ruby or :oracle."
45
+ end
36
46
  when :statement_cache_size
37
47
  if OCI8.oracle_client_version < OCI8::ORAVER_9_2
38
48
  raise RuntimeError, ":statement_cache_size is disabled on Oracle 9iR1 client."
39
49
  end
40
50
  val = val.to_i
41
51
  raise ArgumentError, "The property value for :statement_cache_size must not be negative." if val < 0
52
+ when :events_mode
53
+ val = val ? true : false
54
+ if val
55
+ OCI8.__set_prop(2, OCI8.__get_prop(2) | 4) # set OCI_EVENTS
56
+ else
57
+ OCI8.__set_prop(2, OCI8.__get_prop(2) & ~4) # unset OCI_EVENTS
58
+ end
42
59
  end
43
60
  super(name, val)
44
61
  end
45
62
 
46
- # call-seq:
47
- # OCI8.properties -> a customized Hash
48
- #
49
- # (new in 2.0.5)
50
- #
51
63
  # Returns a Hash which ruby-oci8 global settings.
52
64
  # The hash's setter and getter methods are customized to check
53
65
  # property names and values.
@@ -63,19 +75,20 @@ class OCI8
63
75
  # Supported properties are listed below:
64
76
  #
65
77
  # [:length_semantics]
66
- # (new in 2.1.0)
67
78
  #
68
79
  # +:char+ when Oracle character length is counted by the number of characters.
69
80
  # +:byte+ when it is counted by the number of bytes.
70
81
  # The default setting is +:byte+ because +:char+ causes unexpected behaviour on
71
82
  # Oracle 9i.
83
+ #
84
+ # *Since:* 2.1.0
72
85
  #
73
86
  # [:bind_string_as_nchar]
87
+ #
74
88
  # +true+ when string bind variables are bound as NCHAR,
75
89
  # otherwise +false+. The default value is +false+.
76
90
  #
77
91
  # [:float_conversion_type]
78
- # (new in 2.1.0)
79
92
  #
80
93
  # +:ruby+ when Oracle decimal numbers are converted to ruby Float values
81
94
  # same as Float#to_s does. (default)
@@ -85,14 +98,35 @@ class OCI8
85
98
  # the Oracle function OCINumberToReal() makes a string representation
86
99
  # 15.700000000000001 by Float#to_s.
87
100
  # See: http://rubyforge.org/forum/forum.php?thread_id=50030&forum_id=1078
101
+ #
102
+ # *Since:* 2.1.0
88
103
  #
89
104
  # [:statement_cache_size]
90
- # (new in 2.1.1)
91
105
  #
92
106
  # The statement cache size per each session. The default size is 0, which
93
107
  # means no statement cache, since 2.1.2. It was 20 in 2.1.1.
94
108
  # This feature is available on Oracle 9iR2 or later.
95
109
  # See: http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/oci09adv.htm#i471377
110
+ #
111
+ # *Since:* 2.1.1
112
+ #
113
+ # [:events_mode]
114
+ #
115
+ # +true+ when Fast Application Notification (FAN) Support is enabled.
116
+ # +false+ when it is disabled. The default value is +false+.
117
+ # This corresponds to {http://php.net/manual/en/oci8.configuration.php#ini.oci8.events +oci8.events+ in PHP}.
118
+ #
119
+ # This parameter can be changed only when no OCI methods are called.
120
+ #
121
+ # require 'oci8'
122
+ # OCI8.properties[:events_mode] = true # works fine.
123
+ # ... call some OCI methods ...
124
+ # OCI8.properties[:events_mode] = true # raises a runtime error.
125
+ #
126
+ # *Since:* 2.1.4
127
+ #
128
+ # @return [a customized Hash]
129
+ # @since 2.0.5
96
130
  #
97
131
  def self.properties
98
132
  @@properties
@@ -75,6 +75,22 @@ class TestCLob < Test::Unit::TestCase
75
75
  lob.close
76
76
  end
77
77
 
78
+ # https://github.com/kubo/ruby-oci8/issues/20
79
+ def test_github_issue_20
80
+ lob1 = OCI8::CLOB.new(@conn, ' ' * (1024 * 1024))
81
+ begin
82
+ lob2 = OCI8::CLOB.new(@conn, ' ' * (128 * 1024 * 1024))
83
+ rescue OCIError
84
+ raise if $!.code != 24817
85
+ # ORA-24817: Unable to allocate the given chunk for current lob operation
86
+ GC.start
87
+ # allocate smaller size
88
+ lob2 = OCI8::CLOB.new(@conn, ' ' * (16 * 1024 * 1024))
89
+ end
90
+ lob1 = nil # lob1's value will be freed in GC.
91
+ lob2.read # GC must run here to reproduce the issue.
92
+ end
93
+
78
94
  def teardown
79
95
  drop_table('test_table')
80
96
  @conn.logoff
@@ -25,7 +25,7 @@ STORAGE (
25
25
  MAXEXTENTS UNLIMITED
26
26
  PCTINCREASE 0)
27
27
  EOS
28
- ascii_8bit = Encoding.find('ASCII-8BIT')
28
+ ascii_8bit = "\xab\xcd".force_encoding('ASCII-8BIT')
29
29
  @conn.exec(<<EOS)
30
30
  INSERT INTO test_table VALUES ('abcd', 'abcd', 'abcd', 'abcd', 'abcd', 'abcd', 'abcd')
31
31
  EOS
@@ -34,16 +34,16 @@ EOS
34
34
  assert_equal(OCI8.encoding, row[0].encoding);
35
35
  assert_equal('abcd', row[1], 'VARCHAR2(10)')
36
36
  assert_equal(OCI8.encoding, row[1].encoding);
37
- assert_equal("\xab\xcd", row[2], 'RAW(10)')
38
- assert_equal(ascii_8bit, row[2].encoding);
39
- assert_equal("\xab\xcd", row[3], 'LONG RAW')
40
- assert_equal(ascii_8bit, row[3].encoding);
37
+ assert_equal(ascii_8bit, row[2], 'RAW(10)')
38
+ assert_equal(ascii_8bit.encoding, row[2].encoding);
39
+ assert_equal(ascii_8bit, row[3], 'LONG RAW')
40
+ assert_equal(ascii_8bit.encoding, row[3].encoding);
41
41
  assert_equal('abcd', (data = row[4].read), 'CLOB')
42
42
  assert_equal(OCI8.encoding, data.encoding);
43
43
  assert_equal('abcd', (data = row[5].read), 'NCLOB')
44
44
  assert_equal(OCI8.encoding, data.encoding);
45
- assert_equal("\xab\xcd", (data = row[6].read), 'BLOB')
46
- assert_equal(ascii_8bit, data.encoding);
45
+ assert_equal(ascii_8bit, (data = row[6].read), 'BLOB')
46
+ assert_equal(ascii_8bit.encoding, data.encoding);
47
47
 
48
48
  if OCI8.encoding.name == "UTF-8" and ['WE8ISO8859P1', 'WE8ISO8859P15', 'AL32UTF8', 'UTF8'].include? @conn.database_charset_name
49
49
  utf_8 = "\u00A1\u00A2\u00A3\u00A5\u00A7\u00A9"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-oci8
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.3
4
+ version: 2.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-11 00:00:00.000000000 Z
12
+ date: 2013-01-06 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'ruby-oci8 is a ruby interface for Oracle using OCI8 API. It is available
15
15
  with Oracle8, Oracle8i, Oracle9i, Oracle10g and Oracle Instant Client.
@@ -135,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
135
  version: '0'
136
136
  requirements: []
137
137
  rubyforge_project: ruby-oci8
138
- rubygems_version: 1.8.23
138
+ rubygems_version: 1.8.11
139
139
  signing_key:
140
140
  specification_version: 3
141
141
  summary: Ruby interface for Oracle using OCI8 API