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
@@ -0,0 +1,201 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * connection_pool.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
6
+ *
7
+ */
8
+ #include "oci8.h"
9
+
10
+ static VALUE cOCIConnectionPool;
11
+
12
+ typedef struct {
13
+ oci8_base_t base;
14
+ VALUE pool_name;
15
+ } oci8_cpool_t;
16
+
17
+ static void oci8_cpool_mark(oci8_base_t *base)
18
+ {
19
+ oci8_cpool_t *cpool = (oci8_cpool_t *)base;
20
+
21
+ rb_gc_mark(cpool->pool_name);
22
+ }
23
+
24
+ static VALUE cpool_free_thread(void *arg)
25
+ {
26
+ OCIConnectionPoolDestroy((OCICPool *)arg, oci8_errhp, OCI_DEFAULT);
27
+ OCIHandleFree(arg, OCI_HTYPE_CPOOL);
28
+ return 0;
29
+ }
30
+
31
+ static void oci8_cpool_free(oci8_base_t *base)
32
+ {
33
+ oci8_run_native_thread(cpool_free_thread, base->hp.poolhp);
34
+ base->type = 0;
35
+ base->hp.ptr = NULL;
36
+ }
37
+
38
+ static void oci8_cpool_init(oci8_base_t *base)
39
+ {
40
+ oci8_cpool_t *cpool = (oci8_cpool_t *)base;
41
+
42
+ cpool->pool_name = Qnil;
43
+ }
44
+
45
+ static oci8_base_vtable_t oci8_cpool_vtable = {
46
+ oci8_cpool_mark,
47
+ oci8_cpool_free,
48
+ sizeof(oci8_cpool_t),
49
+ oci8_cpool_init,
50
+ };
51
+
52
+ /*
53
+ * call-seq:
54
+ * OCI8::ConnectionPool.new(conn_min, conn_max, conn_incr, username = nil, password = nil, dbname = nil) -> connection pool
55
+ * OCI8::ConnectionPool.new(conn_min, conn_max, conn_incr, connect_string) -> connection pool
56
+ *
57
+ * Creates a connection pool.
58
+ *
59
+ * <i>conn_min</i> specifies the minimum number of connections in the
60
+ * connection pool. Valid values are 0 and higher.
61
+ *
62
+ * <i>conn_max</i> specifies the maximum number of connections that
63
+ * can be opened to the database. Once this value is reached, no more
64
+ * connections are opened. Valid values are 1 and higher.
65
+ * Note that this limits the number of concurent SQL executions, not
66
+ * the number of concurrent sessions.
67
+ *
68
+ * <i>conn_incr</i> allows the application to set the next increment
69
+ * for connections to be opened to the database if the current number
70
+ * of connections are less than <i>conn_max</i>. Valid values are 0
71
+ * and higher.
72
+ *
73
+ * <i>username</i> and <i>password</i> are required to establish an
74
+ * implicit primary session. When both are nil, external
75
+ * authentication is used.
76
+ *
77
+ * <i>dbname</i> specifies the database server to connect to.
78
+ *
79
+ * If the number of arguments is four, <i>username</i>,
80
+ * <i>password</i> and <i>dbname</i> are extracted from the fourth
81
+ * argument <i>connect_string</i>. The syntax is "username/password" or
82
+ * "username/password@dbname".
83
+ */
84
+ static VALUE oci8_cpool_initialize(int argc, VALUE *argv, VALUE self)
85
+ {
86
+ VALUE conn_min;
87
+ VALUE conn_max;
88
+ VALUE conn_incr;
89
+ VALUE username;
90
+ VALUE password;
91
+ VALUE dbname;
92
+ oci8_cpool_t *cpool = DATA_PTR(self);
93
+ OraText *pool_name;
94
+ sb4 pool_name_len;
95
+ sword rv;
96
+
97
+ /* check arguments */
98
+ rb_scan_args(argc, argv, "42", &conn_min, &conn_max, &conn_incr,
99
+ &username, &password, &dbname);
100
+ Check_Type(conn_min, T_FIXNUM);
101
+ Check_Type(conn_max, T_FIXNUM);
102
+ Check_Type(conn_incr, T_FIXNUM);
103
+ if (argc == 4) {
104
+ VALUE mode;
105
+ VALUE conn_str = username;
106
+
107
+ OCI8SafeStringValue(conn_str);
108
+ oci8_do_parse_connect_string(conn_str, &username, &password, &dbname, &mode);
109
+ if (!NIL_P(mode)) {
110
+ rb_raise(rb_eArgError, "invalid connect string \"%s\": Connection pooling doesn't support sysdba and sysoper privileges.", RSTRING_PTR(conn_str));
111
+ }
112
+ } else {
113
+ if (!NIL_P(username)) {
114
+ OCI8SafeStringValue(username);
115
+ }
116
+ if (!NIL_P(password)) {
117
+ OCI8SafeStringValue(password);
118
+ }
119
+ if (!NIL_P(dbname)) {
120
+ OCI8SafeStringValue(dbname);
121
+ }
122
+ }
123
+
124
+ rv = OCIHandleAlloc(oci8_envhp, &cpool->base.hp.ptr, OCI_HTYPE_CPOOL, 0, NULL);
125
+ if (rv != OCI_SUCCESS)
126
+ oci8_env_raise(oci8_envhp, rv);
127
+ cpool->base.type = OCI_HTYPE_CPOOL;
128
+
129
+ chker2(OCIConnectionPoolCreate(oci8_envhp, oci8_errhp, cpool->base.hp.poolhp,
130
+ &pool_name, &pool_name_len,
131
+ NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
132
+ NIL_P(dbname) ? 0 : RSTRING_LEN(dbname),
133
+ FIX2UINT(conn_min), FIX2UINT(conn_max),
134
+ FIX2UINT(conn_incr),
135
+ NIL_P(username) ? NULL : RSTRING_ORATEXT(username),
136
+ NIL_P(username) ? 0 : RSTRING_LEN(username),
137
+ NIL_P(password) ? NULL : RSTRING_ORATEXT(password),
138
+ NIL_P(password) ? 0 : RSTRING_LEN(password),
139
+ OCI_DEFAULT),
140
+ &cpool->base);
141
+ cpool->pool_name = rb_str_new(TO_CHARPTR(pool_name), pool_name_len);
142
+ rb_str_freeze(cpool->pool_name);
143
+ return Qnil;
144
+ }
145
+
146
+ /*
147
+ * call-seq:
148
+ * reinitialize(min, max, incr)
149
+ *
150
+ * Changes the the number of minimum connections, the number of
151
+ * maximum connections and the connection increment parameter.
152
+ */
153
+ static VALUE oci8_cpool_reinitialize(VALUE self, VALUE conn_min, VALUE conn_max, VALUE conn_incr)
154
+ {
155
+ oci8_cpool_t *cpool = DATA_PTR(self);
156
+ OraText *pool_name;
157
+ sb4 pool_name_len;
158
+
159
+ /* check arguments */
160
+ Check_Type(conn_min, T_FIXNUM);
161
+ Check_Type(conn_max, T_FIXNUM);
162
+ Check_Type(conn_incr, T_FIXNUM);
163
+
164
+ chker2(OCIConnectionPoolCreate(oci8_envhp, oci8_errhp, cpool->base.hp.poolhp,
165
+ &pool_name, &pool_name_len, NULL, 0,
166
+ FIX2UINT(conn_min), FIX2UINT(conn_max),
167
+ FIX2UINT(conn_incr),
168
+ NULL, 0, NULL, 0, OCI_CPOOL_REINITIALIZE),
169
+ &cpool->base);
170
+ return self;
171
+ }
172
+
173
+ /*
174
+ * call-seq:
175
+ * pool_name -> string
176
+ *
177
+ * <b>internal use only</b>
178
+ *
179
+ * Retruns the pool name.
180
+ */
181
+ static VALUE oci8_cpool_pool_name(VALUE self)
182
+ {
183
+ oci8_cpool_t *cpool = DATA_PTR(self);
184
+
185
+ return cpool->pool_name;
186
+ }
187
+
188
+ void Init_oci8_connection_pool(VALUE cOCI8)
189
+ {
190
+ #if 0
191
+ cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
192
+ cOCI8 = rb_define_class("OCI8", cOCIHandle);
193
+ cOCIConnectionPool = rb_define_class_under(cOCI8, "ConnectionPool", cOCIHandle);
194
+ #endif
195
+
196
+ cOCIConnectionPool = oci8_define_class_under(cOCI8, "ConnectionPool", &oci8_cpool_vtable);
197
+
198
+ rb_define_private_method(cOCIConnectionPool, "initialize", oci8_cpool_initialize, -1);
199
+ rb_define_method(cOCIConnectionPool, "reinitialize", oci8_cpool_reinitialize, 3);
200
+ rb_define_private_method(cOCIConnectionPool, "pool_name", oci8_cpool_pool_name, 0);
201
+ }
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * encoding.c - part of ruby-oci8
4
4
  *
