ruby-oci8 2.2.6.1 → 2.2.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
![dialog](osx-install-dev-tools.png)
|
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
|
}
|