ruby-oci8 2.0.3 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ChangeLog CHANGED
@@ -1,3 +1,83 @@
1
+ 2010-02-28 KUBO Takehiro <kubo@jiubao.org>
2
+ * NEWS: add changes between 2.0.3 and 2.0.4.
3
+ * VERSION: change the version to 2.0.3.
4
+ * ext/oci8/stmt.c: fix segmentation fault when OCI8::Cursor#fetch
5
+ is called prior to OCI8::Cursor#exec.
6
+ * ext/oci8/oci8.c: minor fix in rdoc comment.
7
+
8
+ 2010-02-27 KUBO Takehiro <kubo@jiubao.org>
9
+ * lib/oci8/datetime.rb: fix a problem that fractional seconds are lost
10
+ when Time value is bound to TIMESTAMP.
11
+ (reported by Raimonds Simanovskis)
12
+
13
+ 2010-02-27 KUBO Takehiro <kubo@jiubao.org>
14
+ * ext/oci8/error.c, ext/oci8/extconf.rb, ext/oci8/oci8.h: fix for
15
+ old Oracle versions, which lack declarations of OCIMsg, oraub8,
16
+ orasb8 and OCI_DURATION_PROCESS.
17
+ * ext/oci8/ocihandle.c: fix for mingw compiler.
18
+
19
+ 2010-02-27 KUBO Takehiro <kubo@jiubao.org>
20
+ * ext/oci8/apiwrap.yml, ext/oci8/error.c, ext/oci8/oci8.h,
21
+ ext/oci8/ocinumber.c: fix for Oracle 8.0 client, which doesn't
22
+ have OCIMessageOpen() and OCIMessageGet().
23
+ * ext/oci8/oci8.c: add a new method OCI8.error_message to get
24
+ a error message which depends on NLS_LANGUAGE.
25
+
26
+ 2010-02-09 KUBO Takehiro <kubo@jiubao.org>
27
+ * dist-files: add ext/oci8/oranumber_util.c and
28
+ ext/oci8/oranumber_util.h.
29
+ (reported by Raimonds Simanovskis)
30
+
31
+ 2010-02-07 KUBO Takehiro <kubo@jiubao.org>
32
+ * ext/oci8/ocinumber.c, ext/oci8/oranumber_util.c,
33
+ ext/oci8/oranumber_util.h: change the declaration of
34
+ oranumber_to_str() to prevent buffer overflow by
35
+ unexpected invalid Oracle number internal data.
36
+
37
+ 2010-02-07 KUBO Takehiro <kubo@jiubao.org>
38
+ * ext/oci8/error.c, ext/oci8/oci8.h: add oci8_raise_by_msgno()
39
+ to retrieve a Oracle error message which depends on NLS_LANGUAGE.
40
+ * ext/oci8/oranumber_util.c, ext/oci8/oranumber_util.h,
41
+ ext/oci8/extconf.rb: add handwritten conversion functions from
42
+ OCINumber internal representation to string and vice versa.
43
+ * ext/oci8/ocinumber.c: 1. use handwritten conversion functions
44
+ instead of OCI functions to convert OraNumber to string
45
+ and vice varse. 2. add OraNumber#dump.
46
+ * test/test_oranumber.rb: add test cases to check conversion from
47
+ OraNumber to string and vice varse.
48
+
49
+ 2010-02-02 KUBO Takehiro <kubo@jiubao.org>
50
+ * ext/oci8/ocinumber.c: fix to support NUMBERS with scale larger
51
+ than 38 by using scientific number notation to convert OraNumber
52
+ to BigDecimal. OraNumber#to_i is also fixed.
53
+ (reported by Raimonds Simanovskis)
54
+
55
+ 2010-01-24 KUBO Takehiro <kubo@jiubao.org>
56
+ * ext/oci8/error.c: Use OCIErrorGet() to retrieve the error message
57
+ when the OCI return code is OCI_NO_DATA.
58
+ (reported by Raimonds Simanovskis)
59
+
60
+ 2009-12-06 KUBO Takehiro <kubo@jiubao.org>
61
+ * ext/oci8/object.c: 1. fix segv when GC starts while initializing
62
+ a bind object for object type. (reported by Remi Gagnon)
63
+ 2. fix memory leak about 30 bytes per one bind object for object
64
+ type.
65
+
66
+ 2009-11-03 KUBO Takehiro <kubo@jiubao.org>
67
+ * ext/oci8/object.c: fix segv when binding a collection of string.
68
+ (reported by Raimonds Simanovskis)
69
+
70
+ 2009-10-26 KUBO Takehiro <kubo@jiubao.org>
71
+ * NEW: fix typo.
72
+ * dist-files, ext/oci8/.document: add ocihandle.c.
73
+ * ext/oci8/ocihandle.c: add private methods OCIHandle#attr_get_*,
74
+ OCIHandle#attr_set_* and their rdoc comments.
75
+
76
+ 2009-10-23 KUBO Takehiro <kubo@jiubao.org>
77
+ * ext/oci8/extconf.rb, ext/oci8/oci8.h, ext/oci8/oci8lib.c,
78
+ ext/oci8/ocihandle.c: add ocihandle.c and move OCIHandle
79
+ definitions from oci8lib.c to the file.
80
+
1
81
  2009-10-21 KUBO Takehiro <kubo@jiubao.org>