5
- * Copyright (C) 2008 KUBO Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2008-2010 KUBO Takehiro <kubo@jiubao.org>
6
6
  *
7
7
  */
8
8
  #include "oci8.h"
@@ -11,15 +11,8 @@
11
11
  #define OCI_NLS_MAXBUFSZ 100
12
12
  #endif
13
13
 
14
- /* type of callback function's argument */
15
- typedef struct {
16
- oci8_svcctx_t *svcctx;
17
- OCIStmt *stmtp;
18
- union {
19
- VALUE name;
20
- int csid;
21
- } u;
22
- } cb_arg_t;
14
+ /* NLS ratio, maximum number of bytes per one chracter */
15
+ int oci8_nls_ratio = 1;
23
16
 
24
17
  /* Oracle charset id -> Oracle charset name */
25
18
  static VALUE csid2name;
@@ -32,6 +25,30 @@ static VALUE oci8_charset_name2id(VALUE svc, VALUE name);
32
25
  rb_encoding *oci8_encoding;
33
26
  #endif
34
27
 
28
+
29
+ /*
30
+ * call-seq:
31
+ * charset_id2name(charset_id) -> charset_name
32
+ *
33
+ * <b>(new in 2.0.0)</b>
34
+ *
35
+ * Returns the Oracle character set name from the specified
36
+ * character set ID if it is valid. Otherwise, +nil+ is returned.
37
+ *
38
+ * === Oracle 9iR2 client or upper
39
+ *
40
+ * It is done by using the mapping table stored in the client side.
41
+ *
42
+ * === Oracle 9iR1 client or lower
43
+ *
44
+ * It executes the following PL/SQL block internally to use
45
+ * the mapping table stored in the server side.
46
+ *
47
+ * BEGIN
48
+ * :name := nls_charset_name(:csid);
49
+ * END;
50
+ *
51
+ */
35
52
  VALUE oci8_charset_id2name(VALUE svc, VALUE csid)
