ruby-oci8 2.2.5.1 → 2.2.6

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,71 @@
1
+ 2018-08-22 Kubo Takehiro <kubo@jiubao.org>
2
+ * NEWS: Add changes between 2.2.5.1 and 2.2.6
3
+ * lib/oci8/version.rb: Update to 2.2.6
4
+ * mkpkg-win32.rb: Don't test with self-build ruby 2.4.
5
+
6
+ 2018-08-22 Kubo Takehiro <kubo@jiubao.org>
7
+ * ext/oci8/oci8lib.c: Load a Oracle client library which doesn't have
8
+ version number suffix also on Unix when runtime-check is enabled.
9
+ Oracle version numbers are incremented yearly sice Oracle 18c.
10
+
11
+ 2018-08-22 Kubo Takehiro <kubo@jiubao.org>
12
+ * ext/oci8/hook_funcs.c, ext/oci8/win32.c: Suppress warnings:
13
+ "'raise_error' defined but not used" and "'strncpy' specified
14
+ bound 512 equals destination size".
15
+
16
+ 2018-08-19 Kubo Takehiro <kubo@jiubao.org>
17
+ * ext/oci8/hook_funcs.c: Not depend on Oracle version number
18
+ of Oracle client file name suffix when hooking functions.
19
+ (rsim/oracle-enhanced#1754)
20
+ * test/test_all.rb, test/test_properties.rb, dist-files:
21
+ Add tests for hooking.
22
+
23
+ 2018-08-18 Kubo Takehiro <kubo@jiubao.org>
24
+ * test/test_oci8.rb: Fix to pass a test when the client is 11g
25
+ and the server is 18c. client_driver in v$session_connect_info
26
+ has an extra space at the end.
27
+
28
+ 2018-08-18 Kubo Takehiro <kubo@jiubao.org>
29
+ * ext/oci8/apiwrap.rb, ext/oci8/apiwrap.yml, ext/oci8/oci8.c,
30
+ ext/oci8/oci8.h, lib/oci8/oci8.rb, lib/oci8/oracle_version.rb,
31
+ test/test_oci8.rb: Fix OCI8#oracle_server_version to get
32
+ full version of Oracle 18c.
33
+
34
+ 2018-08-18 Kubo Takehiro <kubo@jiubao.org>
35
+ * lib/oci8/metadata.rb: Update doc comments of OCI8::Metadata::ArgBase#level
36
+ and OCI8::Metadata::ArgBase#arguments.
37
+ * test/test_package_type.rb, lib/oci8.rb: Fix to pass tests on Oracle 18c.
38
+ Detailed user-defined type information used in arguments isn't available
39
+ on Oracle 18c.
40
+
41
+ 2018-08-12 Kubo Takehiro <kubo@jiubao.org>
42
+ * test/test_clob.rb: Skip TestCLob#test_github_issue_20 because it
43
+ takes 4 minutes to test it in my Linux box.
44
+
45
+ 2018-08-12 Kubo Takehiro <kubo@jiubao.org>
46
+ * ext/oci8/lob.c, test/test_clob.rb: LOB#sync, LOB#sync= and LOB#flush
47
+ do nothing now. They have not worked by mistake from the beginning
48
+ because incorrect arguments has been passed to OCILobOpen().
49
+ Moreover it crashed Oracle 18c server-side processes and caused
50
+ "ORA-03113: end-of-file on communication channel."
51
+ (github issue #198)
52
+
53
+ 2018-01-28 Kubo Takehiro <kubo@jiubao.org>
54
+ * ext/oci8/object.c, lib/oci8/object.rb: Add timestamp with time zone
55
+ data type support in object type attributes.
56
+ (github issue #185)
57
+ * test/setup_test_object.sql, test/test_object.rb: Add tests for
58
+ timestamp and timestamp with time zone.
59
+
60
+ 2018-01-23 Kubo Takehiro <kubo@jiubao.org>
61
+ * ext/oci8/object.c, ext/oci8/oci8.h, lib/oci8/object.rb:
62
+ Add timestamp data type support in object type attributes.
63
+ (github issue #185)
64
+
65
+ 2017-12-27 Kubo Takehiro <kubo@jiubao.org>
66
+ * mkpkg-win32.rb: Remove '-rubygems' in the command line to run tests.
67
+ `ubygems.rb` was removed in ruby 2.5.
68
+
1
69
  2017-12-27 Kubo Takehiro <kubo@jiubao.org>
2
70
  * NEWS: Add changes between 2.2.5 and 2.2.5.1
3
71
  * lib/oci8/version.rb: Update to 2.2.5.1
data/NEWS CHANGED
@@ -1,5 +1,44 @@
1
1
  # @markup markdown
2
2
 
3
+ 2.2.6
4
+ =====
5
+
6
+ This release fixed issues about Oracle 18c except one.
7
+
8
+ Fixed issue
9
+ -----------
10
+
11
+ ### Setting some properties failed with Oracle 18c client
12
+
13
+ Setting `OCI8::properties[:tcp_keepalive_time]` or `OCI8::properties[:cancel_read_at_exit]`
14
+ failed with the error message "No shared library is found to hook" when Oracle
15
+ client version is 18c.
16
+ (rsim/oracle-enhanced#1754)
17
+
18
+ ### Fix `OCI8#oracle_server_version` to get full version of Oracle 18c
19
+
20
+ `OCI8#oracle_server_version` returned Oracle version number whose
21
+ number components after the first dot are zeros such as '18.0.0.0.0'
22
+ even when the server version is `18.3.0.0.0`. This issue was fixed by
23
+ using a new OCI function. However the function is available since
24
+ Oracle 18c client. So when the Oracle client version is 12c or earlier
25
+ and the Oracle server version is 18c or later, it cannot get the *full*
26
+ Oracle version number.
27
+
28
+ ### Fix tests when the Oracle server version is 18c.
29
+
30
+ ### LOB#sync, LOB#sync= and LOB#flush do nothing now.
31
+
32
+ They have not worked by mistake from the beginning because incorrect
33
+ arguments has been passed to OCILobOpen(). Moreover it crashed Oracle
34
+ 18c server-side processes and caused "ORA-03113: end-of-file on
35
+ communication channel."
36
+ (github issue #198)
37
+
38
+ ### `unsupported typecode timestamp` when timestamp with time zone is in object type attributes.
39
+
40
+ (github issue #185)
41
+
3
42
  2.2.5.1
4
43
  =======
5
44
 
data/README.md CHANGED
@@ -2,7 +2,7 @@ Ruby-oci8
2
2
  =========
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/ruby-oci8.svg)](http://badge.fury.io/rb/ruby-oci8)
5
- [![Circle CI](https://circleci.com/gh/kubo/ruby-oci8.png?style=shield)](https://circleci.com/gh/kubo/ruby-oci8)
5
+ [![Build Status](https://travis-ci.org/kubo/ruby-oci8.svg?branch=master)](https://travis-ci.org/kubo/ruby-oci8)
6
6
 
7
7
  What is ruby-oci8
8
8
  -----------------
data/dist-files CHANGED
@@ -109,4 +109,5 @@ test/test_oracle_version.rb
109
109
  test/test_oradate.rb
110
110
  test/test_oranumber.rb
111
111
  test/test_package_type.rb
112
+ test/test_properties.rb
112
113
  test/test_rowid.rb
@@ -39,7 +39,7 @@ Download the following packages from [Oracle Technology Network][]
39
39
 
40
40
  * Instant Client Package - Basic (`instantclient-basic-macos.x64-12.1.0.2.0.zip`) or Basic Lite (`instantclient-basiclite-macos.x64-12.1.0.2.0.zip`)
41
41
  * Instant Client Package - SDK (`instantclient-sdk-macos.x64-12.1.0.2.0.zip`)
42
- * Instant Client Package - SQL*Plus (`instantclient-sdk-macos.x64-12.1.0.2.0.zip`) (optionally)
42
+ * Instant Client Package - SQL*Plus (`instantclient-sqlplus-macos.x64-12.1.0.2.0.zip`) (optionally)
43
43
 
44
44
  ### Install Oracle Instant Client Packages via Homebrew
45
45
 
data/ext/oci8/apiwrap.rb CHANGED
@@ -35,7 +35,11 @@ class FuncDef
35
35
  ver_major = (ver / 100)
36
36
  ver_minor = (ver / 10) % 10
37
37
  ver_update = ver % 10
38
- @version = ((ver_major << 24) | (ver_minor << 20) | (ver_update << 12))
38
+ @version = if ver_major >= 18
39
+ ((ver_major << 24) | (ver_minor << 16) | (ver_update << 12))
40
+ else
41
+ ((ver_major << 24) | (ver_minor << 20) | (ver_update << 12))
42
+ end
39
43
  case @version
40
44
  when 0x08000000; @version_num = 'ORAVER_8_0'
41
45
  when 0x08100000; @version_num = 'ORAVER_8_1'
@@ -44,6 +48,7 @@ class FuncDef
44
48
  when 0x0a100000; @version_num = 'ORAVER_10_1'
45
49
  when 0x0a200000; @version_num = 'ORAVER_10_2'
46
50
  when 0x0b100000; @version_num = 'ORAVER_11_1'
51
+ when 0x12000000; @version_num = 'ORAVER_18'
47
52
  end
48
53
  @version_str = "#{ver_major}.#{ver_minor}.#{ver_update}"
49
54
  @ret = val[:ret] || 'sword'
data/ext/oci8/apiwrap.yml CHANGED
@@ -1286,3 +1286,17 @@ OCIPing_nb:
1286
1286
  - OCISvcCtx *svchp
1287
1287
  - OCIError *errhp
1288
1288
  - ub4 mode
1289
+
1290
+ #
1291
+ # Oracle 18.1
1292
+ #
1293
+ OCIServerRelease2:
1294
+ :version: 1800
1295
+ :args:
1296
+ - dvoid *hndlp
1297
+ - OCIError *errhp
1298
+ - OraText *bufp
1299
+ - ub4 bufsz
1300
+ - ub1 hndltype
1301
+ - ub4 *version
1302
+ - ub4 mode
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * hook.c
4
4
  *
5
- * Copyright (C) 2015 Kubo Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2015-2018 Kubo Takehiro <kubo@jiubao.org>
6
6
  */
7
7
  #if defined(_WIN32) || defined(__CYGWIN__)
8
8
  #define WINDOWS
@@ -12,15 +12,19 @@
12
12
  #include "plthook.h"
13
13
  #ifdef __CYGWIN__
14
14
  #undef boolean /* boolean defined in oratypes.h coflicts with that in windows.h */
15
+ #define stricmp strcasecmp
16
+ #define strnicmp strncasecmp
15
17
  #endif
16
18
  #ifdef WINDOWS
17
19
  #include <windows.h>
18
20
  #include <mstcpip.h>
21
+ #include <tlhelp32.h>
19
22
  #else
20
23
  #include <unistd.h>
21
24
  #include <sys/socket.h>
22
25
  #include <netinet/in.h>
23
26
  #include <netinet/tcp.h>
27
+ #include <dlfcn.h>
24
28
  #endif
25
29
 
26
30
  #ifdef WINDOWS
@@ -59,6 +63,7 @@ static int WSAAPI hook_setsockopt(SOCKET sockfd, int level, int optname, const v
59
63
  int oci8_tcp_keepalive_time = -1;
60
64
  #endif
61
65
 
66
+ static char hook_errmsg[512];
62
67
 
63
68
  typedef struct {
64
69
  const char *func_name;
@@ -95,35 +100,35 @@ static void socket_entry_clear(socket_entry_t *entry)
95
100
  UNLOCK(&lock);
96
101
  }
97
102
 
98
- static int replace_functions(const char * const *files, hook_func_entry_t *functions)
103
+ static int replace_functions(void *addr, const char *file, hook_func_entry_t *functions)
99
104
  {
105
+ plthook_t *ph;
100
106
  int i;
107
+ int rv = 0;
101
108
 
102
- for (i = 0; files[i] != NULL; i++) {
103
- const char *file = files[i];
104
- plthook_t *ph;
105
- if (plthook_open(&ph, file) == 0) {
106
- int j;
107
- int rv = 0;
108
-
109
- /* install hooks */
110
- for (j = 0; functions[j].func_name != NULL ; j++) {
111
- hook_func_entry_t *function = &functions[j];
112
- rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
113
- if (rv != 0) {
114
- while (--j >= 0) {
115
- /*restore hooked fuction address */
116
- plthook_replace(ph, functions[j].func_name, functions[j].old_func_addr, NULL);
117
- }
118
- plthook_close(ph);
119
- rb_raise(rb_eRuntimeError, "Could not replace function %s in %s", function->func_name, file);
120
- }
109
+ if (plthook_open_by_address(&ph, addr) != 0) {
110
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
111
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
112
+ return -1;
113
+ }
114
+
115
+ /* install hooks */
116
+ for (i = 0; functions[i].func_name != NULL ; i++) {
117
+ hook_func_entry_t *function = &functions[i];
118
+ rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
119
+ if (rv != 0) {
120
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
121
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
122
+ while (--i >= 0) {
123
+ /*restore hooked fuction address */
124
+ plthook_replace(ph, functions[i].func_name, functions[i].old_func_addr, NULL);
121
125
  }
122
- plthook_close(ph);
123
- return 0;
126
+ snprintf(hook_errmsg, sizeof(hook_errmsg), "Could not replace function %s in %s", function->func_name, file);
127
+ break;
124
128
  }
125
129
  }
126
- return -1;
130
+ plthook_close(ph);
131
+ return rv;
127
132
  }
128
133
 
129
134
  #ifdef WINDOWS
@@ -142,23 +147,6 @@ static int locK_is_initialized;
142
147
 
143
148
  static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
144
149
 
145
- static const char * const tcp_func_files[] = {
146
- /* full client */
147
- "orantcp12.dll",
148
- "orantcp11.dll",
149
- "orantcp10.dll",
150
- "orantcp9.dll",
151
- /* instant client basic */
152
- "oraociei12.dll",
153
- "oraociei11.dll",
154
- "oraociei10.dll",
155
- /* instant client basic lite */
156
- "oraociicus12.dll",
157
- "oraociicus11.dll",
158
- "oraociicus10.dll",
159
- NULL,
160
- };
161
-
162
150
  static hook_func_entry_t tcp_functions[] = {
163
151
  {"WSARecv", (void*)hook_WSARecv, NULL},
164
152
  {"setsockopt", (void*)hook_setsockopt, NULL},
@@ -190,6 +178,9 @@ void oci8_install_hook_functions()
190
178
  DWORD data;
191
179
  DWORD cbData = sizeof(data);
192
180
  const char *reg_key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
181
+ HANDLE hSnapshot;
182
+ MODULEENTRY32 me;
183
+ BOOL module_found = FALSE;
193
184
 
194
185
  if (hook_functions_installed) {
195
186
  return;
@@ -222,7 +213,32 @@ void oci8_install_hook_functions()
222
213
  }
223
214
  RegCloseKey(hKey);
224
215
 
225
- if (replace_functions(tcp_func_files, tcp_functions) != 0) {
216
+ hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
217
+ me.dwSize = sizeof(me);
218
+ if (Module32First(hSnapshot, &me)) {
219
+ do {
220
+ const char *p = NULL;
221
+ if (strnicmp(me.szModule, "orantcp", 7) == 0) { // ORACLE_HOME-based client
222
+ p = me.szModule + 7;
223
+ } else if (strnicmp(me.szModule, "oraociei", 8) == 0) { // instant client basic
224
+ p = me.szModule + 8;
225
+ } else if (strnicmp(me.szModule, "oraociicus", 10) == 0) { // instant client basic lite
226
+ p = me.szModule + 10;
227
+ }
228
+ if (p != NULL && ('1' <= *p && *p <= '9') && ('0' <= *(p + 1) && *(p + 1) <= '9')
229
+ && stricmp(p + 2, ".dll") == 0) {
230
+ if (GetProcAddress((HMODULE)me.modBaseAddr, "nttini") != NULL) {
231
+ module_found = TRUE;
232
+ if (replace_functions(me.modBaseAddr, me.szExePath, tcp_functions) != 0) {
233
+ CloseHandle(hSnapshot);
234
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
235
+ }
236
+ }
237
+ }
238
+ } while (Module32Next(hSnapshot, &me));
239
+ }
240
+ CloseHandle(hSnapshot);
241
+ if (!module_found) {
226
242
  rb_raise(rb_eRuntimeError, "No DLL is found to hook.");
227
243
  }
228
244
  hook_functions_installed = 1;
@@ -241,20 +257,6 @@ static void shutdown_socket(socket_entry_t *entry)
241
257
  #else
242
258
  static ssize_t hook_read(int fd, void *buf, size_t count);
243
259
 
244
- #ifdef __APPLE__
245
- #define SO_EXT "dylib"
246
- #else
247
- #define SO_EXT "so"
248
- #endif
249
-
250
- static const char * const files[] = {
251
- "libclntsh." SO_EXT ".12.1",
252
- "libclntsh." SO_EXT ".11.1",
253
- "libclntsh." SO_EXT ".10.1",
254
- "libclntsh." SO_EXT ".9.0",
255
- NULL,
256
- };
257
-
258
260
  static hook_func_entry_t functions[] = {
259
261
  {"read", (void*)hook_read, NULL},
260
262
  #ifdef SUPPORT_TCP_KEEPALIVE_TIME
@@ -279,16 +281,44 @@ static ssize_t hook_read(int fd, void *buf, size_t count)
279
281
  return rv;
280
282
  }
281
283
 
284
+ static void *ocifunc_addr(void *dlsym_handle, const char **file)
285
+ {
286
+ void *addr = dlsym(dlsym_handle, "OCIEnvCreate");
287
+ Dl_info dli;
288
+
289
+ if (addr == NULL) {
290
+ return NULL;
291
+ }
292
+ if (dladdr(addr, &dli) == 0) {
293
+ return NULL;
294
+ }
295
+ if (strstr(dli.dli_fname, "/libclntsh.so") == 0) {
296
+ return NULL;
297
+ }
298
+ *file = dli.dli_fname;
299
+ return addr;
300
+ }
301
+
282
302
  void oci8_install_hook_functions(void)
283
303
  {
284
304
  static int hook_functions_installed = 0;
305
+ void *addr;
306
+ const char *file;
285
307
 
286
308
  if (hook_functions_installed) {
287
309
  return;
288
310
  }
289
- if (replace_functions(files, functions) != 0) {
311
+ addr = ocifunc_addr(RTLD_DEFAULT, &file);
312
+ if (addr == NULL) {
313
+ /* OCI symbols may be hooked by LD_PRELOAD. */
314
+ addr = ocifunc_addr(RTLD_NEXT, &file);
315
+ }
316
+ if (addr == NULL) {
290
317
  rb_raise(rb_eRuntimeError, "No shared library is found to hook.");
291
318
  }
319
+ if (replace_functions(addr, file, functions) != 0) {
320
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
321
+ }
292
322
  hook_functions_installed = 1;
293
323
  }
294
324
 
data/ext/oci8/lob.c CHANGED
@@ -26,8 +26,6 @@ static VALUE seek_end;
26
26
 
27
27
  enum state {
28
28
  S_NO_OPEN_CLOSE,
29
- S_OPEN,
30
- S_CLOSE,
31
29
  S_BFILE_CLOSE,
32
30
  S_BFILE_OPEN,
33
31
  };
@@ -266,28 +264,6 @@ static ub8 oci8_lob_get_length(oci8_lob_t *lob)
266
264
  return len;
267
265
  }
268
266
 
269
- static void lob_open(oci8_lob_t *lob)
270
- {
271
- if (lob->state == S_CLOSE) {
272
- oci8_svcctx_t *svcctx = check_svcctx(lob);
273
-
274
- chker2(OCILobOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_DEFAULT),
275
- &svcctx->base);
276
- lob->state = S_OPEN;
277
- }
278
- }
279
-
280
- static void lob_close(oci8_lob_t *lob)
281
- {
282
- if (lob->state == S_OPEN) {
283
- oci8_svcctx_t *svcctx = check_svcctx(lob);
284
-
285
- chker2(OCILobClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob),
286
- &svcctx->base);
287
- lob->state = S_CLOSE;
288
- }
289
- }
290
-
291
267
  static void bfile_close(oci8_lob_t *lob)
292
268
  {
293
269
  if (lob->state == S_BFILE_OPEN) {
@@ -368,7 +344,6 @@ static void bfile_close(oci8_lob_t *lob)
368
344
  static VALUE oci8_lob_close(VALUE self)
369
345
  {
370
346
  oci8_lob_t *lob = TO_LOB(self);
371
- lob_close(lob);
372
347
  oci8_base_free(&lob->base);
373
348
  return self;
374
349
  }
@@ -591,7 +566,6 @@ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
591
566
  oci8_lob_t *lob = TO_LOB(self);
592
567
  oci8_svcctx_t *svcctx = check_svcctx(lob);
593
568
 
594
- lob_open(lob);
595
569
  chker2(OCILobTrim2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2ULL(len)),
596
570
  &svcctx->base);
597
571
  return self;
@@ -740,7 +714,6 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
740
714
  } while (rv == OCI_NEED_DATA);
741
715
 
742
716
  if (pos >= lob_length) {
743
- lob_close(lob);
744
717
  bfile_close(lob);
745
718
  }
746
719
  lob->pos = pos;
@@ -781,7 +754,6 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
781
754
  ub8 byte_amt;
782
755
  ub8 char_amt;
783
756
 
784
- lob_open(lob);
785
757
  if (TYPE(data) != T_STRING) {
786
758
  str = rb_obj_as_string(data);
787
759
  } else {
@@ -809,40 +781,32 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
809
781
  }
810
782
 
811
783
  /*
812
- * @deprecated I'm not sure that this is what the name indicates.
784
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
813
785
  * @private
814
786
  */
815
787
  static VALUE oci8_lob_get_sync(VALUE self)
816
788
  {
817
- oci8_lob_t *lob = TO_LOB(self);
818
- return (lob->state == S_NO_OPEN_CLOSE) ? Qtrue : Qfalse;
789
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
790
+ return Qfalse;
819
791
  }
820
792
 
821
793
  /*
822
- * @deprecated I'm not sure that this is what the name indicates.
794
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
823
795
  * @private
824
796
  */
825
797
  static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
826
798
  {
827
- oci8_lob_t *lob = TO_LOB(self);
828
- if (RTEST(b)) {
829
- lob_close(lob);
830
- lob->state = S_NO_OPEN_CLOSE;
831
- } else {
832
- if (lob->state == S_NO_OPEN_CLOSE)
833
- lob->state = S_CLOSE;
834
- }
799
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
835
800
  return b;
836
801
  }
837
802
 
838
803
  /*
839
- * @deprecated I'm not sure that this is what the name indicates.
804
+ * @deprecated LOB#flush had not worked by mistake. Do nothing now.
840
805
  * @private
841
806
  */
842
807
  static VALUE oci8_lob_flush(VALUE self)
843
808
  {
844
- oci8_lob_t *lob = TO_LOB(self);
845
- lob_close(lob);
809
+ rb_warning("LOB#flush had not worked by mistake. Do nothing now.");
846
810
  return self;
847
811
  }
848
812
 
data/ext/oci8/object.c CHANGED
@@ -44,6 +44,8 @@ enum {
44
44
  ATTR_FLOAT,
45
45
  ATTR_INTEGER,
46
46
  ATTR_OCIDATE,
47
+ ATTR_TIMESTAMP,
48
+ ATTR_TIMESTAMP_TZ,
47
49
  ATTR_BINARY_DOUBLE,
48
50
  ATTR_BINARY_FLOAT,
49
51
  ATTR_NAMED_TYPE,
@@ -235,6 +237,10 @@ static VALUE get_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *dat
235
237
  return oci8_make_integer((OCINumber *)data, oci8_errhp);
236
238
  case ATTR_OCIDATE:
237
239
  return oci8_make_ocidate((OCIDate *)data);
240
+ case ATTR_TIMESTAMP:
241
+ return oci8_make_ocitimestamp(*(OCIDateTime**)data, FALSE);
242
+ case ATTR_TIMESTAMP_TZ:
243
+ return oci8_make_ocitimestamp(*(OCIDateTime**)data, TRUE);
238
244
  case ATTR_BINARY_DOUBLE:
239
245
  return rb_float_new(*(double*)data);
240
246
  case ATTR_BINARY_FLOAT:
@@ -413,6 +419,18 @@ static VALUE oci8_named_coll_set_coll_element(VALUE self, VALUE datatype, VALUE
413
419
  case ATTR_OCIDATE:
414
420
  cb_data.indp = &cb_data.ind;
415
421
  break;
422
+ case ATTR_TIMESTAMP:
423
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_TIMESTAMP, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
424
+ svcctx);
425
+ chker2(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp),
426
+ svcctx);
427
+ break;
428
+ case ATTR_TIMESTAMP_TZ:
429
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_TIMESTAMP_TZ, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
430
+ svcctx);
431
+ chker2(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp),
432
+ svcctx);
433
+ break;
416
434
  case ATTR_BINARY_DOUBLE:
417
435
  cb_data.data.dbl = 0.0;
418
436
  cb_data.indp = &cb_data.ind;
@@ -507,6 +525,8 @@ static VALUE set_coll_element_ensure(set_coll_element_cb_data_t *cb_data)
507
525
  switch (FIX2INT(datatype)) {
508
526
  case ATTR_STRING:
509
527
  case ATTR_RAW:
528
+ case ATTR_TIMESTAMP:
529
+ case ATTR_TIMESTAMP_TZ:
510
530
  case ATTR_NAMED_TYPE:
511
531
  case ATTR_NAMED_COLLECTION:
512
532
  if (cb_data->data.ptr != NULL) {
@@ -558,6 +578,12 @@ static void set_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *data
558
578
  case ATTR_OCIDATE:
559
579
  oci8_set_ocidate((OCIDate*)data, val);
560
580
  break;
581
+ case ATTR_TIMESTAMP:
582
+ oci8_set_ocitimestamp_tz(*(OCIDateTime **)data, val, Qnil);
583
+ break;
584
+ case ATTR_TIMESTAMP_TZ:
585
+ oci8_set_ocitimestamp_tz(*(OCIDateTime **)data, val, Qnil);
586
+ break;
561
587
  case ATTR_BINARY_DOUBLE:
562
588
  *(double*)data = NUM2DBL(val);
563
589
  break;
@@ -818,6 +844,10 @@ void Init_oci_object(VALUE cOCI8)
818
844
  /* @private */
819
845
  rb_define_const(cOCI8TDO, "ATTR_OCIDATE", INT2FIX(ATTR_OCIDATE));
820
846
  /* @private */
847
+ rb_define_const(cOCI8TDO, "ATTR_TIMESTAMP", INT2FIX(ATTR_TIMESTAMP));
848
+ /* @private */
849
+ rb_define_const(cOCI8TDO, "ATTR_TIMESTAMP_TZ", INT2FIX(ATTR_TIMESTAMP_TZ));
850
+ /* @private */
821
851
  rb_define_const(cOCI8TDO, "ATTR_BINARY_DOUBLE", INT2FIX(ATTR_BINARY_DOUBLE));
822
852
  /* @private */
823
853
  rb_define_const(cOCI8TDO, "ATTR_BINARY_FLOAT", INT2FIX(ATTR_BINARY_FLOAT));
data/ext/oci8/oci8.c CHANGED
@@ -582,6 +582,8 @@ static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE attach_mode)
582
582
  static VALUE oci8_session_begin(VALUE self, VALUE cred, VALUE mode)
583
583
  {
584
584
  oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
585
+ char buf[100];
586
+ ub4 version;
585
587
 
586
588
  if (svcctx->logoff_strategy != &complex_logoff) {
587
589
  rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle().");
@@ -604,6 +606,16 @@ static VALUE oci8_session_begin(VALUE self, VALUE cred, VALUE mode)
604
606
  oci8_errhp),
605
607
  &svcctx->base);
606
608
  svcctx->state |= OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
609
+ if (have_OCIServerRelease2) {
610
+ chker2(OCIServerRelease2(svcctx->base.hp.ptr, oci8_errhp, (text*)buf,
611
+ sizeof(buf), (ub1)svcctx->base.type, &version, OCI_DEFAULT),
612
+ &svcctx->base);
613
+ } else {
614
+ chker2(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf,
615
+ sizeof(buf), (ub1)svcctx->base.type, &version),
616
+ &svcctx->base);
617
+ }
618
+ svcctx->server_version = version;
607
619
  return Qnil;
608
620
  }
609
621
 
@@ -796,11 +808,8 @@ static VALUE oci8_break(VALUE self)
796
808
  static VALUE oci8_oracle_server_vernum(VALUE self)
797
809
  {
798
810
  oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
799
- char buf[100];
800
- ub4 version;
801
811
 
802
- chker2(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type, &version), &svcctx->base);
803
- return UINT2NUM(version);
812
+ return UINT2NUM(svcctx->server_version);
804
813
  }
805
814
 
806
815
  /*
data/ext/oci8/oci8.h CHANGED
@@ -21,8 +21,23 @@ extern "C"
21
21
  }
22
22
  #endif
23
23
 
24
+ /*
25
+ * Oracle version number format in 32-bit integer.
26
+ *
27
+ * Oracle 12c or earier Oracle 18c or later
28
+ *
29
+ * hexadecimal -> dotted version number hexadecimal -> dotted version number
30
+ * 0c102304 -> 12.1.2.3.4 12012034 -> 18.1.2.3.4
31
+ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
32
+ * 0c ------------' | | | | 2 bytes 12 ------------' | | | | 2 bytes
33
+ * 1 --------------' | | | 1 byte 01 -------------' | | | 2 bytes
34
+ * 02 --------------' | | 2 bytes 2 --------------' | | 1 byte
35
+ * 3 ---------------' | 1 byte 03 --------------' | 2 bytes
36
+ * 04 ---------------' 2 bytes 4 ---------------' 1 byte
37
+ */
24
38
  #define ORAVERNUM(major, minor, update, patch, port_update) \
25
- (((major) << 24) | ((minor) << 20) | ((update) << 12) | ((patch) << 8) | (port_update))
39
+ (((major) >= 18) ? (((major) << 24) | ((minor) << 16) | ((update) << 12) | ((patch) << 4) | (port_update)) \
40
+ : (((major) << 24) | ((minor) << 20) | ((update) << 12) | ((patch) << 8) | (port_update)))
26
41
 
27
42
  #define ORAVER_8_0 ORAVERNUM(8, 0, 0, 0, 0)
28
43
  #define ORAVER_8_1 ORAVERNUM(8, 1, 0, 0, 0)
@@ -32,6 +47,7 @@ extern "C"
32
47
  #define ORAVER_10_2 ORAVERNUM(10, 2, 0, 0, 0)
33
48
  #define ORAVER_11_1 ORAVERNUM(11, 1, 0, 0, 0)
34
49
  #define ORAVER_12_1 ORAVERNUM(12, 1, 0, 0, 0)
50
+ #define ORAVER_18 ORAVERNUM(18, 0, 0, 0, 0)
35
51
 
36
52
  #include "extconf.h"
37
53
  #include <ruby/encoding.h>
@@ -316,6 +332,7 @@ typedef struct oci8_svcctx {
316
332
  const oci8_logoff_strategy_t *logoff_strategy;
317
333
  OCISession *usrhp;
318
334
  OCIServer *srvhp;
335
+ ub4 server_version;
319
336
  rb_pid_t pid;
320
337
  unsigned char state;
321
338
  char is_autocommit;
@@ -489,8 +506,8 @@ OCINumber *oci8_dbl_to_onum(OCINumber *result, double dbl, OCIError *errhp);
489
506
  void Init_oci_datetime(void);
490
507
  VALUE oci8_make_ocidate(OCIDate *od);
491
508
  OCIDate *oci8_set_ocidate(OCIDate *od, VALUE val);
492
- VALUE oci8_make_ocidatetime(OCIDateTime *dttm);
493
- OCIDateTime *oci8_set_ocidatetime(OCIDateTime *dttm, VALUE val);
509
+ VALUE oci8_make_ocitimestamp(OCIDateTime *dttm, boolean have_tz);
510
+ OCIDateTime *oci8_set_ocitimestamp_tz(OCIDateTime *dttm, VALUE val, VALUE svc);
494
511
  VALUE oci8_make_interval_ym(OCIInterval *s);
495
512
  VALUE oci8_make_interval_ds(OCIInterval *s);
496
513
 
data/ext/oci8/oci8lib.c CHANGED
@@ -620,11 +620,13 @@ void *oci8_find_symbol(const char *symbol_name)
620
620
  "libclntsh.sl.10.1",
621
621
  #elif defined(__APPLE__)
622
622
  /* Mac OS X */
623
+ "libclntsh.dylib",
623
624
  "libclntsh.dylib.12.1",
624
625
  "libclntsh.dylib.11.1",
625
626
  "libclntsh.dylib.10.1",
626
627
  #else
627
628
  /* Linux, Solaris and HP-UX(IA64) */
629
+ "libclntsh.so",
628
630
  "libclntsh.so.12.1",
629
631
  "libclntsh.so.11.1",
630
632
  "libclntsh.so.10.1",
data/ext/oci8/win32.c CHANGED
@@ -21,26 +21,6 @@
21
21
  * @private
22
22
  */
23
23
 
24
- NORETURN(static void raise_error(void));
25
-
26
- static void raise_error(void)
27
- {
28
- char msg[1024];
29
- int err = GetLastError();
30
- char *p;
31
-
32
- sprintf(msg, "%d: ", err);
33
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
34
- NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
35
- msg + strlen(msg), sizeof(msg) - strlen(msg), NULL);
36
- for (p = msg; *p != '\0'; p++) {
37
- if (*p == '\n' || *p == '\r') {
38
- *p = ' ';
39
- }
40
- }
41
- rb_raise(rb_eRuntimeError, "%s", msg);
42
- }
43
-
44
24
  typedef struct {
45
25
  HKEY hKey;
46
26
  HKEY hSubKey;
data/lib/oci8.rb CHANGED
@@ -140,6 +140,8 @@ class OCI8
140
140
  ORAVER_11_1 = OCI8::OracleVersion.new(11, 1)
141
141
  # @private
142
142
  ORAVER_12_1 = OCI8::OracleVersion.new(12, 1)
143
+ # @private
144
+ ORAVER_18 = OCI8::OracleVersion.new(18)
143
145
 
144
146
  # @private
145
147
  @@oracle_client_version = OCI8::OracleVersion.new(self.oracle_client_vernum)
data/lib/oci8/metadata.rb CHANGED
@@ -1503,7 +1503,11 @@ class OCI8
1503
1503
  attr_get_sb1(OCI_ATTR_SCALE)
1504
1504
  end
1505
1505
 
1506
- # The datatype levels. This attribute always returns zero.
1506
+ # The nest level.
1507
+ #
1508
+ # Oracle manual says that it always returns zero. However it returns
1509
+ # the depth of {OCI8::ArgBase#arguments} calls when #arguments returns
1510
+ # a non-empty array.
1507
1511
  def level
1508
1512
  attr_get_ub2(OCI_ATTR_LEVEL)
1509
1513
  end
@@ -1607,6 +1611,10 @@ class OCI8
1607
1611
 
1608
1612
  # The list of arguments at the next level (when the argument is
1609
1613
  # of a record or table type).
1614
+ #
1615
+ # This method returns an array containing type information when
1616
+ # the type is a user-defined type and the Oracle server version
1617
+ # is 12c or earlier. Otherwise, it returns an empty array.
1610
1618
  def arguments
1611
1619
  @arguments ||= list_arguments.to_a
1612
1620
  end
data/lib/oci8/object.rb CHANGED
@@ -493,6 +493,16 @@ EOS
493
493
  Proc.new do |val| datetime_to_array(val, :date) end, # set_proc
494
494
  Proc.new do |val| array_to_time(val, :local) end, # get_proc
495
495
  ]
496
+ when :timestamp
497
+ [ATTR_TIMESTAMP, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
498
+ Proc.new do |val| datetime_to_array(val, :timestamp) end, # set_proc
499
+ Proc.new do |val| array_to_time(val, :local) end, # get_proc
500
+ ]
501
+ when :timestamp_tz
502
+ [ATTR_TIMESTAMP_TZ, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
503
+ Proc.new do |val| datetime_to_array(val, :timestamp_tz) end, # set_proc
504
+ Proc.new do |val| array_to_time(val, nil) end, # get_proc
505
+ ]
496
506
  when :binary_double
497
507
  [ATTR_BINARY_DOUBLE, nil, SIZE_OF_DOUBLE, 2, ALIGNMENT_OF_DOUBLE]
498
508
  when :binary_float
data/lib/oci8/oci8.rb CHANGED
@@ -340,6 +340,12 @@ class OCI8
340
340
 
341
341
  # Returns the Oracle server version.
342
342
  #
343
+ # When the Oracle client version is 12c or earlier and
344
+ # the Oracle server version is 18c or later, this method
345
+ # doesn't return *full* version number such as '18.3.0.0.0'.
346
+ # It returns version number whose number components after
347
+ # the first dot are zeros such as '18.0.0.0.0'.
348
+ #
343
349
  # @see OCI8.oracle_client_version
344
350
  # @return [OCI8::OracleVersion]
345
351
  def oracle_server_version
@@ -66,6 +66,12 @@ class OCI8
66
66
  major, minor, update, patch, port_update = arg.split('.').collect do |v|
67
67
  v.to_i
68
68
  end
69
+ elsif arg >= 0x12000000
70
+ major = (arg & 0xFF000000) >> 24
71
+ minor = (arg & 0x00FF0000) >> 16
72
+ update = (arg & 0x0000F000) >> 12
73
+ patch = (arg & 0x00000FF0) >> 4
74
+ port_update = (arg & 0x0000000F)
69
75
  elsif arg >= 0x08000000
70
76
  major = (arg & 0xFF000000) >> 24
71
77
  minor = (arg & 0x00F00000) >> 20
@@ -80,7 +86,11 @@ class OCI8
80
86
  @update = update || 0
81
87
  @patch = patch || 0
82
88
  @port_update = port_update || 0
83
- @vernum = (@major << 24) | (@minor << 20) | (@update << 12) | (@patch << 8) | @port_update
89
+ @vernum = if @major >= 18
90
+ (@major << 24) | (@minor << 16) | (@update << 12) | (@patch << 4) | @port_update
91
+ else
92
+ (@major << 24) | (@minor << 20) | (@update << 12) | (@patch << 8) | @port_update
93
+ end
84
94
  end
85
95
 
86
96
  # Compares +self+ and +other+.
data/lib/oci8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class OCI8
2
- VERSION = "2.2.5.1"
2
+ VERSION = "2.2.6"
3
3
  end
data/lib/ruby-oci8.rb CHANGED
@@ -1,4 +1 @@
1
- if caller[0] !~ /\/bundler\/runtime\.rb:\d+:in `require'/
2
- warn "Don't require 'ruby-oci8'. Use \"require 'oci8'\" instead. 'ruby-oci8.rb' was added only for 'Bundler.require'."
3
- end
4
1
  require 'oci8'
@@ -61,6 +61,8 @@ create type rb_test_obj as object (
61
61
  obj_array_val rb_test_obj_elem_array,
62
62
  obj_ary_of_ary_val rb_test_obj_elem_ary_of_ary,
63
63
  date_val date,
64
+ timestamp_val timestamp(9),
65
+ timestamp_tz_val timestamp(9) with time zone,
64
66
  -- date_array_val rb_test_date_array,
65
67
 
66
68
  constructor function rb_test_obj(n number) return self as result,
@@ -72,19 +74,23 @@ create type rb_test_obj as object (
72
74
  member procedure member_proc(n in integer)
73
75
  )
74
76
  /
75
- create or replace type body rb_test_obj is
76
-
77
+ create type body rb_test_obj is
77
78
  constructor function rb_test_obj(n number) return self as result is
78
- function to_test_date(n number) return date is
79
- begin
80
- return to_date(to_char(1990 + n, 'FM0000') ||
81
- to_char(mod(round(n) * 5, 12) + 1, 'FM00') ||
82
- to_char(mod(round(n) * 7, 27) + 1, 'FM00') ||
83
- to_char(mod(round(n) * 9, 24), 'FM00') ||
84
- to_char(mod(round(n) * 11, 60), 'FM00') ||
85
- to_char(mod(round(n) * 13, 60), 'FM00'), 'yyyymmddhh24miss');
86
- end;
79
+ str varchar(28);
80
+ ts timestamp(9);
81
+ ts_tz timestamp(9) with time zone;
87
82
  begin
83
+ str := to_char(1990 + n, 'FM0000') ||
84
+ to_char(mod(round(n) * 5, 12) + 1, 'FM00') ||
85
+ to_char(mod(round(n) * 7, 27) + 1, 'FM00') ||
86
+ to_char(mod(round(n) * 9, 24), 'FM00') ||
87
+ to_char(mod(round(n) * 11, 60), 'FM00') ||
88
+ to_char(mod(round(n) * 13, 60), 'FM00') ||
89
+ to_char(mod(round(n) * 333333333, 1000000000), 'FM000000000');
90
+ ts := to_timestamp(str, 'yyyymmddhh24missff9');
91
+ str := str || to_char(mod(round(n) * 15, 24) - 11, 'FMS00') ||
92
+ to_char(mod(round(n) * 17, 60), 'FM00');
93
+ ts_tz := to_timestamp_tz(str, 'yyyymmddhh24missff9tzhtzm');
88
94
  self.int_val := n;
89
95
  self.flt_val := n;
90
96
  self.num_val := n;
@@ -96,7 +102,9 @@ create or replace type body rb_test_obj is
96
102
  self.nclob_val := to_clob(n);
97
103
  self.blob_val := to_blob(utl_raw.cast_to_raw(to_char(n)));
98
104
  self.obj_val := rb_test_obj_elem(n, n + 1);
99
- self.date_val := to_test_date(n);
105
+ self.date_val := ts;
106
+ self.timestamp_val := ts;
107
+ self.timestamp_tz_val := ts_tz;
100
108
  if self.int_val != 1 then
101
109
  self.int_array_val := rb_test_int_array(n, n + 1, n + 2);
102
110
  self.flt_array_val := rb_test_flt_array(n, n + 1, n + 2);
@@ -120,7 +128,7 @@ create or replace type body rb_test_obj is
120
128
 
121
129
  static function test_object_version return integer is
122
130
  begin
123
- return 3;
131
+ return 4;
124
132
  end;
125
133
 
126
134
  static function class_func(n number) return rb_test_obj is
data/test/test_all.rb CHANGED
@@ -26,6 +26,7 @@ require "#{srcdir}/test_oracle_version"
26
26
  require "#{srcdir}/test_error"
27
27
  require "#{srcdir}/test_connection_pool"
28
28
  require "#{srcdir}/test_object"
29
+ require "#{srcdir}/test_properties.rb"
29
30
 
30
31
  if OCI8.respond_to? :encoding
31
32
  require "#{srcdir}/test_encoding"
data/test/test_clob.rb CHANGED
@@ -24,22 +24,6 @@ class TestCLob < Minitest::Test
24
24
  lob.close
25
25
  end
26
26
 
27
- def test_insert_with_flush
28
- filename = File.basename($lobfile)
29
- @conn.exec("DELETE FROM test_table WHERE filename = :1", filename)
30
- @conn.exec("INSERT INTO test_table(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
31
- cursor = @conn.exec("SELECT content FROM test_table WHERE filename = :1 FOR UPDATE", filename)
32
- lob = cursor.fetch[0]
33
- lob.sync = false
34
- open($lobfile) do |f|
35
- while s = f.read(1000)
36
- lob.write(s)
37
- end
38
- end
39
- lob.flush
40
- lob.close
41
- end
42
-
43
27
  def test_insert_symbol
44
28
  filename = 'test_symbol'
45
29
  value = :foo_bar
@@ -76,6 +60,9 @@ class TestCLob < Minitest::Test
76
60
 
77
61
  # https://github.com/kubo/ruby-oci8/issues/20
78
62
  def test_github_issue_20
63
+ # Skip this test if FULLTEST isn't set because it takes 4 minutes in my Linux box.
64
+ return if ENV['FULLTEST']
65
+
79
66
  lob1 = OCI8::CLOB.new(@conn, ' ' * (1024 * 1024))
80
67
  lob1.read(1) # to suppress `warning: assigned but unused variable - lob1`
81
68
  begin
data/test/test_object.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  require 'oci8'
2
2
  require File.dirname(__FILE__) + '/config'
3
3
 
4
+ class Time
5
+ def inspect
6
+ self.strftime("%Y-%m-%d %H:%M:%S.%N %:z")
7
+ end
8
+ end
9
+
4
10
  conn = OCI8.new($dbuser, $dbpass, $dbname)
5
11
  error_message = nil
6
12
  begin
@@ -22,7 +28,7 @@ begin
22
28
 
23
29
  begin
24
30
  version = RbTestObj.test_object_version(conn)
25
- error_message = "Invalid test object version" if version != 3
31
+ error_message = "Invalid test object version" if version != 4
26
32
  rescue NoMethodError
27
33
  raise unless $!.to_s.include?('test_object_version')
28
34
  error_message = "rb_test_obj.test_object_version is not declared."
@@ -100,7 +106,8 @@ class TestObj1 < Minitest::Test
100
106
  attr_reader :obj_array_val
101
107
  attr_reader :obj_ary_of_ary_val
102
108
  attr_reader :date_val
103
- # attr_reader :date_array_val
109
+ attr_reader :timestamp_val
110
+ attr_reader :timestamp_tz_val
104
111
 
105
112
  attr_accessor :assertions
106
113
 
@@ -109,16 +116,28 @@ class TestObj1 < Minitest::Test
109
116
  @assertions = 0
110
117
  end
111
118
 
112
- def to_test_date(n)
119
+ def to_test_datetime(n, type)
113
120
  year = (1990 + n).round
114
121
  month = (n.round * 5) % 12 + 1
115
122
  mday = (n.round * 7) % 27 + 1
116
123
  hour = (n.round * 9) % 24
117
124
  minute = (n.round * 11) % 60
118
125
  sec = (n.round * 13) % 60
119
- convert_to_time(year, month, mday, hour, minute, sec, 0, nil)
126
+ nsec = if type == :date
127
+ 0
128
+ else
129
+ ((n.round * 333_333_333) % 1_000_000_000).to_r / 1_000_000_000
130
+ end
131
+ tz = if type == :timestamp_tz
132
+ tzh = (n.round * 15) % 24 - 11
133
+ tzm = (n.round * 17) % 60
134
+ format('%+03d:%02d', tzh, tzm)
135
+ else
136
+ nil
137
+ end
138
+ convert_to_time(year, month, mday, hour, minute, sec, nsec, tz)
120
139
  end
121
- private :to_test_date
140
+ private :to_test_datetime
122
141
 
123
142
  def next
124
143
  @n += 1.2
@@ -135,7 +154,9 @@ class TestObj1 < Minitest::Test
135
154
  @nclob_val = @str_val
136
155
  @blob_val = @str_val
137
156
  @obj_val = ExpectedValObjElem.new(@int_val, @int_val + 1)
138
- @date_val = to_test_date(@n)
157
+ @date_val = to_test_datetime(@n, :date)
158
+ @timestamp_val = to_test_datetime(@n, :timestamp)
159
+ @timestamp_tz_val = to_test_datetime(@n, :timestamp_tz)
139
160
  if @int_val == 1
140
161
  @int_array_val = nil
141
162
  @flt_array_val = nil
@@ -199,7 +220,8 @@ class TestObj1 < Minitest::Test
199
220
  obj_array_val = val[18]
200
221
  obj_ary_of_ary_val = val[19]
201
222
  date_val = val[20]
202
- # date_array_val = val[18]
223
+ timestamp_val = val[21]
224
+ timestamp_tz_val = val[22]
203
225
  else
204
226
  assert_instance_of(RbTestObj, val)
205
227
  int_val = val.int_val
@@ -223,7 +245,8 @@ class TestObj1 < Minitest::Test
223
245
  obj_array_val = val.obj_array_val
224
246
  obj_ary_of_ary_val = val.obj_ary_of_ary_val
225
247
  date_val = val.date_val
226
- # date_array_val = val.date_array_val
248
+ timestamp_val = val.timestamp_val
249
+ timestamp_tz_val = val.timestamp_tz_val
227
250
  end
228
251
 
229
252
  assert_equal(@int_val, int_val)
@@ -267,7 +290,8 @@ class TestObj1 < Minitest::Test
267
290
  assert_nil(obj_ary_of_ary_val)
268
291
  end
269
292
  assert_equal(@date_val, date_val)
270
- # assert_equal(@date_array_val, date_array_val && date_array_val.to_ary)
293
+ assert_equal(@timestamp_val, timestamp_val)
294
+ assert_equal(@timestamp_tz_val, timestamp_tz_val)
271
295
  end
272
296
 
273
297
  def assert_array_in_delta(exp, val)
data/test/test_oci8.rb CHANGED
@@ -491,9 +491,23 @@ EOS
491
491
  else
492
492
  raise "Unknown column size #{column_size}"
493
493
  end
494
- driver_name = cursor.fetch[0]
494
+ driver_name = cursor.fetch[0].strip
495
495
  cursor.close
496
496
  assert_equal(expected_value, driver_name)
497
497
  end
498
498
  end
499
+
500
+ def test_server_version
501
+ cursor = @conn.exec("select * from product_component_version where product like 'Oracle Database %'")
502
+ row = cursor.fetch_hash
503
+ cursor.close
504
+ ver = if OCI8::oracle_client_version >= OCI8::ORAVER_18
505
+ row['VERSION_FULL'] || row['VERSION']
506
+ else
507
+ # OCI8#oracle_server_version could not get infomation corresponding
508
+ # to VERSION_FULL when the Oracle client version is below 18.1.
509
+ row['VERSION']
510
+ end
511
+ assert_equal(ver, @conn.oracle_server_version.to_s)
512
+ end
499
513
  end # TestOCI8
@@ -639,7 +639,11 @@ class TestPackageType < Minitest::Test
639
639
  :sub_name => "TABLE_OF_PLS_INTEGER",
640
640
  :link => "",
641
641
  #:type_metadata => nil,
642
- :arguments => {
642
+ :arguments => ($oracle_server_version >= OCI8::ORAVER_18) ?
643
+ {
644
+ :class => Array,
645
+ :size => 0,
646
+ } : {
643
647
  :class => Array,
644
648
  :size => 1,
645
649
  [0] => {
@@ -729,7 +733,11 @@ class TestPackageType < Minitest::Test
729
733
  :sub_name => "TABLE_OF_REC1",
730
734
  :link => "",
731
735
  #:type_metadata => nil,
732
- :arguments => {
736
+ :arguments => ($oracle_server_version >= OCI8::ORAVER_18) ?
737
+ {
738
+ :class => Array,
739
+ :size => 0,
740
+ } : {
733
741
  :class => Array,
734
742
  :size => 1,
735
743
  [0] => {
@@ -846,7 +854,11 @@ class TestPackageType < Minitest::Test
846
854
  :sub_name => "TABLE_OF_REC1",
847
855
  :link => "",
848
856
  #:type_metadata => nil,
849
- :arguments => {
857
+ :arguments => ($oracle_server_version >= OCI8::ORAVER_18) ?
858
+ {
859
+ :class => Array,
860
+ :size => 0,
861
+ } : {
850
862
  :class => Array,
851
863
  :size => 1,
852
864
  [0] => {
@@ -0,0 +1,17 @@
1
+ require 'oci8'
2
+ require File.dirname(__FILE__) + '/config'
3
+
4
+ class TestProperties < Minitest::Test
5
+ def test_tcp_keepalive_time
6
+ begin
7
+ oldval = OCI8.properties[:tcp_keepalive_time]
8
+ begin
9
+ OCI8.properties[:tcp_keepalive_time] = 600
10
+ assert(true)
11
+ ensure
12
+ OCI8.properties[:tcp_keepalive_time] = oldval
13
+ end
14
+ rescue NotImplementedError
15
+ end
16
+ end
17
+ end
metadata CHANGED
@@ -1,35 +1,27 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: ruby-oci8
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 2
7
- - 2
8
- - 5
9
- - 1
10
- version: 2.2.5.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.2.6
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Kubo Takehiro
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2017-12-27 00:00:00 +09:00
19
- default_executable:
12
+ date: 2018-08-22 00:00:00.000000000 Z
20
13
  dependencies: []
14
+ description: ! 'ruby-oci8 is a ruby interface for Oracle using OCI8 API. It is available
15
+ with Oracle 10g or later including Oracle Instant Client.
21
16
 
22
- description: |
23
- ruby-oci8 is a ruby interface for Oracle using OCI8 API. It is available with Oracle 10g or later including Oracle Instant Client.
24
-
17
+ '
25
18
  email: kubo@jiubao.org
26
19
  executables: []
27
-
28
- extensions:
20
+ extensions:
29
21
  - ext/oci8/extconf.rb
30
- extra_rdoc_files:
22
+ extra_rdoc_files:
31
23
  - README.md
32
- files:
24
+ files:
33
25
  - .yardopts
34
26
  - COPYING
35
27
  - COPYING_old
@@ -141,41 +133,34 @@ files:
141
133
  - test/test_oradate.rb
142
134
  - test/test_oranumber.rb
143
135
  - test/test_package_type.rb
136
+ - test/test_properties.rb
144
137
  - test/test_rowid.rb
145
- has_rdoc: true
146
138
  homepage: http://www.rubydoc.info/github/kubo/ruby-oci8
147
- licenses:
139
+ licenses:
148
140
  - BSD-2-Clause
149
141
  post_install_message:
150
142
  rdoc_options: []
151
-
152
- require_paths:
143
+ require_paths:
153
144
  - lib
154
145
  - ext/oci8
155
- required_ruby_version: !ruby/object:Gem::Requirement
146
+ required_ruby_version: !ruby/object:Gem::Requirement
156
147
  none: false
157
- requirements:
158
- - - ">="
159
- - !ruby/object:Gem::Version
160
- segments:
161
- - 1
162
- - 9
163
- - 1
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
164
151
  version: 1.9.1
165
- required_rubygems_version: !ruby/object:Gem::Requirement
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
153
  none: false
167
- requirements:
168
- - - ">="
169
- - !ruby/object:Gem::Version
170
- segments:
171
- - 0
172
- version: "0"
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
173
158
  requirements: []
174
-
175
159
  rubyforge_project:
176
- rubygems_version: 1.3.7
160
+ rubygems_version: 1.8.11
177
161
  signing_key:
178
162
  specification_version: 3
179
163
  summary: Ruby interface for Oracle using OCI8 API
180
- test_files:
164
+ test_files:
181
165
  - test/test_all.rb
166
+ has_rdoc: yard