2
82
  * NEWS: add changes between 2.0.2 and 2.0.3.
3
83
  * VERSION, Makefile: change the version to 2.0.3.
data/NEWS CHANGED
@@ -1,6 +1,61 @@
1
+ 2.0.4:
2
+
3
+ * New Features
4
+
5
+ - OCI8.error_message(message_no) -> string
6
+
7
+ Gets the Oracle error message specified by message id.
8
+ Its language depends on NLS_LANGUAGE.
9
+
10
+ Note: This method is unavailable if the Oracle client
11
+ version is 8.0.
12
+
13
+ # When NLS_LANG is AMERICAN_AMERICA.AL32UTF8
14
+ OCI8.error_message(1)
15
+ # => "ORA-00001: unique constraint (%s.%s) violated"
16
+
17
+ # When NLS_LANG is FRENCH_FRANCE.AL32UTF8
18
+ OCI8.error_message(1)
19
+ # => "ORA-00001: violation de contrainte unique (%s.%s)"
20
+
21
+ - OraNumber#dump -> string
22
+
23
+ Returns OraNumber's internal representation whose format
24
+ is same with the return value of Oracle SQL function DUMP().
25
+
26
+ OraNumber.new(100).dump #=> "Typ=2 Len=2: 194,2"
27
+ OraNumber.new(123).dump #=> "Typ=2 Len=3: 194,2,24"
28
+ OraNumber.new(0.1).dump #=> "Typ=2 Len=2: 192,11"
29
+
30
+ * Fixed issues
31
+
32
+ - Fractional second part is lost when ruby's Time instance is bound
33
+ to Oracle datatype TIMESTAMP.
34
+ (reported by Raimonds Simanovskis)
35
+
36
+ - OraNumber#to_i and OraNumber#to_s fail when its scale is larger
37
+ than 38.
38
+ (reported by Raimonds Simanovskis)
39
+
40
+ - Memory leak about 30 bytes per one place holder for object type.
41
+
42
+ - Segmentation fault when a collection of string is bound.
43
+ (reported by Raimonds Simanovskis)
44
+
45
+ - Segmentation fault when GC starts while initializing a bind
46
+ object for object type.
47
+ (reported by Remi Gagnon)
48
+
49
+ - Segmentation fault when OCI8::Cursor#fetch is called prior to
50
+ OCI8::Cursor#exec.
51
+
52
+ - Detailed error message is not reported when PL/SQL NO_DATA_FOUND
53
+ exception is raised.
54
+ (reported by Raimonds Simanovskis)
55
+
1
56
  2.0.3:
2
57
 
3
- * Imcompatible Changes
58
+ * Incompatible Changes
4
59
 
5
60
  - Number column in a SQL statement
6
61
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.3
1
+ 2.0.4
data/dist-files CHANGED
@@ -31,9 +31,12 @@ ext/oci8/oci8.c
31
31
  ext/oci8/oci8.h
32
32
  ext/oci8/oci8lib.c
33
33
  ext/oci8/ocidatetime.c
34
+ ext/oci8/ocihandle.c
34
35
  ext/oci8/ocinumber.c
35
36
  ext/oci8/oraconf.rb
36
37
  ext/oci8/oradate.c
38
+ ext/oci8/oranumber_util.c
39
+ ext/oci8/oranumber_util.h
37
40
  ext/oci8/post-config.rb
38
41
  ext/oci8/stmt.c
39
42
  ext/oci8/object.c
@@ -3,6 +3,7 @@
3
3
  #env.c
4
4
 
5
5
  oci8.c
6
+ ocihandle.c
6
7
  bind.c
7
8
  stmt.c
8
9
  encoding.c
@@ -947,6 +947,23 @@ OCILobOpen_nb:
947
947
  - OCILobLocator *locp
948
948
  - ub1 mode
949
949
 