36
53
  {
37
54
  VALUE name = rb_hash_aref(csid2name, csid);
@@ -83,6 +100,29 @@ VALUE oci8_charset_id2name(VALUE svc, VALUE csid)
83
100
  return name;
84
101
  }
85
102
 
103
+ /*
104
+ * call-seq:
105
+ * charset_name2id(charset_name) -> charset_id
106
+ *
107
+ * <b>(new in 2.0.0)</b>
108
+ *
109
+ * Returns the Oracle character set ID for the specified Oracle
110
+ * character set name if it is valid. Othewise, +nil+ is returned.
111
+ *
112
+ * === Oracle 9iR2 client or upper
113
+ *
114
+ * It is done by using the mapping table stored in the client side.
115
+ *
116
+ * === Oracle 9iR1 client or lower
117
+ *
118
+ * It executes the following PL/SQL block internally to use
119
+ * the mapping table stored in the server side.
120
+ *
121
+ * BEGIN
122
+ * :csid := nls_charset_id(:name);
123
+ * END;
124
+ *
125
+ */
86
126
  static VALUE oci8_charset_name2id(VALUE svc, VALUE name)
87
127
  {
88
128
  VALUE csid;
@@ -132,27 +172,72 @@ static VALUE oci8_charset_name2id(VALUE svc, VALUE name)
132
172
  return csid;
133
173
  }
