ruby-staci 2.2.9

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.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +14 -0
  3. data/COPYING +30 -0
  4. data/COPYING_old +64 -0
  5. data/ChangeLog +3826 -0
  6. data/Makefile +92 -0
  7. data/NEWS +1194 -0
  8. data/README.md +66 -0
  9. data/dist-files +113 -0
  10. data/docs/bind-array-to-in_cond.md +38 -0
  11. data/docs/conflicts-local-connections-and-processes.md +98 -0
  12. data/docs/hanging-after-inactivity.md +63 -0
  13. data/docs/install-binary-package.md +44 -0
  14. data/docs/install-full-client.md +111 -0
  15. data/docs/install-instant-client.md +194 -0
  16. data/docs/install-on-osx.md +133 -0
  17. data/docs/ldap-auth-and-function-interposition.md +123 -0
  18. data/docs/number-type-mapping.md +79 -0
  19. data/docs/osx-install-dev-tools.png +0 -0
  20. data/docs/platform-specific-issues.md +164 -0
  21. data/docs/report-installation-issue.md +50 -0
  22. data/docs/timeout-parameters.md +94 -0
  23. data/ext/oci8/.document +18 -0
  24. data/ext/oci8/MANIFEST +18 -0
  25. data/ext/oci8/apiwrap.c.tmpl +178 -0
  26. data/ext/oci8/apiwrap.h.tmpl +61 -0
  27. data/ext/oci8/apiwrap.rb +96 -0
  28. data/ext/oci8/apiwrap.yml +1322 -0
  29. data/ext/oci8/attr.c +57 -0
  30. data/ext/oci8/bind.c +838 -0
  31. data/ext/oci8/connection_pool.c +216 -0
  32. data/ext/oci8/encoding.c +196 -0
  33. data/ext/oci8/env.c +139 -0
  34. data/ext/oci8/error.c +385 -0
  35. data/ext/oci8/extconf.rb +219 -0
  36. data/ext/oci8/hook_funcs.c +407 -0
  37. data/ext/oci8/lob.c +1278 -0
  38. data/ext/oci8/metadata.c +279 -0
  39. data/ext/oci8/object.c +919 -0
  40. data/ext/oci8/oci8.c +1058 -0
  41. data/ext/oci8/oci8.h +556 -0
  42. data/ext/oci8/oci8lib.c +704 -0
  43. data/ext/oci8/ocidatetime.c +506 -0
  44. data/ext/oci8/ocihandle.c +852 -0
  45. data/ext/oci8/ocinumber.c +1922 -0
  46. data/ext/oci8/oraconf.rb +1145 -0
  47. data/ext/oci8/oradate.c +670 -0
  48. data/ext/oci8/oranumber_util.c +352 -0
  49. data/ext/oci8/oranumber_util.h +24 -0
  50. data/ext/oci8/plthook.h +66 -0
  51. data/ext/oci8/plthook_elf.c +702 -0
  52. data/ext/oci8/plthook_osx.c +505 -0
  53. data/ext/oci8/plthook_win32.c +391 -0
  54. data/ext/oci8/post-config.rb +5 -0
  55. data/ext/oci8/stmt.c +448 -0
  56. data/ext/oci8/thread_util.c +81 -0
  57. data/ext/oci8/thread_util.h +18 -0
  58. data/ext/oci8/util.c +71 -0
  59. data/ext/oci8/win32.c +117 -0
  60. data/lib/.document +1 -0
  61. data/lib/dbd/STACI.rb +591 -0
  62. data/lib/oci8/.document +8 -0
  63. data/lib/oci8/bindtype.rb +333 -0
  64. data/lib/oci8/check_load_error.rb +146 -0
  65. data/lib/oci8/compat.rb +117 -0
  66. data/lib/oci8/connection_pool.rb +179 -0
  67. data/lib/oci8/cursor.rb +605 -0
  68. data/lib/oci8/datetime.rb +605 -0
  69. data/lib/oci8/encoding-init.rb +45 -0
  70. data/lib/oci8/encoding.yml +537 -0
  71. data/lib/oci8/metadata.rb +2148 -0
  72. data/lib/oci8/object.rb +641 -0
  73. data/lib/oci8/oci8.rb +756 -0
  74. data/lib/oci8/ocihandle.rb +591 -0
  75. data/lib/oci8/oracle_version.rb +153 -0
  76. data/lib/oci8/properties.rb +196 -0
  77. data/lib/oci8/version.rb +3 -0
  78. data/lib/ruby-staci.rb +1 -0
  79. data/lib/staci.rb +190 -0
  80. data/metaconfig +142 -0
  81. data/pre-distclean.rb +7 -0
  82. data/ruby-aci.gemspec +83 -0
  83. data/setup.rb +1342 -0
  84. data/test/README.md +37 -0
  85. data/test/config.rb +201 -0
  86. data/test/setup_test_object.sql +199 -0
  87. data/test/setup_test_package.sql +59 -0
  88. data/test/test_all.rb +56 -0
  89. data/test/test_appinfo.rb +62 -0
  90. data/test/test_array_dml.rb +333 -0
  91. data/test/test_bind_array.rb +70 -0
  92. data/test/test_bind_boolean.rb +99 -0
  93. data/test/test_bind_integer.rb +47 -0
  94. data/test/test_bind_raw.rb +45 -0
  95. data/test/test_bind_string.rb +105 -0
  96. data/test/test_bind_time.rb +177 -0
  97. data/test/test_break.rb +124 -0
  98. data/test/test_clob.rb +86 -0
  99. data/test/test_connection_pool.rb +124 -0
  100. data/test/test_connstr.rb +220 -0
  101. data/test/test_datetime.rb +585 -0
  102. data/test/test_dbi.rb +365 -0
  103. data/test/test_dbi_clob.rb +53 -0
  104. data/test/test_encoding.rb +103 -0
  105. data/test/test_error.rb +87 -0
  106. data/test/test_metadata.rb +2674 -0
  107. data/test/test_object.rb +546 -0
  108. data/test/test_oci8.rb +624 -0
  109. data/test/test_oracle_version.rb +68 -0
  110. data/test/test_oradate.rb +255 -0
  111. data/test/test_oranumber.rb +786 -0
  112. data/test/test_package_type.rb +981 -0
  113. data/test/test_properties.rb +17 -0
  114. data/test/test_rowid.rb +32 -0
  115. metadata +158 -0