950
+ OCIMessageOpen:
951
+ :version: 810
952
+ :args: - dvoid *envhp
953
+ - OCIError *errhp
954
+ - OCIMsg **msghp
955
+ - CONST OraText *product
956
+ - CONST OraText *facility
957
+ - OCIDuration dur
958
+
959
+ OCIMessageGet:
960
+ :version: 810
961
+ :ret: OraText *
962
+ :args: - OCIMsg *msgh
963
+ - ub4 msgno
964
+ - OraText *msgbuf
965
+ - size_t buflen
966
+
950
967
  # round trip: 0
951
968
  OCINumberIsInt:
952
969
  :version: 810
@@ -3,7 +3,7 @@
3
3
  * attr.c
4
4
  *
5
5
  * $Author: kubo $
6
- * $Date: 2009-10-21 22:50:01 +0900 (Wed, 21 Oct 2009) $
6
+ * $Date: 2009-05-17 19:08:39 +0900 (Sun, 17 May 2009) $
7
7
  *
8
8
  * Copyright (C) 2002-2007 KUBO Takehiro <kubo@jiubao.org>
9
9
  */
@@ -3,7 +3,7 @@
3
3
  * bind.c
4
4
  *
5
5
  * $Author: kubo $
6
- * $Date: 2009-10-21 22:50:01 +0900 (Wed, 21 Oct 2009) $
6
+ * $Date: 2009-05-19 21:51:28 +0900 (Tue, 19 May 2009) $
7
7
  *
8
8
  * Copyright (C) 2002-2008 KUBO Takehiro <kubo@jiubao.org>
9
9
  */
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  error.c - part of ruby-oci8
4
4
 
5
- Copyright (C) 2002-2007 KUBO Takehiro <kubo@jiubao.org>
5
+ Copyright (C) 2002-2010 KUBO Takehiro <kubo@jiubao.org>
6
6
 
7
7
  =begin
8
8
  == OCIError
@@ -28,9 +28,58 @@ static ID oci8_id_sql;
28
28
  static ID oci8_id_caller;
29
29
  static ID oci8_id_set_backtrace;
30
30
 
31
+ #define ERRBUF_EXPAND_LEN 256
32
+ static char *errbuf;
33
+ static ub4 errbufsiz;
34
+
35
+ static OCIMsg *msghp;
36
+
37
+ #ifndef OCI_DURATION_PROCESS
38
+ #define OCI_DURATION_PROCESS ((OCIDuration)5)
39
+ #endif
40
+
31
41
  NORETURN(static void oci8_raise2(dvoid *errhp, sword status, ub4 type, OCIStmt *stmthp, const char *file, int line));
32
42
  NORETURN(static void set_backtrace_and_raise(VALUE exc, const char *file, int line));
33
43
 
44
+ static VALUE get_error_msg(dvoid *errhp, ub4 type, const char *default_msg, sb4 *errcode_p)
45
+ {
46
+ sword rv;
47
+ size_t len;
48
+
49
+ retry:
50
+ errbuf[0] = '\0';
51
+ rv = OCIErrorGet(errhp, 1, NULL, errcode_p, TO_ORATEXT(errbuf), errbufsiz, type);
52
+ /* OCI manual says:
53
+ * If type is set to OCI_HTYPE_ERROR, then the return
54
+ * code during truncation for OCIErrorGet() is
55
+ * OCI_ERROR. The client can then specify a bigger
56
+ * buffer and call OCIErrorGet() again.
57
+ *
58
+ * But as far as I tested on Oracle XE 10.2.0.1, the return
59
+ * code is OCI_SUCCESS when the message is truncated.
60
+ */
61
+ len = strlen(errbuf);
62
+ if (errbufsiz - len <= 7) {
63
+ /* The error message may be truncated.
64
+ * The magic number 7 means the maximum length of one utf-8
65
+ * character plus the length of a nul terminator.
66
+ */
67
+ errbufsiz += ERRBUF_EXPAND_LEN;
68
+ errbuf = xrealloc(errbuf, errbufsiz);
69
+ goto retry;
70
+ }
71
+ if (rv != OCI_SUCCESS) {
72
+ /* No message is found. Use the default message. */
73
+ return rb_usascii_str_new_cstr(default_msg);
74
+ }
75
+
76
+ /* truncate trailing CR and LF */
77
+ while (len > 0 && (errbuf[len - 1] == '\n' || errbuf[len - 1] == '\r')) {
78
+ len--;
79
+ }
80
+ return rb_external_str_new_with_enc(errbuf, len, oci8_encoding);
81
+ }
82
+
34
83
  static void oci8_raise2(dvoid *errhp, sword status, ub4 type, OCIStmt *stmthp, const char *file, int line)