134
174
 
175
+ /*
176
+ * call-seq:
177
+ * OCI8.nls_ratio -> integer
178
+ *
179
+ * <b>(new in 2.1.0)</b>
180
+ *
181
+ * Gets NLS ratio, maximum number of bytes per one character of the
182
+ * current NLS chracter set. It is a factor to calculate the
183
+ * internal buffer size of a string bind variable whose nls length
184
+ * semantics is char.
185
+ */
186
+ static VALUE oci8_get_nls_ratio(VALUE klass)
187
+ {
188
+ return INT2NUM(oci8_nls_ratio);
189
+ }
190
+
191
+ /*
192
+ * call-seq:
193
+ * OCI8.nls_ratio = integer
194
+ *
195
+ * <b>(new in 2.1.0)</b>
196
+ *
197
+ * Sets NLS ratio, maximum number of bytes per one character of the
198
+ * current NLS chracter set. It is initialized in 'oci8/encoding-init.rb'
199
+ * when oci8 is required. You have no need to set it explicitly.
200
+ */
201
+ static VALUE oci8_set_nls_ratio(VALUE klass, VALUE val)
202
+ {
203
+ int v = NUM2INT(val);
204
+ if (v <= 0) {
205
+ rb_raise(rb_eRangeError, "expected a positive integer but %d", v);
206
+ }
207
+ oci8_nls_ratio = v;
208
+ return val;
209
+ }
210
+
135
211
  #ifdef HAVE_TYPE_RB_ENCODING
136
212
 
137
213
  /*
138
214
  * call-seq:
139
- * OCI8.encoding -> enc
215
+ * OCI8.encoding -> enc
216
+ *
217
+ * <b>(new in 2.0.0 and ruby 1.9)</b>
140
218
  *
141
- * (new in ruby 1.9)
219
+ * Returns the Oracle client encoding.
142
220
  *
143
- * Returns Oracle client encoding.
221
+ * When string data, such as SQL statements and bind variables,
222
+ * are passed to Oracle, they are converted to +OCI8.encoding+
223
+ * in advance.
144
224
  *
145
- * String values passed to Oracle, such as SQL statements,
146
- * bind values etc., are converted from their encoding to
147
- * the Oracle client encoding.
225
+ * # When OCI8.encoding is ISO-8859-1,
226
+ * conn.exec('insert into country_code values(:1, :2, :3)',
227
+ * 'AT', 'Austria', "\u00d6sterreichs")
228
+ * # "\u00d6sterreichs" is 'Österreichs' encoded by UTF-8.
229
+ * # It is converted to ISO-8859-1 before it is passed to
230
+ * # the Oracle C API.
148
231
  *
149
- * If <code>Encoding.default_internal</code> is nil,
150
- * string values got from Oracle are tagged by
151
- * <code>OCI8.encoding</code>. If not nil, they are
152
- * converted from <code>OCI8.encoding</code> to
153
- * <code>Encoding.default_internal</code> by default.
154
232
  *
155
- * If it is 'ASCII-8BIT', no encoding conversions are done.
233
+ * When string data, such as fetched values and bind variable
234
+ * for output, are retrieved from Oracle, they are encoded
235
+ * by +OCI8.encoding+ if +Encoding.default_internal+ is +nil+.
236
+ * If it isn't +nil+, they are converted from +OCI8.encoding+
237
+ * to +Encoding.default_internal+.
238
+ *
239
+ * If +OCI8.encoding+ is ASCII-8BIT, no encoding conversions
240
+ * are done.
156
241
  */
157
242
  static VALUE oci8_get_encoding(VALUE klass)