@@ -0,0 +1,216 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * connection_pool.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2010-2014 Kubo Takehiro <kubo@jiubao.org>
6
+ *
7
+ */
8
+ #include "oci8.h"
9
+
10
+ static VALUE cOCIConnectionPool;
11
+
12
+ #define TO_CPOOL(obj) ((oci8_cpool_t *)oci8_check_typeddata((obj), &oci8_cpool_data_type, 1))
13
+
14
+ typedef struct {
15
+ oci8_base_t base;
16
+ VALUE pool_name;
17
+ } oci8_cpool_t;
18
+
19
+ static void oci8_cpool_mark(oci8_base_t *base)
20
+ {
21
+ oci8_cpool_t *cpool = (oci8_cpool_t *)base;
22
+
23
+ rb_gc_mark(cpool->pool_name);
24
+ }
25
+
26
+ static void *cpool_free_thread(void *arg)
27
+ {
28
+ OCIConnectionPoolDestroy((OCICPool *)arg, oci8_errhp, OCI_DEFAULT);
29
+ OCIHandleFree(arg, OCI_HTYPE_CPOOL);
30
+ return NULL;
31
+ }
32
+
33
+ static void oci8_cpool_free(oci8_base_t *base)
34
+ {
35
+ oci8_run_native_thread(cpool_free_thread, base->hp.poolhp);
36
+ base->type = 0;
37
+ base->closed = 1;
38
+ base->hp.ptr = NULL;
39
+ }
40
+
41
+ static const oci8_handle_data_type_t oci8_cpool_data_type = {
42
+ {
43
+ "STACI::ConnectionPool",
44
+ {
45
+ (RUBY_DATA_FUNC)oci8_cpool_mark,
46
+ oci8_handle_cleanup,
47
+ oci8_handle_size,
48
+ },
49
+ &oci8_handle_data_type.rb_data_type, NULL,
50
+ #ifdef RUBY_TYPED_WB_PROTECTED
51
+ RUBY_TYPED_WB_PROTECTED,
52
+ #endif
53
+ },
54
+ oci8_cpool_free,
55
+ sizeof(oci8_cpool_t),
56
+ };
57
+
58
+ static VALUE oci8_cpool_alloc(VALUE klass)
59
+ {
60
+ VALUE self = oci8_allocate_typeddata(klass, &oci8_cpool_data_type);
61
+ oci8_cpool_t *cpool = (oci8_cpool_t *)RTYPEDDATA_DATA(self);
62
+
63
+ cpool->pool_name = Qnil;
64
+ return self;
65
+ }
66
+
67
+ /*
68
+ * call-seq:
69
+ * STACI::ConnectionPool.new(conn_min, conn_max, conn_incr, username = nil, password = nil, dbname = nil) -> connection pool
70
+ * STACI::ConnectionPool.new(conn_min, conn_max, conn_incr, connect_string) -> connection pool
71
+ *
72
+ * Creates a connection pool.
73
+ *
74
+ * <i>conn_min</i> specifies the minimum number of connections in the
75
+ * connection pool. Valid values are 0 and higher.
76
+ *
77
+ * <i>conn_max</i> specifies the maximum number of connections that
78
+ * can be opened to the database. Once this value is reached, no more
79
+ * connections are opened. Valid values are 1 and higher.
80
+ * Note that this limits the number of concurent SQL executions, not
81
+ * the number of concurrent sessions.
82
+ *
83
+ * <i>conn_incr</i> allows the application to set the next increment
84
+ * for connections to be opened to the database if the current number
85
+ * of connections are less than <i>conn_max</i>. Valid values are 0
86
+ * and higher.
87
+ *
88
+ * <i>username</i> and <i>password</i> are required to establish an
89
+ * implicit primary session. When both are nil, external
90
+ * authentication is used.
91
+ *
92
+ * <i>dbname</i> specifies the database server to connect to.
93
+ *
94
+ * If the number of arguments is four, <i>username</i>,
95
+ * <i>password</i> and <i>dbname</i> are extracted from the fourth
96
+ * argument <i>connect_string</i>. The syntax is "username/password" or
97
+ * "username/password@dbname".
98
+ */
99
+ static VALUE oci8_cpool_initialize(int argc, VALUE *argv, VALUE self)
100
+ {
101
+ VALUE conn_min;
102
+ VALUE conn_max;
103
+ VALUE conn_incr;
104
+ VALUE username;
105
+ VALUE password;
106
+ VALUE dbname;
107
+ oci8_cpool_t *cpool = TO_CPOOL(self);
108
+ OraText *pool_name = NULL;
109
+ sb4 pool_name_len = 0;
110
+ sword rv;
111
+
112
+ /* check arguments */
113
+ rb_scan_args(argc, argv, "42", &conn_min, &conn_max, &conn_incr,
114
+ &username, &password, &dbname);
115
+ Check_Type(conn_min, T_FIXNUM);
116
+ Check_Type(conn_max, T_FIXNUM);
117
+ Check_Type(conn_incr, T_FIXNUM);
118
+ if (argc == 4) {
119
+ VALUE mode;
120
+ VALUE conn_str = username;
121
+
122
+ OCI8SafeStringValue(conn_str);
123
+ oci8_do_parse_connect_string(conn_str, &username, &password, &dbname, &mode);
124
+ if (!NIL_P(mode)) {
125
+ rb_raise(rb_eArgError, "invalid connect string \"%s\": Connection pooling doesn't support sysdba and sysoper privileges.", RSTRING_PTR(conn_str));
126
+ }
127
+ } else {
128
+ if (!NIL_P(username)) {
129
+ OCI8SafeStringValue(username);
130
+ }
131
+ if (!NIL_P(password)) {
132
+ OCI8SafeStringValue(password);
133
+ }
134
+ if (!NIL_P(dbname)) {
135
+ OCI8SafeStringValue(dbname);
136
+ }
137
+ }
138
+
139
+ rv = OCIHandleAlloc(oci8_envhp, &cpool->base.hp.ptr, OCI_HTYPE_CPOOL, 0, NULL);
140
+ if (rv != OCI_SUCCESS)
141
+ oci8_env_raise(oci8_envhp, rv);
142
+ cpool->base.type = OCI_HTYPE_CPOOL;
143
+
144
+ chker2(OCIConnectionPoolCreate(oci8_envhp, oci8_errhp, cpool->base.hp.poolhp,
145
+ &pool_name, &pool_name_len,
146
+ NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
147
+ NIL_P(dbname) ? 0 : RSTRING_LEN(dbname),
148
+ FIX2UINT(conn_min), FIX2UINT(conn_max),
149
+ FIX2UINT(conn_incr),
150
+ NIL_P(username) ? NULL : RSTRING_ORATEXT(username),
151
+ NIL_P(username) ? 0 : RSTRING_LEN(username),
152
+ NIL_P(password) ? NULL : RSTRING_ORATEXT(password),
153
+ NIL_P(password) ? 0 : RSTRING_LEN(password),
154
+ OCI_DEFAULT),
155
+ &cpool->base);
156
+ RB_OBJ_WRITE(cpool->base.self, &cpool->pool_name, rb_str_new(TO_CHARPTR(pool_name), pool_name_len));
157
+ rb_str_freeze(cpool->pool_name);
158
+ return Qnil;
159
+ }
160
+
161
+ /*
162
+ * call-seq:
163
+ * reinitialize(min, max, incr)
164
+ *
165
+ * Changes the the number of minimum connections, the number of
166
+ * maximum connections and the connection increment parameter.
167
+ */
168
+ static VALUE oci8_cpool_reinitialize(VALUE self, VALUE conn_min, VALUE conn_max, VALUE conn_incr)
169
+ {
170
+ oci8_cpool_t *cpool = TO_CPOOL(self);
171
+ OraText *pool_name;
172
+ sb4 pool_name_len;
173
+
174
+ /* check arguments */
175
+ Check_Type(conn_min, T_FIXNUM);
176
+ Check_Type(conn_max, T_FIXNUM);
177
+ Check_Type(conn_incr, T_FIXNUM);
178
+
179
+ chker2(OCIConnectionPoolCreate(oci8_envhp, oci8_errhp, cpool->base.hp.poolhp,
180
+ &pool_name, &pool_name_len, NULL, 0,
181
+ FIX2UINT(conn_min), FIX2UINT(conn_max),
182
+ FIX2UINT(conn_incr),
183
+ NULL, 0, NULL, 0, OCI_CPOOL_REINITIALIZE),
184
+ &cpool->base);
185
+ return self;
186
+ }
187
+
188
+ /*
189
+ * call-seq:
190
+ * pool_name -> string
191
+ *
192
+ * Retruns the pool name.
193
+ *
194
+ * @private
195
+ */
196
+ static VALUE oci8_cpool_pool_name(VALUE self)
197
+ {
198
+ oci8_cpool_t *cpool = TO_CPOOL(self);
199
+
200
+ return cpool->pool_name;
201
+ }
202
+
203
+ void Init_oci8_connection_pool(VALUE cOCI8)
204
+ {
205
+ #if 0
206
+ cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
207
+ cOCI8 = rb_define_class("STACI", cOCIHandle);
208
+ cOCIConnectionPool = rb_define_class_under(cOCI8, "ConnectionPool", cOCIHandle);
209
+ #endif
210
+
211
+ cOCIConnectionPool = oci8_define_class_under(cOCI8, "ConnectionPool", &oci8_cpool_data_type, oci8_cpool_alloc);
212
+
213
+ rb_define_private_method(cOCIConnectionPool, "initialize", oci8_cpool_initialize, -1);
214
+ rb_define_method(cOCIConnectionPool, "reinitialize", oci8_cpool_reinitialize, 3);
215
+ rb_define_private_method(cOCIConnectionPool, "pool_name", oci8_cpool_pool_name, 0);
216
+ }
@@ -0,0 +1,196 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * encoding.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2008-2010 KUBO Takehiro <kubo@jiubao.org>
6
+ *
7
+ */
8
+ #include "oci8.h"
9
+
10
+ #ifndef OCI_NLS_MAXBUFSZ
11
+ #define OCI_NLS_MAXBUFSZ 100
12
+ #endif
13
+
14
+ /* NLS ratio, maximum number of bytes per one chracter */
15
+ int oci8_nls_ratio = 1;
16
+
17
+ rb_encoding *oci8_encoding;
18
+
19
+ /*
20
+ * call-seq:
21
+ * charset_id2name(charset_id) -> charset_name
22
+ *
23
+ * Returns the Oracle character set name from the specified
24
+ * character set ID if it is valid. Otherwise, +nil+ is returned.
25
+ *
26
+ * @param [Integer] charset_id Oracle character set id
27
+ * @return [String] Oracle character set name or nil
28
+ * @since 2.2.0
29
+ */
30
+ VALUE oci8_s_charset_id2name(VALUE klass, VALUE csid)
31
+ {
32
+ char buf[OCI_NLS_MAXBUFSZ];
33
+ sword rv;
34
+
35
+ Check_Type(csid, T_FIXNUM);
36
+ rv = OCINlsCharSetIdToName(oci8_envhp, TO_ORATEXT(buf), sizeof(buf), (ub2)FIX2INT(csid));
37
+ if (rv != OCI_SUCCESS) {
38
+ return Qnil;
39
+ }
40
+ return rb_usascii_str_new_cstr(buf);
41
+ }
42
+
43
+ /*
44
+ * call-seq:
45
+ * charset_name2id(charset_name) -> charset_id
46
+ *
47
+ * Returns the Oracle character set ID for the specified Oracle
48
+ * character set name if it is valid. Othewise, +nil+ is returned.
49
+ *
50
+ * @param [String] charset_name Oracle character set name
51
+ * @return [Integer] Oracle character set id or nil
52
+ * @since 2.2.0
53
+ */
54
+ static VALUE oci8_s_charset_name2id(VALUE klass, VALUE name)
55
+ {
56
+ ub2 rv;
57
+
58
+ rv = OCINlsCharSetNameToId(oci8_envhp, TO_ORATEXT(StringValueCStr(name)));
59
+ if (rv == 0) {
60
+ return Qnil;
61
+ }
62
+ return INT2FIX(rv);
63
+ }
64
+
65
+ /*
66
+ * call-seq:
67
+ * STACI.nls_ratio -> integer
68
+ *
69
+ * Gets NLS ratio, maximum number of bytes per one character of the
70
+ * current NLS chracter set. It is a factor to calculate the
71
+ * internal buffer size of a string bind variable whose nls length
72
+ * semantics is char.
73
+ *
74
+ * @return [Integer] NLS ratio
75
+ * @since 2.1.0
76
+ * @private
77
+ */
78
+ static VALUE oci8_get_nls_ratio(VALUE klass)
79
+ {
80
+ return INT2NUM(oci8_nls_ratio);
81
+ }
82
+
83
+ /*
84
+ * call-seq:
85
+ * STACI.encoding -> enc
86
+ *
87
+ * Returns the Oracle client encoding.
88
+ *
89
+ * When string data, such as SQL statements and bind variables,
90
+ * are passed to Oracle, they are converted to +STACI.encoding+
91
+ * in advance.
92
+ *
93
+ * @example
94
+ * # When STACI.encoding is ISO-8859-1,
95
+ * conn.exec('insert into country_code values(:1, :2, :3)',
96
+ * 'AT', 'Austria', "\u00d6sterreichs")
97
+ * # "\u00d6sterreichs" is 'Österreichs' encoded by UTF-8.
98
+ * # It is converted to ISO-8859-1 before it is passed to
99
+ * # the Oracle C API.
100
+ *
101
+ *
102
+ * When string data, such as fetched values and bind variable
103
+ * for output, are retrieved from Oracle, they are encoded
104
+ * by +STACI.encoding+ if +Encoding.default_internal+ is +nil+.
105
+ * If it isn't +nil+, they are converted from +STACI.encoding+
106
+ * to +Encoding.default_internal+.
107
+ *
108
+ * If +STACI.encoding+ is ASCII-8BIT, no encoding conversions
109
+ * are done.
110
+ *
111
+ * @return [Encoding]
112
+ * @since 2.0.0 and ruby 1.9
113
+ * @private
114
+ * @see STACI.client_charset_name
115
+ */
116
+ static VALUE oci8_get_encoding(VALUE klass)
117
+ {
118
+ return rb_enc_from_encoding(oci8_encoding);
119
+ }
120
+
121
+ /*
122
+ * call-seq:
123
+ * STACI.encoding = enc or nil
124
+ *
125
+ * Sets Oracle client encoding. You must not use this method.
126
+ * You should set the environment variable NLS_LANG properly to
127
+ * change +STACI.encoding+.
128
+ *
129
+ * @param [Encoding] enc
130
+ * @since 2.0.0 and ruby 1.9
131
+ * @private
132
+ */
133
+ static VALUE oci8_set_encoding(VALUE klass, VALUE encoding)
134
+ {
135
+ if (NIL_P(encoding)) {
136
+ oci8_encoding = NULL;
137
+ oci8_nls_ratio = 1;
138
+ } else {
139
+ oci8_encoding = rb_to_encoding(encoding);
140
+ oci8_nls_ratio = rb_enc_mbmaxlen(oci8_encoding);
141
+ }
142
+ return encoding;
143
+ }
144
+
145
+ /*
146
+ * call-seq:
147
+ * charset_name2id(charset_name) -> charset_id
148
+ *
149
+ * Returns the Oracle character set ID for the specified Oracle
150
+ * character set name if it is valid. Othewise, +nil+ is returned.
151
+ *
152
+ * @param [String] charset_name Oracle character set name
153
+ * @return [Integer] Oracle character set id or nil
154
+ * @since 2.0.0
155
+ * @deprecated Use {STACI.charset_name2id} instead.
156
+ */
157
+ static VALUE oci8_charset_name2id(VALUE svc, VALUE name)
158
+ {
159
+ rb_warning("Use STACI.charset_name2id instead of STACI#charset_name2id.");
160
+ return oci8_s_charset_name2id(Qnil, name);
161
+ }
162
+
163
+ /*
164
+ * call-seq:
165
+ * charset_id2name(charset_id) -> charset_name
166
+ *
167
+ * Returns the Oracle character set name from the specified
168
+ * character set ID if it is valid. Otherwise, +nil+ is returned.
169
+ *
170
+ * @param [Integer] charset_id Oracle character set id
171
+ * @return [String] Oracle character set name or nil
172
+ * @since 2.0.0
173
+ * @deprecated Use {STACI.charset_id2name} instead.
174
+ */
175
+ static VALUE oci8_charset_id2name(VALUE svc, VALUE name)
176
+ {
177
+ rb_warning("Use STACI.charset_id2name instead of STACI#charset_id2name.");
178
+ return oci8_s_charset_id2name(Qnil, name);
179
+ }
180
+
181
+
182
+ void Init_oci8_encoding(VALUE cOCI8)
183
+ {
184
+ #if 0
185
+ oci8_cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
186
+ cOCI8 = rb_define_class("STACI", oci8_cOCIHandle);
187
+ #endif
188
+
189
+ rb_define_singleton_method(cOCI8, "charset_name2id", oci8_s_charset_name2id, 1);
190
+ rb_define_singleton_method(cOCI8, "charset_id2name", oci8_s_charset_id2name, 1);
191
+ rb_define_singleton_method(cOCI8, "nls_ratio", oci8_get_nls_ratio, 0);
192
+ rb_define_singleton_method(cOCI8, "encoding", oci8_get_encoding, 0);
193
+ rb_define_singleton_method(cOCI8, "encoding=", oci8_set_encoding, 1);
194
+ rb_define_method(cOCI8, "charset_name2id", oci8_charset_name2id, 1);
195
+ rb_define_method(cOCI8, "charset_id2name", oci8_charset_id2name, 1);
196
+ }
data/ext/oci8/env.c ADDED
@@ -0,0 +1,139 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * env.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
6
+ */
7
+ #include "oci8.h"
8
+ #include <ruby/util.h>
9
+ #include <aci.h>
10
+
11
+ ub4 oci8_env_mode = OCI_OBJECT | OCI_THREADED;
12
+
13
+ OCIEnv *oci8_global_envhp;
14
+
15
+ OCIEnv *oci8_make_envhp(void)
16
+ {
17
+ sword rv;
18
+ OCIEnv *envhp = NULL;
19
+
20
+ rv = OCIEnvCreate(&envhp, oci8_env_mode, NULL, NULL, NULL, NULL, 0, NULL);
21
+ if (rv != OCI_SUCCESS) {
22
+ if (envhp != NULL) {
23
+ oci8_env_free_and_raise(envhp, rv);
24
+ } else {
25
+ oci8_raise_init_error();
26
+ }
27
+ }
28
+ oci8_global_envhp = envhp;
29
+ return oci8_global_envhp;
30
+ }
31
+
32
+ /*
33
+ * Setup thread-local oci8_errhp.
34
+ */
35
+
36
+ oci8_tls_key_t oci8_tls_key; /* native thread key */
37
+
38
+ /* This function is called on the native thread termination
39
+ * if the thread local errhp is not null.
40
+ */
41
+ static void oci8_free_errhp(void *errhp)
42
+ {
43
+ OCIHandleFree(errhp, OCI_HTYPE_ERROR);
44
+ }
45
+
46
+ #ifdef _WIN32
47
+ static int dllmain_is_called;
48
+
49
+ __declspec(dllexport)
50
+ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
51
+ {
52
+ void *errhp;
53
+
54
+ switch (fdwReason) {
55
+ case DLL_PROCESS_ATTACH:
56
+ dllmain_is_called = 1;
57
+ break;
58
+ case DLL_THREAD_ATTACH:
59
+ /* do nothing */
60
+ break;
61
+ case DLL_THREAD_DETACH:
62
+ errhp = oci8_tls_get(oci8_tls_key);
63
+ if (errhp != NULL) {
64
+ oci8_free_errhp(errhp);
65
+ }
66
+ break;
67
+ case DLL_PROCESS_DETACH:
68
+ /* do nothing */
69
+ break;
70
+ }
71
+ return TRUE;
72
+ }
73
+ #endif
74
+
75
+ ACIError *oci8_make_errhp(void)
76
+ {
77
+ ACIError *errhp;
78
+ sword rv;
79
+
80
+ /* create a new errhp. */
81
+ rv = OCIHandleAlloc(oci8_envhp, (dvoid *)&errhp, OCI_HTYPE_ERROR, 0, NULL);
82
+ if (rv != OCI_SUCCESS) {
83
+ oci8_env_raise(oci8_envhp, rv);
84
+ }
85
+ /* Set the errhp to the thread local storage.
86
+ * It is freed by oci8_free_errhp().
87
+ */
88
+ oci8_tls_set(oci8_tls_key, (void*)errhp);
89
+ return errhp;
90
+ }
91
+
92
+ void Init_oci8_env(void)
93
+ {
94
+ int error;
95
+
96
+ /* workaround code.
97
+ *
98
+ * When ORACLE_HOME ends with '/' and the Oracle client is
99
+ * an instant client lower than 10.2.0.3, OCIEvnCreate()
100
+ * doesn't work even though the combination of OCIInitialize()
101
+ * and OCIEnvInit() works fine. Delete the last slash for
102
+ * a workaround.
103
+ */
104
+ if (oracle_client_version < ORAVERNUM(10, 2, 0, 3, 0)) {
105
+ #ifdef _WIN32
106
+ #define DIR_SEP '\\'
107
+ #else
108
+ #define DIR_SEP '/'
109
+ #endif
110
+ char *home = getenv("ORACLE_HOME");
111
+ if (home != NULL) {
112
+ size_t homelen = strlen(home);
113
+ if (homelen > 0 && home[homelen - 1] == DIR_SEP) {
114
+ home = ruby_strdup(home);
115
+ home[homelen - 1] = '\0';
116
+ ruby_setenv("ORACLE_HOME", home);
117
+ xfree(home);
118
+ }
119
+ }
120
+ }
121
+
122
+ #if defined(_WIN32)
123
+ if (!dllmain_is_called) {
124
+ /* sanity check */
125
+ rb_raise(rb_eRuntimeError, "DllMain is not unexpectedly called. This causes resource leaks.");
126
+ }
127
+ oci8_tls_key = TlsAlloc();
128
+ if (oci8_tls_key == 0xFFFFFFFF) {
129
+ error = GetLastError();
130
+ } else {
131
+ error = 0;
132
+ }
133
+ #else
134
+ error = pthread_key_create(&oci8_tls_key, oci8_free_errhp);
135
+ #endif
136
+ if (error != 0) {
137
+ rb_raise(rb_eRuntimeError, "Cannot create thread local key (errno = %d)", error);
138
+ }
139
+ }