ruby-oci8 2.2.6.1 → 2.2.10
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.
- checksums.yaml +7 -0
- data/ChangeLog +167 -3
- data/NEWS +162 -54
- data/README.md +1 -1
- data/dist-files +1 -2
- data/docs/install-instant-client.md +2 -1
- data/docs/install-on-osx.md +29 -116
- data/ext/oci8/apiwrap.c.tmpl +2 -5
- data/ext/oci8/apiwrap.yml +20 -0
- data/ext/oci8/attr.c +4 -2
- data/ext/oci8/bind.c +366 -6
- data/ext/oci8/connection_pool.c +3 -3
- data/ext/oci8/extconf.rb +5 -2
- data/ext/oci8/hook_funcs.c +21 -1
- data/ext/oci8/lob.c +24 -32
- data/ext/oci8/metadata.c +2 -2
- data/ext/oci8/object.c +42 -27
- data/ext/oci8/oci8.c +14 -16
- data/ext/oci8/oci8.h +1 -0
- data/ext/oci8/oci8lib.c +10 -7
- data/ext/oci8/ocihandle.c +2 -2
- data/ext/oci8/ocinumber.c +11 -9
- data/ext/oci8/oraconf.rb +130 -257
- data/ext/oci8/oradate.c +1 -1
- data/ext/oci8/plthook_osx.c +10 -10
- data/ext/oci8/stmt.c +51 -16
- data/ext/oci8/win32.c +4 -2
- data/lib/oci8/bindtype.rb +0 -14
- data/lib/oci8/check_load_error.rb +51 -16
- data/lib/oci8/cursor.rb +46 -13
- data/lib/oci8/oci8.rb +1 -1
- data/lib/oci8/version.rb +1 -1
- data/lib/oci8.rb +9 -4
- data/ruby-oci8.gemspec +2 -3
- data/setup.rb +11 -2
- data/test/README.md +37 -0
- data/test/config.rb +1 -1
- data/test/test_break.rb +9 -9
- data/test/test_datetime.rb +8 -3
- data/test/test_oci8.rb +154 -43
- data/test/test_oranumber.rb +7 -1
- metadata +33 -55
- data/docs/osx-install-dev-tools.png +0 -0
- data/test/README +0 -42
data/docs/install-on-osx.md
CHANGED
@@ -1,133 +1,46 @@
|
|
1
|
-
# @title Install ruby-oci8 on
|
1
|
+
# @title Install ruby-oci8 on macOS
|
2
2
|
|
3
|
-
Install ruby-oci8 on
|
3
|
+
Install ruby-oci8 on macOS
|
4
4
|
=========================
|
5
5
|
|
6
|
-
|
6
|
+
**Note: Ruby-oci8 doesn't run on Apple Silicon because Oracle instant client
|
7
|
+
for Apple Silicon has not been released yet.**
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
Install C compiler
|
12
|
-
------------------
|
13
|
-
|
14
|
-
You need to install the command line developer tools or the Xcode.
|
15
|
-
(The latter includes the former.)
|
16
|
-
|
17
|
-
Run `"cc --version"` in a terminal to check whether they are installed.
|
18
|
-
|
19
|
-
If the cc version is printed, the tools are installed.
|
20
|
-
|
21
|
-
If the follwoing dialog is displayed, click its Install button to
|
22
|
-
install the tools.
|
23
|
-
You have no need to install the Xcode to compile ruby-oci8.
|
24
|
-
It requires command line tools, not an IDE such as the Xcode.
|
25
|
-
|
26
|
-