158
243
  {
@@ -163,9 +248,11 @@ static VALUE oci8_get_encoding(VALUE klass)
163
248
  * call-seq:
164
249
  * OCI8.encoding = enc or nil
165
250
  *
166
- * (new in ruby 1.9)
251
+ * <b>(new in 2.0.0 and ruby 1.9)</b>
167
252
  *
168
- * Sets Oracle client encoding.
253
+ * Sets Oracle client encoding. You must not use this method.
254
+ * You should set the environment variable NLS_LANG properly to
255
+ * change +OCI8.encoding+.
169
256
  */
170
257
  static VALUE oci8_set_encoding(VALUE klass, VALUE encoding)
171
258
  {
@@ -180,6 +267,10 @@ static VALUE oci8_set_encoding(VALUE klass, VALUE encoding)
180
267
 
181
268
  void Init_oci8_encoding(VALUE cOCI8)
182
269
  {
270
+ #if 0
271
+ oci8_cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
272
+ cOCI8 = rb_define_class("OCI8", oci8_cOCIHandle);
273
+ #endif
183
274
  csid2name = rb_hash_new();
184
275
  rb_global_variable(&csid2name);
185
276
 
@@ -189,6 +280,8 @@ void Init_oci8_encoding(VALUE cOCI8)
189
280
 
190
281
  rb_define_method(cOCI8, "charset_name2id", oci8_charset_name2id, 1);
191
282
  rb_define_method(cOCI8, "charset_id2name", oci8_charset_id2name, 1);
283
+ rb_define_singleton_method(cOCI8, "nls_ratio", oci8_get_nls_ratio, 0);
284
+ rb_define_singleton_method(cOCI8, "nls_ratio=", oci8_set_nls_ratio, 1);
192
285
  #ifdef HAVE_TYPE_RB_ENCODING
193
286
  rb_define_singleton_method(cOCI8, "encoding", oci8_get_encoding, 0);
194
287
  rb_define_singleton_method(cOCI8, "encoding=", oci8_set_encoding, 1);
@@ -12,11 +12,7 @@
12
12
  #include <util.h>
13
13
  #endif
14
14
 
15
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
16
15
  ub4 oci8_env_mode = OCI_OBJECT | OCI_THREADED;
17
- #else
18
- ub4 oci8_env_mode = OCI_OBJECT;
19
- #endif
20
16
 
21
17
  OCIEnv *oci8_global_envhp;
22
18
 
@@ -31,9 +27,9 @@ OCIEnv *oci8_make_envhp(void)
31
27
  return oci8_global_envhp;
32
28
  }
33
29
 
34
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
30
+ #ifdef USE_THREAD_LOCAL_ERRHP
35
31
  /*
36
- * oci8_errhp is a thread local object in ruby 1.9.
32
+ * Setup thread-local oci8_errhp.
37
33
  */
38
34
 
39
35
  oci8_tls_key_t oci8_tls_key; /* native thread key */
@@ -93,7 +89,7 @@ OCIError *oci8_make_errhp(void)
93
89
  }
94
90
  #else
95
91
  /*
96
- * oci8_errhp is global in ruby 1.8.
92
+ * oci8_errhp is global in ruby 1.8 configured without --enable-pthread on Unix.
97
93
  */
98
94
  OCIError *oci8_global_errhp;
99
95
 
@@ -110,7 +106,7 @@ OCIError *oci8_make_errhp(void)
110
106
 
111
107
  void Init_oci8_env(void)
112
108
  {
113
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
109
+ #ifdef USE_THREAD_LOCAL_ERRHP
114
110
  int error;
115
111
  #endif
116
112
 
@@ -160,8 +156,7 @@ void Init_oci8_env(void)
160
156
  }
161
157
  }
162
158
 
163
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
164
- /* ruby 1.9 */
159
+ #ifdef USE_THREAD_LOCAL_ERRHP
165
160
  #if defined(_WIN32)
166
161
  if (!dllmain_is_called) {
167
162
  /* sanity check */