35
84
  {
36
85
  VALUE vcodes = Qnil;
@@ -103,7 +152,7 @@ static void oci8_raise2(dvoid *errhp, sword status, ub4 type, OCIStmt *stmthp, c
103
152
  break;
104
153
  case OCI_NO_DATA:
105
154
  exc = eOCINoData;
106
- msg = rb_usascii_str_new_cstr("No Data");
155
+ msg = get_error_msg(errhp, type, "No Data", &errcode);
107
156
  break;
108
157
  case OCI_INVALID_HANDLE:
109
158
  exc = eOCIInvalidHandle;
@@ -252,6 +301,9 @@ sb4 oci8_get_error_code(OCIError *errhp)
252
301
 
253
302
  void Init_oci8_error(void)
254
303
  {
304
+ errbufsiz = ERRBUF_EXPAND_LEN;
305
+ errbuf = xmalloc(errbufsiz);
306
+
255
307
  oci8_id_code = rb_intern("code");
256
308
  oci8_id_message = rb_intern("message");
257
309
  oci8_id_parse_error_offset = rb_intern("parse_error_offset");
@@ -301,3 +353,40 @@ void oci8_do_raise_init_error(const char *file, int line)
301
353
  rb_ivar_set(exc, oci8_id_message, rb_ary_new3(1, msg));
302
354
  set_backtrace_and_raise(exc, file, line);
303
355
  }
356
+
357
+ VALUE oci8_get_error_message(ub4 msgno, const char *default_msg)
358
+ {
359
+ char head[32];
360
+ size_t headsz;
361
+ const char *errmsg = NULL;
362
+ char msgbuf[64];
363
+
364
+ if (have_OCIMessageGet) {
365
+ if (msghp == NULL) {
366
+ oci_lc(OCIMessageOpen(oci8_envhp, oci8_errhp, &msghp, TO_ORATEXT("rdbms"), TO_ORATEXT("ora"), OCI_DURATION_PROCESS));
367
+ }
368
+ errmsg = TO_CHARPTR(OCIMessageGet(msghp, msgno, NULL, 0));
369
+ }
370
+ if (errmsg == NULL) {
371
+ if (default_msg != NULL) {
372
+ errmsg = default_msg;
373
+ } else {
374
+ /* last resort */
375
+ snprintf(msgbuf, sizeof(msgbuf), "Message %u not found; product=rdbms; facility=ora", msgno);
376
+ errmsg = msgbuf;
377
+ }
378
+ }
379
+ headsz = snprintf(head, sizeof(head), "ORA-%05u: ", msgno);
380
+ return rb_str_append(rb_usascii_str_new(head, headsz),
381
+ rb_external_str_new_with_enc(errmsg, strlen(errmsg), oci8_encoding));
382
+ }
383
+
384
+ void oci8_do_raise_by_msgno(ub4 msgno, const char *default_msg, const char *file, int line)
385
+ {
386
+ VALUE msg = oci8_get_error_message(msgno, default_msg);
387
+ VALUE exc = rb_funcall(eOCIError, oci8_id_new, 1, msg);
388
+
389
+ rb_ivar_set(exc, oci8_id_code, rb_ary_new3(1, INT2FIX(-1)));
390
+ rb_ivar_set(exc, oci8_id_message, rb_ary_new3(1, msg));
391
+ set_backtrace_and_raise(exc, file, line);
392
+ }
@@ -69,6 +69,7 @@ have_type('OCIInterval*', 'ociap.h')
69
69
  have_type('OCICallbackLobRead2', 'ociap.h')
70
70
  have_type('OCICallbackLobWrite2', 'ociap.h')
71
71
  have_type('OCIAdmin*', 'ociap.h')
72
+ have_type('OCIMsg*', 'ociap.h')
72
73
 
73
74
  if with_config('oracle-version')
74
75
  oci_client_version = OCI8::OracleVersion.new(with_config('oracle-version')).to_i
@@ -82,11 +83,11 @@ if with_config('runtime-check')
82
83
  $libs = saved_libs
83
84
  end
84
85
 
85
- $objs = ["oci8lib.o", "env.o", "error.o", "oci8.o",
86
+ $objs = ["oci8lib.o", "env.o", "error.o", "oci8.o", "ocihandle.o",
86
87
  "stmt.o", "bind.o", "metadata.o", "attr.o",
87
88
  "lob.o", "oradate.o",
88
89
  "ocinumber.o", "ocidatetime.o", "object.o", "apiwrap.o",
89
- "encoding.o", "xmldb.o"]
90
+ "encoding.o", "xmldb.o", "oranumber_util.o"]
90
91
 
91
92
  if RUBY_PLATFORM =~ /mswin32|cygwin|mingw32|bccwin32/
92
93
  $defs << "-DUSE_WIN32_C"
@@ -300,11 +300,11 @@ static VALUE oci8_named_coll_set_coll_element(VALUE self, VALUE datatype, VALUE
300
300
  switch (FIX2INT(datatype)) {
301
301
  case ATTR_STRING:
302
302
  oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_VARCHAR2, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr));
303
- oci_lc(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp));
303
+ cb_data.indp = &cb_data.ind;
304
304
  break;
305
305
  case ATTR_RAW:
306
306
  oci_lc(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_RAW, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr));