|
9
|
+
Prerequisite
|
10
|
+
------------
|
27
11
|
|
28
|
-
|
29
|
-
please re-run as root via sudo."` is printed, you need to run
|
30
|
-
`"sudo cc --version"`, enter your password, look at the license
|
31
|
-
and type `"agree"`.
|
12
|
+
* Command line tools for Xcode or Xcode (by executing `xcode-select --install`) or [Xcode]
|
32
13
|
|
33
14
|
Install Oracle Instant Client Packages
|
34
15
|
--------------------------------------
|
35
16
|
|
36
|
-
|
37
|
-
|
38
|
-
Download the following packages from [Oracle Technology Network][]
|
39
|
-
|
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
|
-
* Instant Client Package - SDK (`instantclient-sdk-macos.x64-12.1.0.2.0.zip`)
|
42
|
-
* Instant Client Package - SQL*Plus (`instantclient-sqlplus-macos.x64-12.1.0.2.0.zip`) (optionally)
|
43
|
-
|
44
|
-
### Install Oracle Instant Client Packages via Homebrew
|
45
|
-
|
46
|
-
To install `Oracle Instant Client Basic` via [Homebrew][]
|
47
|
-
|
48
|
-
* Copy downloaded zip files to `/Library/Caches/Homebrew`
|
49
|
-
(if the environment variable `HOMEBREW_CACHE`
|
50
|
-
is not set and `$HOME/Library/Caches/Homebrew` doesn't exist.)
|
51
|
-
|
52
|
-
* Run the followining commands:
|
53
|
-
|
54
|
-
brew tap InstantClientTap/instantclient
|
55
|
-
brew install instantclient-basic
|
56
|
-
brew install instantclient-sdk
|
57
|
-
brew install instantclient-sqlplus # (optionally)
|
58
|
-
|
59
|
-
* Set the environment variable `OCI_DIR` while performing the following installation steps
|
60
|
-
if Homebrew is installed outside `/usr/local`.
|
61
|
-
|
62
|
-
export OCI_DIR=$(brew --prefix)/lib
|
63
|
-
|
64
|
-
To install `Oracle Instant Client Basic Lite` via [Homebrew][]
|
65
|
-
|
66
|
-
* Copy downloaded zip files to `/Library/Caches/Homebrew`
|
67
|
-
(if the environment variable `HOMEBREW_CACHE`
|
68
|
-
is not set and `$HOME/Library/Caches/Homebrew` doesn't exist.)
|
69
|
-
|
70
|
-
* Run the followining commands:
|
71
|
-
|
72
|
-
brew tap InstantClientTap/instantclient
|
73
|
-
brew install instantclient-basiclite
|
74
|
-
brew install instantclient-sdk
|
75
|
-
brew install instantclient-sqlplus --with-basiclite # (optionally)
|
76
|
-
|
77
|
-
* Set the environment variable `OCI_DIR` while performing the following installation steps
|
78
|
-
if Homebrew is installed outside `/usr/local`.
|
79
|
-
|
80
|
-
export OCI_DIR=$(brew --prefix)/lib
|
81
|
-
|
82
|
-
### Install Oracle Instant Client Manually
|
83
|
-
|
84
|
-
If you don't use [Homebrew][], do the following:
|
85
|
-
|
86
|
-
Unzip the packages as follows:
|
87
|
-
|
88
|
-
mkdir -p /opt/oracle
|
89
|
-
cd /opt/oracle
|
90
|
-
|
91
|
-
Copy downloaded files to /opt/oracle before running the following commands.
|
92
|
-
|
93
|
-
unzip instantclient-basic-macos.x64-12.1.0.2.0.zip
|
94
|
-
unzip instantclient-sdk-macos.x64-12.1.0.2.0.zip
|
95
|
-
unzip instantclient-sqlplus-macos.x64-12.1.0.2.0.zip
|
96
|
-
|
97
|
-
Make a symbolic link to link the library.
|
98
|
-
|
99
|
-
cd /opt/oracle/instantclient_12_1
|
100
|
-
ln -s libclntsh.dylib.12.1 libclntsh.dylib
|
101
|
-
|
102
|
-
Set the environment variable OCI_DIR while performing the following installation steps.
|
103
|
-
|
104
|
-
export OCI_DIR=/opt/oracle/instantclient_12_1
|
105
|
-
|
106
|
-
Installation
|
107
|
-
------------
|
108
|
-
|
109
|
-
If you get a problem in the following steps, look at {file:docs/report-installation-issue.md}.
|
110
|
-
|
111
|
-
### gem package
|
112
|
-
|
113
|
-
Run the following command.
|
17
|
+
If you have installed [Homebrew], use the following command:
|
114
18
|
|
115
|
-
|
19
|
+
```shell
|
20
|
+
$ brew tap InstantClientTap/instantclient
|
21
|
+
$ brew install instantclient-basic # or instantclient-basiclite
|
22
|
+
$ brew install instantclient-sdk
|
23
|
+
$ brew install instantclient-sqlplus # (optionally)
|
24
|
+
```
|
116
25
|
|
117
|
-
|
26
|
+
Otherwise, look at this [page][OTN] and set the environment variable
|
27
|
+
`OCI_DIR` to point the the directory where instant client is installed.
|
28
|
+
Ruby-oci8 installation script checks the directory.
|
118
29
|
|
119
|
-
|
30
|
+
```shell
|
31
|
+
export OCI_DIR=$HOME/Downloads/instantclient_19_8 # for example
|
32
|
+
```
|
120
33
|
|
121
|
-
|
34
|
+
Install ruby-oci8
|
35
|
+
-----------------
|
122
36
|
|
123
|
-
|
37
|
+
Note that `/usr/bin/ruby` isn't available. You need to use [`rbenv`] or so.
|
124
38
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
make install
|
39
|
+
```shell
|
40
|
+
$ gem install ruby-oci8
|
41
|
+
```
|
129
42
|
|
130
|
-
[download page]: https://bintray.com/kubo/generic/ruby-oci8
|
131
43
|
[Homebrew]: http://brew.sh/
|
132
|
-
[
|
133
|
-
[
|
44
|
+
[OTN]: https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html#ic_osx_inst
|
45
|
+
[Xcode]: https://apps.apple.com/us/app/xcode/id497799835
|
46
|
+
[`rbenv`]: https://github.com/rbenv/rbenv
|
data/ext/oci8/apiwrap.c.tmpl
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
%>
|
5
5
|
#define API_WRAP_C 1
|
6
6
|
#include "apiwrap.h"
|
7
|
-
#define BLOCKING_FUNCTION_EPILOGUE(svcctx) do { (svcctx)->executing_thread = Qnil; } while (0)
|
8
7
|
|
9
8
|
<%
|
10
9
|
prev_name = ''
|
@@ -59,11 +58,9 @@ static void *oci8_<%=f.name%>_cb(void *user_data)
|
|
59
58
|
%> data->rv = <%=f.name%>(<%= f.args.collect do |a| 'data->' + a.name; end.join(', ') %>);
|
60
59
|
<% end %>
|
61
60
|
<% if f.ret == 'sword'
|
62
|
-
%>
|
63
|
-
return (void*)(VALUE)data->rv;
|
61
|
+
%> return (void*)(VALUE)data->rv;
|
64
62
|
<% else
|
65
|
-
%>
|
66
|
-
return NULL;
|
63
|
+
%> return NULL;
|
67
64
|
<% end %>
|
68
65
|
}
|
69
66
|
#else
|
data/ext/oci8/apiwrap.yml
CHANGED
@@ -83,6 +83,17 @@ OCIBindByPos:
|
|
83
83
|
- ub4 *curelep
|
84
84
|
- ub4 mode
|
85
85
|
|
86
|
+
# round trip: 0
|
87
|
+
OCIBindDynamic:
|
88
|
+
:version: 800
|
89
|
+
:args:
|
90
|
+
- OCIBind *bindp
|
91
|
+
- OCIError *errhp
|
92
|
+
- void *ictxp
|
93
|
+
- OCICallbackInBind icbfp
|
94
|
+
- void *octxp
|
95
|
+
- OCICallbackOutBind ocbfp
|
96
|
+
|
86
97
|
# round trip: 0
|
87
98
|
OCIBindObject:
|
88
99
|
:version: 800
|
@@ -180,6 +191,15 @@ OCIDefineByPos:
|
|
180
191
|
- ub2 *rcodep
|
181
192
|
- ub4 mode
|
182
193
|
|
194
|
+
# round trip: 0
|
195
|
+
OCIDefineDynamic:
|
196
|
+
:version: 800
|
197
|
+
:args:
|
198
|
+
- OCIDefine *defnp
|
199
|
+
- OCIError *errhp
|
200
|
+
- dvoid *octxp
|
201
|
+
- OCICallbackDefine ocbfp
|
202
|
+
|
183
203
|
# round trip: 0
|
184
204
|
OCIDefineObject:
|
185
205
|
:version: 800
|
data/ext/oci8/attr.c
CHANGED
@@ -15,8 +15,9 @@ typedef struct {
|
|
15
15
|
OCIRowid *ridp;
|
16
16
|
} rowid_arg_t;
|
17
17
|
|
18
|
-
static VALUE get_rowid_attr(
|
18
|
+
static VALUE get_rowid_attr(VALUE varg)
|
19
19
|
{
|
20
|
+
rowid_arg_t *arg = (rowid_arg_t *)varg;
|
20
21
|
oci8_base_t *base = arg->base;
|
21
22
|
ub4 attrtype = arg->attrtype;
|
22
23
|
char buf[MAX_ROWID_LEN];
|
@@ -36,8 +37,9 @@ static VALUE get_rowid_attr(rowid_arg_t *arg)
|
|
36
37
|
return rb_external_str_new_with_enc(buf, buflen, rb_usascii_encoding());
|
37
38
|
}
|
38
39
|
|
39
|
-
static VALUE rowid_ensure(
|
40
|
+
static VALUE rowid_ensure(VALUE varg)
|
40
41
|
{
|
42
|
+
rowid_arg_t *arg = (rowid_arg_t *)varg;
|
41
43
|
if (arg->ridp != NULL) {
|
42
44
|
OCIDescriptorFree(arg->ridp, OCI_DTYPE_ROWID);
|
43
45
|
}
|
data/ext/oci8/bind.c
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
#endif
|
12
12
|
|
13
13
|
static ID id_bind_type;
|
14
|
+
static ID id_charset_form;
|
14
15
|
static VALUE sym_length;
|
15
16
|
static VALUE sym_length_semantics;
|
16
17
|
static VALUE sym_char;
|
@@ -25,6 +26,29 @@ typedef struct {
|
|
25
26
|
ub1 csfrm;
|
26
27
|
} oci8_bind_string_t;
|
27
28
|
|
29
|
+
static ub4 initial_chunk_size = 32 * 1024;
|
30
|
+
static ub4 max_chunk_size = 8 * 1024 * 1024;
|
31
|
+
|
32
|
+
typedef struct chunk {
|
33
|
+
struct chunk *next;
|
34
|
+
ub4 alloc_len;
|
35
|
+
ub4 used_len;
|
36
|
+
char buf[1];
|
37
|
+
} chunk_t;
|
38
|
+
|
39
|
+
typedef struct {
|
40
|
+
chunk_t *head;
|
41
|
+
chunk_t **tail;
|
42
|
+
chunk_t **inpos;
|
43
|
+
} chunk_buf_t;
|
44
|
+
|
45
|
+
typedef struct {
|
46
|
+
oci8_bind_t obind;
|
47
|
+
ub1 csfrm;
|
48
|
+
} oci8_bind_long_t;
|
49
|
+
|
50
|
+
#define IS_BIND_LONG(obind) (((oci8_bind_data_type_t*)obind->base.data_type)->dty == SQLT_CHR)
|
51
|
+
|
28
52
|
const oci8_handle_data_type_t oci8_bind_data_type = {
|
29
53
|
{
|
30
54
|
"OCI8::BindType::Base",
|
@@ -61,7 +85,7 @@ static void bind_string_set(oci8_bind_t *obind, void *data, void **null_structp,
|
|
61
85
|
rb_raise(rb_eArgError, "too long String to set. (%ld for %d)", RSTRING_LEN(val), obs->bytelen);
|
62
86
|
}
|
63
87
|
memcpy(vstr->buf, RSTRING_PTR(val), RSTRING_LEN(val));
|
64
|
-
vstr->size =
|
88
|
+
vstr->size = RSTRING_LENINT(val);
|
65
89
|
}
|
66
90
|
|
67
91
|
static void bind_string_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE param)
|
@@ -171,7 +195,7 @@ static void bind_raw_set(oci8_bind_t *obind, void *data, void **null_structp, VA
|
|
171
195
|
rb_raise(rb_eArgError, "too long String to set. (%ld for %d)", RSTRING_LEN(val), obs->bytelen);
|
172
196
|
}
|
173
197
|
memcpy(vstr->buf, RSTRING_PTR(val), RSTRING_LEN(val));
|
174
|
-
vstr->size =
|
198
|
+
vstr->size = RSTRING_LENINT(val);
|
175
199
|
}
|
176
200
|
|
177
201
|
static const oci8_bind_data_type_t bind_raw_data_type = {
|
@@ -306,6 +330,295 @@ static VALUE bind_boolean_alloc(VALUE klass)
|
|
306
330
|
return oci8_allocate_typeddata(klass, &bind_boolean_data_type.base);
|
307
331
|
}
|
308
332
|
|
333
|
+
/*
|
334
|
+
* bind_long
|
335
|
+
*/
|
336
|
+
static chunk_t *next_chunk(chunk_buf_t *cb)
|
337
|
+
{
|
338
|
+
chunk_t *chunk;
|
339
|
+
|
340
|
+
if (*cb->tail != NULL) {
|
341
|
+
chunk = *cb->tail;
|
342
|
+
} else {
|
343
|
+
ub4 alloc_len;
|
344
|
+
if (cb->head == NULL) {
|
345
|
+
alloc_len = initial_chunk_size;
|
346
|
+
} else {
|
347
|
+
alloc_len = ((chunk_t*)((size_t)cb->tail - offsetof(chunk_t, next)))->alloc_len * 2;
|
348
|
+
if (alloc_len > max_chunk_size) {
|
349
|
+
alloc_len = max_chunk_size;
|
350
|
+
}
|
351
|
+
}
|
352
|
+
chunk = xmalloc(offsetof(chunk_t, buf) + alloc_len);
|
353
|
+
chunk->next = NULL;
|
354
|
+
chunk->alloc_len = alloc_len;
|
355
|
+
*cb->tail = chunk;
|
356
|
+
}
|
357
|
+
cb->tail = &chunk->next;
|
358
|
+
return chunk;
|
359
|
+
}
|
360
|
+
|
361
|
+
static sb4 define_callback(void *octxp, OCIDefine *defnp, ub4 iter, void **bufpp, ub4 **alenp, ub1 *piecep, void **indp, ub2 **rcodep)
|
362
|
+
{
|
363
|
+
oci8_bind_t *obind = (oci8_bind_t *)octxp;
|
364
|
+
chunk_buf_t *cb = ((chunk_buf_t*)obind->valuep) + iter;
|
365
|
+
chunk_t *chunk;
|
366
|
+
|
367
|
+
if (*piecep == OCI_FIRST_PIECE) {
|
368
|
+
cb->tail = &cb->head;
|
369
|
+
}
|
370
|
+
chunk = next_chunk(cb);
|
371
|
+
chunk->used_len = chunk->alloc_len;
|
372
|
+
*bufpp = chunk->buf;
|
373
|
+
*alenp = &chunk->used_len;
|
374
|
+
*indp = (void*)&obind->u.inds[iter];
|
375
|
+
*rcodep = NULL;
|
376
|
+
return OCI_CONTINUE;
|
377
|
+
}
|
378
|
+
|
379
|
+
static sb4 in_bind_callback(void *ictxp, OCIBind *bindp, ub4 iter, ub4 index, void **bufpp, ub4 *alenp, ub1 *piecep, void **indp)
|
380
|
+
{
|
381
|
+
oci8_bind_t *obind = (oci8_bind_t *)ictxp;
|
382
|
+
chunk_buf_t *cb = ((chunk_buf_t*)obind->valuep) + iter;
|
383
|
+
|
384
|
+
if (cb->tail == &cb->head) {
|
385
|
+
/* empty string */
|
386
|
+
*bufpp = (void *)"";
|
387
|
+
*alenp = 0;
|
388
|
+
*piecep = OCI_ONE_PIECE;
|
389
|
+
} else {
|
390
|
+
chunk_t *chunk = *cb->inpos;
|
391
|
+
*bufpp = chunk->buf;
|
392
|
+
*alenp = chunk->used_len;
|
393
|
+
if (cb->tail == &cb->head->next) {
|
394
|
+
*piecep = OCI_ONE_PIECE;
|
395
|
+
} else if (cb->inpos == &cb->head) {
|
396
|
+
*piecep = OCI_FIRST_PIECE;
|
397
|
+
cb->inpos = &chunk->next;
|
398
|
+
} else if (&chunk->next != cb->tail) {
|
399
|
+
*piecep = OCI_NEXT_PIECE;
|
400
|
+
cb->inpos = &chunk->next;
|
401
|
+
} else {
|
402
|
+
*piecep = OCI_LAST_PIECE;
|
403
|
+
cb->inpos = &cb->head;
|
404
|
+
}
|
405
|
+
}
|
406
|
+
*indp = (void*)&obind->u.inds[iter];
|
407
|
+
return OCI_CONTINUE;
|
408
|
+
}
|
409
|
+
|
410
|
+
static sb4 out_bind_callback(void *octxp, OCIBind *bindp, ub4 iter, ub4 index, void **bufpp, ub4 **alenp, ub1 *piecep, void **indp, ub2 **rcodep)
|
411
|
+
{
|
412
|
+
oci8_bind_t *obind = (oci8_bind_t *)octxp;
|
413
|
+
chunk_buf_t *cb = ((chunk_buf_t*)obind->valuep) + iter;
|
414
|
+
chunk_t *chunk;
|
415
|
+
|
416
|
+
if (*piecep == OCI_ONE_PIECE) {
|
417
|
+
*piecep = OCI_FIRST_PIECE;
|
418
|
+
cb->tail = &cb->head;
|
419
|
+
}
|
420
|
+
chunk = next_chunk(cb);
|
421
|
+
chunk->used_len = chunk->alloc_len;
|
422
|
+
*bufpp = chunk->buf;
|
423
|
+
*alenp = &chunk->used_len;
|
424
|
+
*indp = (void*)&obind->u.inds[iter];
|
425
|
+
*rcodep = NULL;
|
426
|
+
return OCI_CONTINUE;
|
427
|
+
}
|
428
|
+
|
429
|
+
static void bind_long_free(oci8_base_t *base)
|
430
|
+
{
|
431
|
+
oci8_bind_t *obind = (oci8_bind_t *)base;
|
432
|
+
chunk_buf_t *cb = (chunk_buf_t *)obind->valuep;
|
433
|
+
|
434
|
+
if (cb != NULL) {
|
435
|
+
ub4 idx = 0;
|
436
|
+
do {
|
437
|
+
chunk_t *chunk, *chunk_next;
|
438
|
+
for (chunk = cb[idx].head; chunk != NULL; chunk = chunk_next) {
|
439
|
+
chunk_next = chunk->next;
|
440
|
+
xfree(chunk);
|
441
|
+
}
|
442
|
+
} while (++idx < obind->maxar_sz);
|
443
|
+
}
|
444
|
+
oci8_bind_free(base);
|
445
|
+
}
|
446
|
+
|
447
|
+
static VALUE bind_long_get(oci8_bind_t *obind, void *data, void *null_struct)
|
448
|
+
{
|
449
|
+
chunk_buf_t *cb = (chunk_buf_t *)data;
|
450
|
+
chunk_t *chunk;
|
451
|
+
long len = 0;
|
452
|
+
VALUE str;
|
453
|
+
char *buf;
|
454
|
+
|
455
|
+
for (chunk = cb->head; chunk != *cb->tail; chunk = chunk->next) {
|
456
|
+
len += chunk->used_len;
|
457
|
+
}
|
458
|
+
str = rb_str_buf_new(len);
|
459
|
+
buf = RSTRING_PTR(str);
|
460
|
+
for (chunk = cb->head; chunk != *cb->tail; chunk = chunk->next) {
|
461
|
+
memcpy(buf, chunk->buf, chunk->used_len);
|
462
|
+
buf += chunk->used_len;
|
463
|
+
}
|
464
|
+
rb_str_set_len(str, len);
|
465
|
+
if (IS_BIND_LONG(obind)) {
|
466
|
+
rb_encoding *enc = rb_default_internal_encoding();
|
467
|
+
|
468
|
+
rb_enc_associate(str, oci8_encoding);
|
469
|
+
if (enc != NULL) {
|
470
|
+
str = rb_str_conv_enc(str, oci8_encoding, enc);
|
471
|
+
}
|
472
|
+
}
|
473
|
+
return str;
|
474
|
+
}
|
475
|
+
|
476
|
+
static void bind_long_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
|
477
|
+
{
|
478
|
+
chunk_buf_t *cb = (chunk_buf_t *)data;
|
479
|
+
ub4 len;
|
480
|
+
const char *buf;
|
481
|
+
|
482
|
+
if (IS_BIND_LONG(obind)) {
|
483
|
+
OCI8StringValue(val);
|
484
|
+
} else {
|
485
|
+
StringValue(val);
|
486
|
+
}
|
487
|
+
len = (ub4)RSTRING_LEN(val);
|
488
|
+
buf = RSTRING_PTR(val);
|
489
|
+
cb->tail = &cb->head;
|
490
|
+
while (1) {
|
491
|
+
chunk_t *chunk = next_chunk(cb);
|
492
|
+
if (len <= chunk->alloc_len) {
|
493
|
+
memcpy(chunk->buf, buf, len);
|
494
|
+
chunk->used_len = len;
|
495
|
+
break;
|
496
|
+
}
|
497
|
+
memcpy(chunk->buf, buf, chunk->alloc_len);
|
498
|
+
chunk->used_len = chunk->alloc_len;
|
499
|
+
len -= chunk->alloc_len;
|
500
|
+
buf += chunk->alloc_len;
|
501
|
+
}
|
502
|
+
}
|
503
|
+
|
504
|
+
static void bind_long_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE param)
|
505
|
+
{
|
506
|
+
if (IS_BIND_LONG(obind)) {
|
507
|
+
oci8_bind_long_t *obl = (oci8_bind_long_t *)obind;
|
508
|
+
VALUE nchar;
|
509
|
+
|
510
|
+
if (rb_respond_to(param, id_charset_form)) {
|
511
|
+
VALUE csfrm = rb_funcall(param, id_charset_form, 0);
|
512
|
+
nchar = (csfrm == sym_nchar) ? Qtrue : Qfalse;
|
513
|
+
} else {
|
514
|
+
Check_Type(param, T_HASH);
|
515
|
+
nchar = rb_hash_aref(param, sym_nchar);
|
516
|
+
}
|
517
|
+
|
518
|
+
if (RTEST(nchar)) {
|
519
|
+
obl->csfrm = SQLCS_NCHAR; /* bind as NCHAR/NVARCHAR2 */
|
520
|
+
} else {
|
521
|
+
obl->csfrm = SQLCS_IMPLICIT; /* bind as CHAR/VARCHAR2 */
|
522
|
+
}
|
523
|
+
}
|
524
|
+
obind->value_sz = SB4MAXVAL;
|
525
|
+
obind->alloc_sz = sizeof(chunk_buf_t);
|
526
|
+
}
|
527
|
+
|
528
|
+
static void bind_long_init_elem(oci8_bind_t *obind, VALUE svc)
|
529
|
+
{
|
530
|
+
chunk_buf_t *cb = (chunk_buf_t *)obind->valuep;
|
531
|
+
ub4 idx = 0;
|
532
|
+
|
533
|
+
do {
|
534
|
+
cb[idx].tail = &cb[idx].head;
|
535
|
+
cb[idx].inpos = &cb[idx].head;
|
536
|
+
} while (++idx < obind->maxar_sz);
|
537
|
+
}
|
538
|
+
|
539
|
+
static void bind_long_post_bind_hook(oci8_bind_t *obind)
|
540
|
+
{
|
541
|
+
oci8_bind_long_t *ds = (oci8_bind_long_t *)obind;
|
542
|
+
|
543
|
+
if (IS_BIND_LONG(obind)) {
|
544
|
+
chker2(OCIAttrSet(obind->base.hp.ptr, obind->base.type, (void*)&ds->csfrm, 0, OCI_ATTR_CHARSET_FORM, oci8_errhp),
|
545
|
+
&obind->base);
|
546
|
+
}
|
547
|
+
switch (obind->base.type) {
|
548
|
+
case OCI_HTYPE_DEFINE:
|
549
|
+
chker2(OCIDefineDynamic(obind->base.hp.dfn, oci8_errhp, obind, define_callback),
|
550
|
+
&obind->base);
|
551
|
+
break;
|
552
|
+
case OCI_HTYPE_BIND:
|
553
|
+
chker2(OCIBindDynamic(obind->base.hp.bnd, oci8_errhp, obind, in_bind_callback,
|
554
|
+
obind, out_bind_callback),
|
555
|
+
&obind->base);
|
556
|
+
break;
|
557
|
+
}
|
558
|
+
}
|
559
|
+
|
560
|
+
static const oci8_bind_data_type_t bind_long_data_type = {
|
561
|
+
{
|
562
|
+
{
|
563
|
+
"OCI8::BindType::Long",
|
564
|
+
{
|
565
|
+
NULL,
|
566
|
+
oci8_handle_cleanup,
|
567
|
+
oci8_handle_size,
|
568
|
+
},
|
569
|
+
&oci8_bind_data_type.rb_data_type, NULL,
|
570
|
+
#ifdef RUBY_TYPED_WB_PROTECTED
|
571
|
+
RUBY_TYPED_WB_PROTECTED,
|
572
|
+
#endif
|
573
|
+
},
|
574
|
+
bind_long_free,
|
575
|
+
sizeof(oci8_bind_long_t)
|
576
|
+
},
|
577
|
+
bind_long_get,
|
578
|
+
bind_long_set,
|
579
|
+
bind_long_init,
|
580
|
+
bind_long_init_elem,
|
581
|
+
NULL,
|
582
|
+
SQLT_CHR,
|
583
|
+
bind_long_post_bind_hook,
|
584
|
+
};
|
585
|
+
|
586
|
+
static VALUE bind_long_alloc(VALUE klass)
|
587
|
+
{
|
588
|
+
return oci8_allocate_typeddata(klass, &bind_long_data_type.base);
|
589
|
+
}
|
590
|
+
|
591
|
+
static const oci8_bind_data_type_t bind_long_raw_data_type = {
|
592
|
+
{
|
593
|
+
{
|
594
|
+
"OCI8::BindType::LongRaw",
|
595
|
+
{
|
596
|
+
NULL,
|
597
|
+
oci8_handle_cleanup,
|
598
|
+
oci8_handle_size,
|
599
|
+
},
|
600
|
+
&oci8_bind_data_type.rb_data_type, NULL,
|
601
|
+
#ifdef RUBY_TYPED_WB_PROTECTED
|
602
|
+
RUBY_TYPED_WB_PROTECTED,
|
603
|
+
#endif
|
604
|
+
},
|
605
|
+
bind_long_free,
|
606
|
+
sizeof(oci8_bind_long_t)
|
607
|
+
},
|
608
|
+
bind_long_get,
|
609
|
+
bind_long_set,
|
610
|
+
bind_long_init,
|
611
|
+
bind_long_init_elem,
|
612
|
+
NULL,
|
613
|
+
SQLT_BIN,
|
614
|
+
bind_long_post_bind_hook,
|
615
|
+
};
|
616
|
+
|
617
|
+
static VALUE bind_long_raw_alloc(VALUE klass)
|
618
|
+
{
|
619
|
+
return oci8_allocate_typeddata(klass, &bind_long_raw_data_type.base);
|
620
|
+
}
|
621
|
+
|
309
622
|
static VALUE oci8_bind_get(VALUE self)
|
310
623
|
{
|
311
624
|
oci8_bind_t *obind = TO_BIND(self);
|
@@ -320,11 +633,20 @@ static VALUE oci8_bind_get(VALUE self)
|
|
320
633
|
return data_type->get(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp);
|
321
634
|
}
|
322
635
|
|
323
|
-
static VALUE oci8_bind_get_data(VALUE self)
|
636
|
+
static VALUE oci8_bind_get_data(int argc, VALUE *argv, VALUE self)
|
324
637
|
{
|
325
638
|
oci8_bind_t *obind = TO_BIND(self);
|
639
|
+
VALUE index;
|
326
640
|
|
327
|
-
|
641
|
+
rb_scan_args(argc, argv, "01", &index);
|
642
|
+
if (!NIL_P(index)) {
|
643
|
+
ub4 idx = NUM2UINT(index);
|
644
|
+
if (idx >= obind->maxar_sz) {
|
645
|
+
rb_raise(rb_eRuntimeError, "data index is too big. (%u for %u)", idx, obind->maxar_sz);
|
646
|
+
}
|
647
|
+
obind->curar_idx = idx;
|
648
|
+
return rb_funcall(self, oci8_id_get, 0);
|
649
|
+
} else if (obind->maxar_sz == 0) {
|
328
650
|
obind->curar_idx = 0;
|
329
651
|
return rb_funcall(self, oci8_id_get, 0);
|
330
652
|
} else {
|
@@ -378,7 +700,7 @@ static VALUE oci8_bind_set_data(VALUE self, VALUE val)
|
|
378
700
|
ub4 idx;
|
379
701
|
Check_Type(val, T_ARRAY);
|
380
702
|
|
381
|
-
size =
|
703
|
+
size = RARRAY_LENINT(val);
|
382
704
|
if (size > obind->maxar_sz) {
|
383
705
|
rb_raise(rb_eRuntimeError, "over the max array size");
|
384
706
|
}
|
@@ -391,6 +713,36 @@ static VALUE oci8_bind_set_data(VALUE self, VALUE val)
|
|
391
713
|
return self;
|
392
714
|
}
|
393
715
|
|
716
|
+
static VALUE get_initial_chunk_size(VALUE klass)
|
717
|
+
{
|
718
|
+
return UINT2NUM(initial_chunk_size);
|
719
|
+
}
|
720
|
+
|
721
|
+
static VALUE set_initial_chunk_size(VALUE klass, VALUE arg)
|
722
|
+
{
|
723
|
+
ub4 size = NUM2UINT(arg);
|
724
|
+
if (size == 0) {
|
725
|
+
rb_raise(rb_eArgError, "Could not set zero");
|
726
|
+
}
|
727
|
+
initial_chunk_size = size;
|
728
|
+
return arg;
|
729
|
+
}
|
730
|
+
|
731
|
+
static VALUE get_max_chunk_size(VALUE klass)
|
732
|
+
{
|
733
|
+
return UINT2NUM(max_chunk_size);
|
734
|
+
}
|
735
|
+
|
736
|
+
static VALUE set_max_chunk_size(VALUE klass, VALUE arg)
|
737
|
+
{
|
738
|
+
ub4 size = NUM2UINT(arg);
|
739
|
+
if (size == 0) {
|
740
|
+
rb_raise(rb_eArgError, "Could not set zero");
|
741
|
+
}
|
742
|
+
max_chunk_size = size;
|
743
|
+
return arg;
|
744
|
+
}
|
745
|
+
|
394
746
|
static VALUE oci8_bind_initialize(VALUE self, VALUE svc, VALUE val, VALUE length, VALUE max_array_size)
|
395
747
|
{
|
396
748
|
oci8_bind_t *obind = TO_BIND(self);
|
@@ -456,6 +808,7 @@ void Init_oci8_bind(VALUE klass)
|
|
456
808
|
{
|
457
809
|
cOCI8BindTypeBase = klass;
|
458
810
|
id_bind_type = rb_intern("bind_type");
|
811
|
+
id_charset_form = rb_intern("charset_form");
|
459
812
|
sym_length = ID2SYM(rb_intern("length"));
|
460
813
|
sym_length_semantics = ID2SYM(rb_intern("length_semantics"));
|
461
814
|
sym_char = ID2SYM(rb_intern("char"));
|
@@ -464,9 +817,14 @@ void Init_oci8_bind(VALUE klass)
|
|
464
817
|
rb_define_method(cOCI8BindTypeBase, "initialize", oci8_bind_initialize, 4);
|
465
818
|
rb_define_method(cOCI8BindTypeBase, "get", oci8_bind_get, 0);
|
466
819
|
rb_define_method(cOCI8BindTypeBase, "set", oci8_bind_set, 1);
|
467
|
-
rb_define_private_method(cOCI8BindTypeBase, "get_data", oci8_bind_get_data,
|
820
|
+
rb_define_private_method(cOCI8BindTypeBase, "get_data", oci8_bind_get_data, -1);
|
468
821
|
rb_define_private_method(cOCI8BindTypeBase, "set_data", oci8_bind_set_data, 1);
|
469
822
|
|
823
|
+
rb_define_singleton_method(klass, "initial_chunk_size", get_initial_chunk_size, 0);
|
824
|
+
rb_define_singleton_method(klass, "initial_chunk_size=", set_initial_chunk_size, 1);
|
825
|
+
rb_define_singleton_method(klass, "max_chunk_size", get_max_chunk_size, 0);
|
826
|
+
rb_define_singleton_method(klass, "max_chunk_size=", set_max_chunk_size, 1);
|
827
|
+
|
470
828
|
/* register primitive data types. */
|
471
829
|
oci8_define_bind_class("String", &bind_string_data_type, bind_string_alloc);
|
472
830
|
oci8_define_bind_class("RAW", &bind_raw_data_type, bind_raw_alloc);
|
@@ -474,4 +832,6 @@ void Init_oci8_bind(VALUE klass)
|
|
474
832
|
if (oracle_client_version >= ORAVER_12_1) {
|
475
833
|
oci8_define_bind_class("Boolean", &bind_boolean_data_type, bind_boolean_alloc);
|
476
834
|
}
|
835
|
+
klass = oci8_define_bind_class("Long", &bind_long_data_type, bind_long_alloc);
|
836
|
+
klass = oci8_define_bind_class("LongRaw", &bind_long_data_type, bind_long_raw_alloc);
|
477
837
|
}
|