307
- oci_lc(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp));
307
+ cb_data.indp = &cb_data.ind;
308
308
  break;
309
309
  case ATTR_OCINUMBER:
310
310
  case ATTR_FLOAT:
@@ -498,11 +498,14 @@ static void bind_named_type_mark(oci8_base_t *base)
498
498
  {
499
499
  oci8_bind_t *obind = (oci8_bind_t *)base;
500
500
  oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
501
- ub4 idx = 0;
502
501
 
503
- do {
504
- rb_gc_mark(oho[idx].obj);
505
- } while (++idx < obind->maxar_sz);
502
+ if (oho != NULL) {
503
+ ub4 idx = 0;
504
+
505
+ do {
506
+ rb_gc_mark(oho[idx].obj);
507
+ } while (++idx < obind->maxar_sz);
508
+ }
506
509
  rb_gc_mark(obind->tdo);
507
510
  }
508
511
 
@@ -510,14 +513,18 @@ static void bind_named_type_free(oci8_base_t *base)
510
513
  {
511
514
  oci8_bind_t *obind = (oci8_bind_t *)base;
512
515
  oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
513
- ub4 idx = 0;
514
516
 
515
- do {
516
- if (oho[idx].hp != NULL) {
517
- OCIObjectFree(oci8_envhp, oci8_errhp, oho[idx].hp, OCI_DEFAULT);
518
- oho[idx].hp = NULL;
519
- }
520
- } while (++idx < obind->maxar_sz);
517
+ if (oho != NULL) {
518
+ ub4 idx = 0;
519
+
520
+ do {
521
+ if (oho[idx].hp != NULL) {
522
+ OCIObjectFree(oci8_envhp, oci8_errhp, oho[idx].hp, OCI_DEFAULT);
523
+ oho[idx].hp = NULL;
524
+ }
525
+ } while (++idx < obind->maxar_sz);
526
+ }
527
+ oci8_bind_free(base);
521
528
  }
522
529
 
523
530
  static VALUE bind_named_type_get(oci8_bind_t *obind, void *data, void *null_struct)
@@ -64,6 +64,28 @@ static VALUE oci8_s_oracle_client_vernum(VALUE klass)
64
64
  return oracle_client_vernum;
65
65
  }
66
66
 
67
+ /*
68
+ * call-seq:
69
+ * OCI8.error_message(message_no) -> string
70
+ *
71
+ * Get the Oracle error message specified by message_no.
72
+ * Its language depends on NLS_LANGUAGE.
73
+ *
74
+ * Note: This method is unavailable if the Oracle client version is 8.0.
75
+ *
76
+ * example:
77
+ * # When NLS_LANG is AMERICAN_AMERICA.AL32UTF8
78
+ * OCI8.error_message(1) # => "ORA-00001: unique constraint (%s.%s) violated"
79
+ *
80
+ * # When NLS_LANG is FRENCH_FRANCE.AL32UTF8
81
+ * OCI8.error_message(1) # => "ORA-00001: violation de contrainte unique (%s.%s)"
82
+ *
83
+ */
84
+ static VALUE oci8_s_error_message(VALUE klass, VALUE msgid)
85
+ {
86
+ return oci8_get_error_message(NUM2UINT(msgid), NULL);
87
+ }
88
+
67
89
  #define CONN_STR_REGEX "/^([^(\\s|\\@)]*)\\/([^(\\s|\\@)]*)(?:\\@(\\S+))?(?:\\s+as\\s+(\\S*)\\s*)?$/i"
68
90
  static void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode)
69
91
  {
@@ -942,6 +964,9 @@ VALUE Init_oci8(void)
942
964
  id_set_prefetch_rows = rb_intern("prefetch_rows=");
943
965
 
944
966
  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
+ }
945
970
  rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
946
971
  rb_define_method(cOCI8, "initialize", oci8_svcctx_initialize, -1);
947
972
  rb_define_method(cOCI8, "logoff", oci8_svcctx_logoff, 0);