duckdb 0.3.1.0 → 0.3.2.0
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 +4 -4
- data/.github/workflows/test_on_macos.yml +11 -3
- data/.github/workflows/test_on_ubuntu.yml +11 -3
- data/.github/workflows/test_on_windows.yml +16 -7
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +2 -1
- data/README.md +28 -0
- data/ext/duckdb/appender.c +7 -30
- data/ext/duckdb/blob.c +1 -5
- data/ext/duckdb/blob.h +0 -4
- data/ext/duckdb/config.c +2 -4
- data/ext/duckdb/connection.c +2 -3
- data/ext/duckdb/duckdb.c +1 -7
- data/ext/duckdb/error.c +1 -2
- data/ext/duckdb/extconf.rb +29 -20
- data/ext/duckdb/prepared_statement.c +127 -39
- data/ext/duckdb/result.c +27 -12
- data/ext/duckdb/ruby-duckdb.h +1 -16
- data/ext/duckdb/util.c +45 -0
- data/ext/duckdb/util.h +13 -0
- data/lib/duckdb/appender.rb +4 -52
- data/lib/duckdb/config.rb +1 -4
- data/lib/duckdb/converter.rb +52 -0
- data/lib/duckdb/prepared_statement.rb +112 -8
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +1 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96ad27d302c878ca4d207d86e1eb24e61be890c8585d6bd9231237900479053d
|
4
|
+
data.tar.gz: 4e0fb0daf725f53acd454ee77c179ef1af57a96b9308bc6f303853e28fe9b9a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b407a06ebf245a9534362a5106fe7d8bd74a55f2234bf2c734da067f2a8ef150472f8b40a312acd9d0957fb27515ec67fb536cf019375825e6e62d2c1ea82e8e
|
7
|
+
data.tar.gz: e2da40b4d0cb0eb25a77a6e1b383cf54a4bd8618cc31d670f59d5068c74603e41d14c4f57f9e3f909a339798f7e2a0d0143239483aef8ea8094c92cdcac417f4
|
@@ -1,14 +1,22 @@
|
|
1
1
|
name: MacOS
|
2
2
|
|
3
|
-
on:
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
types:
|
9
|
+
- opened
|
10
|
+
- synchronize
|
11
|
+
- reopened
|
4
12
|
|
5
13
|
jobs:
|
6
14
|
build:
|
7
15
|
runs-on: macos-latest
|
8
16
|
strategy:
|
9
17
|
matrix:
|
10
|
-
ruby: ['2.6.
|
11
|
-
duckdb: ['0.3.
|
18
|
+
ruby: ['2.6.9', '2.7.5', '3.0.3', '3.1.1', 'head']
|
19
|
+
duckdb: ['0.3.2', '0.3.1']
|
12
20
|
|
13
21
|
steps:
|
14
22
|
- uses: actions/checkout@v2
|
@@ -1,6 +1,14 @@
|
|
1
1
|
name: Ubuntu
|
2
2
|
|
3
|
-
on:
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
types:
|
9
|
+
- opened
|
10
|
+
- synchronize
|
11
|
+
- reopened
|
4
12
|
|
5
13
|
jobs:
|
6
14
|
build:
|
@@ -8,8 +16,8 @@ jobs:
|
|
8
16
|
runs-on: ubuntu-latest
|
9
17
|
strategy:
|
10
18
|
matrix:
|
11
|
-
ruby: ['2.6.
|
12
|
-
duckdb: ['0.3.
|
19
|
+
ruby: ['2.6.9', '2.7.5', '3.0.3', '3.1.1', 'head']
|
20
|
+
duckdb: ['0.3.2', '0.3.1']
|
13
21
|
|
14
22
|
steps:
|
15
23
|
- uses: actions/checkout@v2
|
@@ -1,14 +1,22 @@
|
|
1
1
|
name: Windows
|
2
2
|
|
3
|
-
on:
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
types:
|
9
|
+
- opened
|
10
|
+
- synchronize
|
11
|
+
- reopened
|
4
12
|
|
5
13
|
jobs:
|
6
14
|
build:
|
7
15
|
runs-on: windows-latest
|
8
16
|
strategy:
|
9
17
|
matrix:
|
10
|
-
ruby: ['2.6.
|
11
|
-
duckdb: ['0.3.
|
18
|
+
ruby: ['2.6.9', '2.7.5', '3.0.3', '3.1.1', 'mingw', 'head']
|
19
|
+
duckdb: ['0.3.2', '0.3.1']
|
12
20
|
|
13
21
|
steps:
|
14
22
|
- uses: actions/checkout@v2
|
@@ -26,15 +34,16 @@ jobs:
|
|
26
34
|
|
27
35
|
- name: extract zip file
|
28
36
|
run: |
|
29
|
-
|
37
|
+
unzip libduckdb-windows-amd64.zip
|
38
|
+
|
39
|
+
- name: setup duckdb.dll
|
40
|
+
run: |
|
41
|
+
cp duckdb.dll C:/Windows/System32/
|
30
42
|
|
31
43
|
- name: Build with Rake with Ruby ${{ matrix.ruby }}
|
32
44
|
run: |
|
33
45
|
bundle install
|
34
46
|
bundle exec rake build -- --with-duckdb-include=../../../.. --with-duckdb-lib=../../../..
|
35
|
-
- name: setup duckdb.dll
|
36
|
-
run: |
|
37
|
-
cp duckdb.dll C:/Windows/System32/
|
38
47
|
|
39
48
|
- name: rake test
|
40
49
|
run: |
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# ChangeLog
|
2
2
|
|
3
|
+
# 0.3.2.0
|
4
|
+
|
5
|
+
- bind_time, bind_timestamp, bind_date, bind_timeinterval to DuckDB::PreparedStatement
|
6
|
+
- bump duckdb 0.3.2
|
7
|
+
- bump Ruby 3.1.1, add Ruby mingw in CI.
|
8
|
+
- bump Ruby 2.6.9, 2.7.5, 3.0.3 in CI.
|
9
|
+
|
10
|
+
## BREAKING CHANGE
|
11
|
+
- drop duckdb <= 0.2.8
|
12
|
+
|
3
13
|
# 0.3.1.0
|
4
14
|
|
5
15
|
- bump duckdb to 0.3.1 in CI.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -12,11 +12,39 @@ ruby-duckdb is Ruby binding for [DuckDB](http://www.duckdb.org) database engine
|
|
12
12
|
|
13
13
|
You must have [DuckDB](http://www.duckdb.org) engine installed in order to build/use this module.
|
14
14
|
|
15
|
+
## Pre-requisite setup (Linux):
|
16
|
+
1. Head over to the [DuckDB](https://duckdb.org/) webpage
|
17
|
+
|
18
|
+
2. Download the latest C++ package release for DuckDB
|
19
|
+
|
20
|
+
3. Move the files to their respective location:
|
21
|
+
- Extract the `duckdb.h` and `duckdb.hpp` file to `/usr/local/include`
|
22
|
+
- Extract the `libduckdb.so` file to `/usr/local/lib`
|
23
|
+
|
24
|
+
```sh
|
25
|
+
unzip libduckdb-linux-amd64.zip -d libduckdb
|
26
|
+
sudo mv libduckdb/duckdb.* /usr/local/include/
|
27
|
+
sudo mv libduckdb/libduckdb.so /usr/local/lib
|
28
|
+
```
|
29
|
+
4. To create the necessary link, run `ldconfig` as root:
|
30
|
+
|
31
|
+
```sh
|
32
|
+
sudo ldconfig /usr/local/lib # adding a --verbose flag is optional - but this will let you know if the libduckdb.so library has been linked
|
33
|
+
```
|
34
|
+
## Pre-requisite setup (MacOS):
|
35
|
+
|
36
|
+
Using `brew install` is recommended.
|
37
|
+
|
38
|
+
```sh
|
39
|
+
brew install duckdb
|
40
|
+
```
|
41
|
+
|
15
42
|
## How to Install
|
16
43
|
|
17
44
|
```
|
18
45
|
gem install duckdb
|
19
46
|
```
|
47
|
+
> this will work fine with the above pre-requisite setup.
|
20
48
|
|
21
49
|
or you must specify the location of the C header and library files:
|
22
50
|
|
data/ext/duckdb/appender.c
CHANGED
@@ -48,16 +48,14 @@ static VALUE appender__append_hugeint(VALUE self, VALUE lower, VALUE upper);
|
|
48
48
|
static VALUE appender_flush(VALUE self);
|
49
49
|
static VALUE appender_close(VALUE self);
|
50
50
|
|
51
|
-
static void deallocate(void * ctx)
|
52
|
-
{
|
51
|
+
static void deallocate(void * ctx) {
|
53
52
|
rubyDuckDBAppender *p = (rubyDuckDBAppender *)ctx;
|
54
53
|
|
55
54
|
duckdb_appender_destroy(&(p->appender));
|
56
55
|
xfree(p);
|
57
56
|
}
|
58
57
|
|
59
|
-
static VALUE allocate(VALUE klass)
|
60
|
-
{
|
58
|
+
static VALUE allocate(VALUE klass) {
|
61
59
|
rubyDuckDBAppender *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBAppender));
|
62
60
|
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
63
61
|
}
|
@@ -290,16 +288,12 @@ static VALUE appender_append_null(VALUE self) {
|
|
290
288
|
}
|
291
289
|
|
292
290
|
#ifdef HAVE_DUCKDB_APPEND_DATE
|
293
|
-
static VALUE appender__append_date(VALUE self, VALUE
|
294
|
-
duckdb_date_struct dt_struct;
|
291
|
+
static VALUE appender__append_date(VALUE self, VALUE year, VALUE month, VALUE day) {
|
295
292
|
duckdb_date dt;
|
296
293
|
rubyDuckDBAppender *ctx;
|
297
294
|
|
298
295
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
299
|
-
|
300
|
-
dt_struct.month = NUM2INT(monthval);
|
301
|
-
dt_struct.day = NUM2INT(dayval);
|
302
|
-
dt = duckdb_to_date(dt_struct);
|
296
|
+
dt = to_duckdb_date_from_value(year, month, day);
|
303
297
|
|
304
298
|
if (duckdb_append_date(ctx->appender, dt) == DuckDBError) {
|
305
299
|
rb_raise(eDuckDBError, "failed to append date");
|
@@ -314,9 +308,7 @@ static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VAL
|
|
314
308
|
rubyDuckDBAppender *ctx;
|
315
309
|
|
316
310
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
317
|
-
interval
|
318
|
-
interval.days = NUM2INT(days);
|
319
|
-
interval.micros = NUM2LL(micros);
|
311
|
+
to_duckdb_interval_from_value(&interval, months, days, micros);
|
320
312
|
|
321
313
|
if (duckdb_append_interval(ctx->appender, interval) == DuckDBError) {
|
322
314
|
rb_raise(eDuckDBError, "failed to append interval");
|
@@ -327,17 +319,11 @@ static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VAL
|
|
327
319
|
|
328
320
|
#ifdef HAVE_DUCKDB_APPEND_TIME
|
329
321
|
static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
330
|
-
duckdb_time_struct time_st;
|
331
322
|
duckdb_time time;
|
332
323
|
rubyDuckDBAppender *ctx;
|
333
324
|
|
334
325
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
335
|
-
|
336
|
-
time_st.min = NUM2INT(min);
|
337
|
-
time_st.sec = NUM2INT(sec);
|
338
|
-
time_st.micros = NUM2INT(micros);
|
339
|
-
|
340
|
-
time = duckdb_to_time(time_st);
|
326
|
+
time = to_duckdb_time_from_value(hour, min, sec, micros);
|
341
327
|
|
342
328
|
if (duckdb_append_time(ctx->appender, time) == DuckDBError) {
|
343
329
|
rb_raise(eDuckDBError, "failed to append time");
|
@@ -348,22 +334,13 @@ static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec,
|
|
348
334
|
|
349
335
|
#ifdef HAVE_DUCKDB_APPEND_TIMESTAMP
|
350
336
|
static VALUE appender__append_timestamp(VALUE self, VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
351
|
-
duckdb_timestamp_struct timestamp_st;
|
352
337
|
duckdb_timestamp timestamp;
|
353
338
|
|
354
339
|
rubyDuckDBAppender *ctx;
|
355
340
|
|
356
341
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
357
342
|
|
358
|
-
|
359
|
-
timestamp_st.date.month = NUM2INT(month);
|
360
|
-
timestamp_st.date.day = NUM2INT(day);
|
361
|
-
timestamp_st.time.hour = NUM2INT(hour);
|
362
|
-
timestamp_st.time.min = NUM2INT(min);
|
363
|
-
timestamp_st.time.sec = NUM2INT(sec);
|
364
|
-
timestamp_st.time.micros = NUM2INT(micros);
|
365
|
-
|
366
|
-
timestamp = duckdb_to_timestamp(timestamp_st);
|
343
|
+
timestamp = to_duckdb_timestamp_from_value(year, month, day, hour, min, sec, micros);
|
367
344
|
|
368
345
|
if (duckdb_append_timestamp(ctx->appender, timestamp) == DuckDBError) {
|
369
346
|
rb_raise(eDuckDBError, "failed to append timestamp");
|
data/ext/duckdb/blob.c
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
#include "ruby-duckdb.h"
|
2
2
|
|
3
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
4
|
-
|
5
3
|
VALUE cDuckDBBlob;
|
6
4
|
|
7
|
-
void init_duckdb_blob(void)
|
8
|
-
{
|
5
|
+
void init_duckdb_blob(void) {
|
9
6
|
cDuckDBBlob = rb_define_class_under(mDuckDB, "Blob", rb_cString);
|
10
7
|
}
|
11
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
data/ext/duckdb/blob.h
CHANGED
data/ext/duckdb/config.c
CHANGED
@@ -11,16 +11,14 @@ static VALUE config_s_get_config_flag(VALUE self, VALUE value);
|
|
11
11
|
static VALUE config_initialize(VALUE self);
|
12
12
|
static VALUE config_set_config(VALUE self, VALUE key, VALUE value);
|
13
13
|
|
14
|
-
static void deallocate(void * ctx)
|
15
|
-
{
|
14
|
+
static void deallocate(void * ctx) {
|
16
15
|
rubyDuckDBConfig *p = (rubyDuckDBConfig *)ctx;
|
17
16
|
|
18
17
|
duckdb_destroy_config(&(p->config));
|
19
18
|
xfree(p);
|
20
19
|
}
|
21
20
|
|
22
|
-
static VALUE allocate(VALUE klass)
|
23
|
-
{
|
21
|
+
static VALUE allocate(VALUE klass) {
|
24
22
|
rubyDuckDBConfig *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBConfig));
|
25
23
|
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
26
24
|
}
|
data/ext/duckdb/connection.c
CHANGED
@@ -78,13 +78,12 @@ static VALUE duckdb_connection_query_sql(VALUE self, VALUE str) {
|
|
78
78
|
}
|
79
79
|
|
80
80
|
if (duckdb_query(ctx->con, StringValueCStr(str), &(ctxr->result)) == DuckDBError) {
|
81
|
-
rb_raise(eDuckDBError, "%s", ctxr->result
|
81
|
+
rb_raise(eDuckDBError, "%s", duckdb_result_error(&(ctxr->result)));
|
82
82
|
}
|
83
83
|
return result;
|
84
84
|
}
|
85
85
|
|
86
|
-
void init_duckdb_connection(void)
|
87
|
-
{
|
86
|
+
void init_duckdb_connection(void) {
|
88
87
|
cDuckDBConnection = rb_define_class_under(mDuckDB, "Connection", rb_cObject);
|
89
88
|
rb_define_alloc_func(cDuckDBConnection, allocate);
|
90
89
|
|
data/ext/duckdb/duckdb.c
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
VALUE mDuckDB;
|
4
4
|
|
5
5
|
void
|
6
|
-
Init_duckdb_native(void)
|
7
|
-
{
|
6
|
+
Init_duckdb_native(void) {
|
8
7
|
mDuckDB = rb_define_module("DuckDB");
|
9
8
|
|
10
9
|
init_duckdb_error();
|
@@ -12,13 +11,8 @@ Init_duckdb_native(void)
|
|
12
11
|
init_duckdb_connection();
|
13
12
|
init_duckdb_result();
|
14
13
|
init_duckdb_prepared_statement();
|
15
|
-
|
16
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
17
|
-
|
18
14
|
init_duckdb_blob();
|
19
15
|
|
20
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
21
|
-
|
22
16
|
#ifdef HAVE_DUCKDB_APPENDER_CREATE
|
23
17
|
|
24
18
|
init_duckdb_appender();
|
data/ext/duckdb/error.c
CHANGED
data/ext/duckdb/extconf.rb
CHANGED
@@ -1,24 +1,33 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
3
|
dir_config('duckdb')
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
have_func('duckdb_appender_create', 'duckdb.h')
|
14
|
-
have_func('duckdb_free', 'duckdb.h')
|
15
|
-
have_func('duckdb_create_config', 'duckdb.h')
|
16
|
-
have_func('duckdb_open_ext', 'duckdb.h')
|
17
|
-
have_func('duckdb_prepare_error', 'duckdb.h')
|
18
|
-
have_func('duckdb_append_date', 'duckdb.h')
|
19
|
-
have_func('duckdb_append_interval', 'duckdb.h')
|
20
|
-
have_func('duckdb_append_time', 'duckdb.h')
|
21
|
-
have_func('duckdb_append_timestamp', 'duckdb.h')
|
22
|
-
have_func('duckdb_append_hugeint', 'duckdb.h')
|
23
|
-
create_makefile('duckdb/duckdb_native')
|
4
|
+
|
5
|
+
raise 'duckdb library is not found. Install duckdb library file and header file.' unless have_library('duckdb')
|
6
|
+
|
7
|
+
raise 'duckdb >= 0.2.9 is required. Install duckdb >= 0.2.9' unless have_func('duckdb_value_is_null', 'duckdb.h')
|
8
|
+
|
9
|
+
if have_func('duckdb_nparams(NULL)', 'duckdb.h')
|
10
|
+
$defs << '-DHAVE_DUCKDB_NPARAMS_029'
|
11
|
+
elsif have_func('duckdb_nparams(NULL, NULL)', 'duckdb.h')
|
12
|
+
$defs << '-DHAVE_DUCKDB_NPARAMS_028'
|
24
13
|
end
|
14
|
+
|
15
|
+
have_func('duckdb_appender_create', 'duckdb.h')
|
16
|
+
have_func('duckdb_free', 'duckdb.h')
|
17
|
+
|
18
|
+
have_func('duckdb_create_config', 'duckdb.h')
|
19
|
+
have_func('duckdb_open_ext', 'duckdb.h')
|
20
|
+
have_func('duckdb_prepare_error', 'duckdb.h')
|
21
|
+
|
22
|
+
have_func('duckdb_append_date', 'duckdb.h')
|
23
|
+
have_func('duckdb_append_interval', 'duckdb.h')
|
24
|
+
have_func('duckdb_append_time', 'duckdb.h')
|
25
|
+
have_func('duckdb_append_timestamp', 'duckdb.h')
|
26
|
+
have_func('duckdb_append_hugeint', 'duckdb.h')
|
27
|
+
|
28
|
+
have_func('duckdb_bind_date', 'duckdb.h')
|
29
|
+
have_func('duckdb_bind_time', 'duckdb.h')
|
30
|
+
have_func('duckdb_bind_timestamp', 'duckdb.h')
|
31
|
+
have_func('duckdb_bind_interval', 'duckdb.h')
|
32
|
+
|
33
|
+
create_makefile('duckdb/duckdb_native')
|
@@ -2,22 +2,53 @@
|
|
2
2
|
|
3
3
|
static VALUE cDuckDBPreparedStatement;
|
4
4
|
|
5
|
-
static void deallocate(void *ctx)
|
6
|
-
|
5
|
+
static void deallocate(void *ctx);
|
6
|
+
static VALUE allocate(VALUE klass);
|
7
|
+
static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query);
|
8
|
+
static VALUE duckdb_prepared_statement_nparams(VALUE self);
|
9
|
+
static VALUE duckdb_prepared_statement_execute(VALUE self);
|
10
|
+
static idx_t check_index(VALUE vidx);
|
11
|
+
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val);
|
12
|
+
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val);
|
13
|
+
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val);
|
14
|
+
static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val);
|
15
|
+
static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val);
|
16
|
+
static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val);
|
17
|
+
static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val);
|
18
|
+
static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str);
|
19
|
+
static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob);
|
20
|
+
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx);
|
21
|
+
|
22
|
+
#ifdef HAVE_DUCKDB_BIND_DATE
|
23
|
+
static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day);
|
24
|
+
#endif
|
25
|
+
|
26
|
+
#ifdef HAVE_DUCKDB_BIND_TIME
|
27
|
+
static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#ifdef HAVE_DUCKDB_BIND_TIMESTAMP
|
31
|
+
static VALUE duckdb_prepared_statement__bind_timestamp(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#ifdef HAVE_DUCKDB_BIND_INTERVAL
|
35
|
+
static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VALUE months, VALUE days, VALUE micros);
|
36
|
+
#endif
|
37
|
+
|
38
|
+
|
39
|
+
static void deallocate(void *ctx) {
|
7
40
|
rubyDuckDBPreparedStatement *p = (rubyDuckDBPreparedStatement *)ctx;
|
8
41
|
|
9
42
|
duckdb_destroy_prepare(&(p->prepared_statement));
|
10
43
|
xfree(p);
|
11
44
|
}
|
12
45
|
|
13
|
-
static VALUE allocate(VALUE klass)
|
14
|
-
{
|
46
|
+
static VALUE allocate(VALUE klass) {
|
15
47
|
rubyDuckDBPreparedStatement *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBPreparedStatement));
|
16
48
|
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
17
49
|
}
|
18
50
|
|
19
|
-
static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query)
|
20
|
-
{
|
51
|
+
static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query) {
|
21
52
|
rubyDuckDBConnection *ctxcon;
|
22
53
|
rubyDuckDBPreparedStatement *ctx;
|
23
54
|
|
@@ -40,8 +71,7 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q
|
|
40
71
|
return self;
|
41
72
|
}
|
42
73
|
|
43
|
-
static VALUE duckdb_prepared_statement_nparams(VALUE self)
|
44
|
-
{
|
74
|
+
static VALUE duckdb_prepared_statement_nparams(VALUE self) {
|
45
75
|
rubyDuckDBPreparedStatement *ctx;
|
46
76
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
47
77
|
#ifdef HAVE_DUCKDB_NPARAMS_029
|
@@ -55,8 +85,7 @@ static VALUE duckdb_prepared_statement_nparams(VALUE self)
|
|
55
85
|
}
|
56
86
|
|
57
87
|
|
58
|
-
static VALUE duckdb_prepared_statement_execute(VALUE self)
|
59
|
-
{
|
88
|
+
static VALUE duckdb_prepared_statement_execute(VALUE self) {
|
60
89
|
rubyDuckDBPreparedStatement *ctx;
|
61
90
|
rubyDuckDBResult *ctxr;
|
62
91
|
VALUE result = create_result();
|
@@ -64,13 +93,12 @@ static VALUE duckdb_prepared_statement_execute(VALUE self)
|
|
64
93
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
65
94
|
Data_Get_Struct(result, rubyDuckDBResult, ctxr);
|
66
95
|
if (duckdb_execute_prepared(ctx->prepared_statement, &(ctxr->result)) == DuckDBError) {
|
67
|
-
rb_raise(eDuckDBError, "%s", ctxr->result
|
96
|
+
rb_raise(eDuckDBError, "%s", duckdb_result_error(&(ctxr->result)));
|
68
97
|
}
|
69
98
|
return result;
|
70
99
|
}
|
71
100
|
|
72
|
-
static idx_t check_index(VALUE vidx)
|
73
|
-
{
|
101
|
+
static idx_t check_index(VALUE vidx) {
|
74
102
|
idx_t idx = FIX2INT(vidx);
|
75
103
|
if (idx <= 0) {
|
76
104
|
rb_raise(rb_eArgError, "index of parameter must be greater than 0");
|
@@ -78,8 +106,7 @@ static idx_t check_index(VALUE vidx)
|
|
78
106
|
return idx;
|
79
107
|
}
|
80
108
|
|
81
|
-
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val)
|
82
|
-
{
|
109
|
+
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val) {
|
83
110
|
rubyDuckDBPreparedStatement *ctx;
|
84
111
|
idx_t idx = check_index(vidx);
|
85
112
|
|
@@ -94,8 +121,7 @@ static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE v
|
|
94
121
|
return self;
|
95
122
|
}
|
96
123
|
|
97
|
-
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val)
|
98
|
-
{
|
124
|
+
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val) {
|
99
125
|
rubyDuckDBPreparedStatement *ctx;
|
100
126
|
idx_t idx = check_index(vidx);
|
101
127
|
int8_t i8val = (int8_t)NUM2INT(val);
|
@@ -108,8 +134,7 @@ static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE v
|
|
108
134
|
return self;
|
109
135
|
}
|
110
136
|
|
111
|
-
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val)
|
112
|
-
{
|
137
|
+
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val) {
|
113
138
|
rubyDuckDBPreparedStatement *ctx;
|
114
139
|
idx_t idx = check_index(vidx);
|
115
140
|
int16_t i16val = NUM2INT(val);
|
@@ -122,8 +147,7 @@ static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE
|
|
122
147
|
return self;
|
123
148
|
}
|
124
149
|
|
125
|
-
static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val)
|
126
|
-
{
|
150
|
+
static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val) {
|
127
151
|
rubyDuckDBPreparedStatement *ctx;
|
128
152
|
idx_t idx = check_index(vidx);
|
129
153
|
int32_t i32val = NUM2INT(val);
|
@@ -136,8 +160,7 @@ static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE
|
|
136
160
|
return self;
|
137
161
|
}
|
138
162
|
|
139
|
-
static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val)
|
140
|
-
{
|
163
|
+
static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val) {
|
141
164
|
rubyDuckDBPreparedStatement *ctx;
|
142
165
|
idx_t idx = check_index(vidx);
|
143
166
|
int64_t i64val = NUM2LL(val);
|
@@ -150,8 +173,7 @@ static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE
|
|
150
173
|
return self;
|
151
174
|
}
|
152
175
|
|
153
|
-
static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val)
|
154
|
-
{
|
176
|
+
static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val) {
|
155
177
|
rubyDuckDBPreparedStatement *ctx;
|
156
178
|
idx_t idx = check_index(vidx);
|
157
179
|
double dbl = NUM2DBL(val);
|
@@ -164,8 +186,7 @@ static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE
|
|
164
186
|
return self;
|
165
187
|
}
|
166
188
|
|
167
|
-
static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val)
|
168
|
-
{
|
189
|
+
static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val) {
|
169
190
|
rubyDuckDBPreparedStatement *ctx;
|
170
191
|
idx_t idx = check_index(vidx);
|
171
192
|
double dbl = NUM2DBL(val);
|
@@ -178,8 +199,7 @@ static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE
|
|
178
199
|
return self;
|
179
200
|
}
|
180
201
|
|
181
|
-
static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str)
|
182
|
-
{
|
202
|
+
static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str) {
|
183
203
|
rubyDuckDBPreparedStatement *ctx;
|
184
204
|
idx_t idx = check_index(vidx);
|
185
205
|
|
@@ -190,9 +210,7 @@ static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALU
|
|
190
210
|
return self;
|
191
211
|
}
|
192
212
|
|
193
|
-
|
194
|
-
static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob)
|
195
|
-
{
|
213
|
+
static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob) {
|
196
214
|
rubyDuckDBPreparedStatement *ctx;
|
197
215
|
idx_t idx = check_index(vidx);
|
198
216
|
|
@@ -202,10 +220,8 @@ static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE b
|
|
202
220
|
}
|
203
221
|
return self;
|
204
222
|
}
|
205
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
206
223
|
|
207
|
-
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
|
208
|
-
{
|
224
|
+
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx) {
|
209
225
|
rubyDuckDBPreparedStatement *ctx;
|
210
226
|
idx_t idx = check_index(vidx);
|
211
227
|
|
@@ -216,8 +232,72 @@ static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
|
|
216
232
|
return self;
|
217
233
|
}
|
218
234
|
|
219
|
-
|
220
|
-
{
|
235
|
+
#ifdef HAVE_DUCKDB_BIND_DATE
|
236
|
+
static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day) {
|
237
|
+
rubyDuckDBPreparedStatement *ctx;
|
238
|
+
duckdb_date dt;
|
239
|
+
idx_t idx = check_index(vidx);
|
240
|
+
|
241
|
+
dt = to_duckdb_date_from_value(year, month, day);
|
242
|
+
|
243
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
244
|
+
if (duckdb_bind_date(ctx->prepared_statement, idx, dt) == DuckDBError) {
|
245
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
246
|
+
}
|
247
|
+
return self;
|
248
|
+
}
|
249
|
+
#endif
|
250
|
+
|
251
|
+
#ifdef HAVE_DUCKDB_BIND_TIME
|
252
|
+
static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE hour, VALUE min, VALUE sec, VALUE micros){
|
253
|
+
rubyDuckDBPreparedStatement *ctx;
|
254
|
+
duckdb_time time;
|
255
|
+
|
256
|
+
idx_t idx = check_index(vidx);
|
257
|
+
|
258
|
+
time = to_duckdb_time_from_value(hour, min, sec, micros);
|
259
|
+
|
260
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
261
|
+
if (duckdb_bind_time(ctx->prepared_statement, idx, time) == DuckDBError) {
|
262
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
263
|
+
}
|
264
|
+
return self;
|
265
|
+
}
|
266
|
+
#endif
|
267
|
+
|
268
|
+
#ifdef HAVE_DUCKDB_BIND_TIMESTAMP
|
269
|
+
static VALUE duckdb_prepared_statement__bind_timestamp(VALUE self, VALUE vidx, VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
270
|
+
duckdb_timestamp timestamp;
|
271
|
+
rubyDuckDBPreparedStatement *ctx;
|
272
|
+
idx_t idx = check_index(vidx);
|
273
|
+
|
274
|
+
timestamp = to_duckdb_timestamp_from_value(year, month, day, hour, min, sec, micros);
|
275
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
276
|
+
|
277
|
+
if (duckdb_bind_timestamp(ctx->prepared_statement, idx, timestamp) == DuckDBError) {
|
278
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
279
|
+
}
|
280
|
+
return self;
|
281
|
+
}
|
282
|
+
#endif
|
283
|
+
|
284
|
+
#ifdef HAVE_DUCKDB_BIND_INTERVAL
|
285
|
+
static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VALUE months, VALUE days, VALUE micros) {
|
286
|
+
duckdb_interval interval;
|
287
|
+
rubyDuckDBPreparedStatement *ctx;
|
288
|
+
idx_t idx = check_index(vidx);
|
289
|
+
|
290
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
291
|
+
to_duckdb_interval_from_value(&interval, months, days, micros);
|
292
|
+
|
293
|
+
if (duckdb_bind_interval(ctx->prepared_statement, idx, interval) == DuckDBError) {
|
294
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
295
|
+
}
|
296
|
+
return self;
|
297
|
+
}
|
298
|
+
#endif
|
299
|
+
|
300
|
+
void init_duckdb_prepared_statement(void) {
|
221
301
|
cDuckDBPreparedStatement = rb_define_class_under(mDuckDB, "PreparedStatement", rb_cObject);
|
222
302
|
|
223
303
|
rb_define_alloc_func(cDuckDBPreparedStatement, allocate);
|
@@ -233,8 +313,16 @@ void init_duckdb_prepared_statement(void)
|
|
233
313
|
rb_define_method(cDuckDBPreparedStatement, "bind_float", duckdb_prepared_statement_bind_float, 2);
|
234
314
|
rb_define_method(cDuckDBPreparedStatement, "bind_double", duckdb_prepared_statement_bind_double, 2);
|
235
315
|
rb_define_method(cDuckDBPreparedStatement, "bind_varchar", duckdb_prepared_statement_bind_varchar, 2);
|
236
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
237
316
|
rb_define_method(cDuckDBPreparedStatement, "bind_blob", duckdb_prepared_statement_bind_blob, 2);
|
238
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
239
317
|
rb_define_method(cDuckDBPreparedStatement, "bind_null", duckdb_prepared_statement_bind_null, 1);
|
318
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_date", duckdb_prepared_statement__bind_date, 4);
|
319
|
+
#ifdef HAVE_DUCKDB_BIND_TIME
|
320
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_time", duckdb_prepared_statement__bind_time, 5);
|
321
|
+
#endif
|
322
|
+
#ifdef HAVE_DUCKDB_BIND_TIMESTAMP
|
323
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_timestamp", duckdb_prepared_statement__bind_timestamp, 8);
|
324
|
+
#endif
|
325
|
+
#ifdef HAVE_DUCKDB_BIND_INTERVAL
|
326
|
+
rb_define_private_method(cDuckDBPreparedStatement, "_bind_interval", duckdb_prepared_statement__bind_interval, 4);
|
327
|
+
#endif
|
240
328
|
}
|
data/ext/duckdb/result.c
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
static VALUE cDuckDBResult;
|
4
4
|
|
5
|
+
static void deallocate(void *ctx);
|
6
|
+
static VALUE allocate(VALUE klass);
|
7
|
+
static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
8
|
+
static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
9
|
+
static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
10
|
+
static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
11
|
+
static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
12
|
+
static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
13
|
+
static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
14
|
+
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx);
|
15
|
+
static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx);
|
16
|
+
static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj);
|
17
|
+
static VALUE duckdb_result_each(VALUE oDuckDBResult);
|
18
|
+
static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult);
|
19
|
+
|
5
20
|
static void deallocate(void *ctx) {
|
6
21
|
rubyDuckDBResult *p = (rubyDuckDBResult *)ctx;
|
7
22
|
|
@@ -44,7 +59,6 @@ static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_
|
|
44
59
|
return DBL2NUM(dval);
|
45
60
|
}
|
46
61
|
|
47
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
48
62
|
static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
49
63
|
VALUE str;
|
50
64
|
duckdb_blob bval = duckdb_value_blob(result, col_idx, row_idx);
|
@@ -60,15 +74,14 @@ static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx,
|
|
60
74
|
|
61
75
|
return str;
|
62
76
|
}
|
63
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
64
77
|
|
65
78
|
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
66
79
|
char *p;
|
67
80
|
VALUE obj = Qnil;
|
68
|
-
if (result
|
81
|
+
if (duckdb_value_is_null(result, col_idx, row_idx)) {
|
69
82
|
return obj;
|
70
83
|
}
|
71
|
-
switch(result
|
84
|
+
switch(duckdb_column_type(result, col_idx)) {
|
72
85
|
case DUCKDB_TYPE_BOOLEAN:
|
73
86
|
return to_ruby_obj_boolean(result, col_idx, row_idx);
|
74
87
|
case DUCKDB_TYPE_SMALLINT:
|
@@ -81,10 +94,8 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
|
81
94
|
return to_ruby_obj_float(result, col_idx, row_idx);
|
82
95
|
case DUCKDB_TYPE_DOUBLE:
|
83
96
|
return to_ruby_obj_double(result, col_idx, row_idx);
|
84
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
85
97
|
case DUCKDB_TYPE_BLOB:
|
86
98
|
return to_ruby_obj_string_from_blob(result, col_idx, row_idx);
|
87
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
88
99
|
default:
|
89
100
|
p = duckdb_value_varchar(result, col_idx, row_idx);
|
90
101
|
if (p) {
|
@@ -94,7 +105,7 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
|
94
105
|
#else
|
95
106
|
free(p);
|
96
107
|
#endif /* HAVE_DUCKDB_FREE */
|
97
|
-
if (result
|
108
|
+
if (duckdb_column_type(result, col_idx) == DUCKDB_TYPE_HUGEINT) {
|
98
109
|
obj = rb_funcall(obj, rb_intern("to_i"), 0);
|
99
110
|
}
|
100
111
|
}
|
@@ -104,8 +115,10 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
|
104
115
|
|
105
116
|
static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx) {
|
106
117
|
idx_t col_idx;
|
107
|
-
|
108
|
-
|
118
|
+
idx_t column_count = duckdb_column_count(&(ctx->result));
|
119
|
+
|
120
|
+
VALUE ary = rb_ary_new2(column_count);
|
121
|
+
for(col_idx = 0; col_idx < column_count; col_idx++) {
|
109
122
|
rb_ary_store(ary, col_idx, to_ruby_obj(&(ctx->result), col_idx, row_idx));
|
110
123
|
}
|
111
124
|
return ary;
|
@@ -115,17 +128,19 @@ static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj)
|
|
115
128
|
rubyDuckDBResult *ctx;
|
116
129
|
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
117
130
|
|
118
|
-
return LONG2FIX(ctx->result
|
131
|
+
return LONG2FIX(duckdb_row_count(&(ctx->result)));
|
119
132
|
}
|
120
133
|
|
121
134
|
static VALUE duckdb_result_each(VALUE oDuckDBResult) {
|
122
135
|
rubyDuckDBResult *ctx;
|
123
136
|
idx_t row_idx = 0;
|
137
|
+
idx_t row_count = 0;
|
124
138
|
|
125
139
|
RETURN_SIZED_ENUMERATOR(oDuckDBResult, 0, 0, duckdb_result_row_size);
|
126
140
|
|
127
141
|
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
128
|
-
|
142
|
+
row_count = duckdb_row_count(&(ctx->result));
|
143
|
+
for (row_idx = 0; row_idx < row_count; row_idx++) {
|
129
144
|
rb_yield(row_array(ctx, row_idx));
|
130
145
|
}
|
131
146
|
return oDuckDBResult;
|
@@ -156,7 +171,7 @@ static VALUE duckdb_result_each(VALUE oDuckDBResult) {
|
|
156
171
|
static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult) {
|
157
172
|
rubyDuckDBResult *ctx;
|
158
173
|
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
159
|
-
return LL2NUM(ctx->result
|
174
|
+
return LL2NUM(duckdb_rows_changed(&(ctx->result)));
|
160
175
|
}
|
161
176
|
|
162
177
|
VALUE create_result(void) {
|
data/ext/duckdb/ruby-duckdb.h
CHANGED
@@ -8,13 +8,9 @@
|
|
8
8
|
#include "./connection.h"
|
9
9
|
#include "./result.h"
|
10
10
|
#include "./prepared_statement.h"
|
11
|
-
|
12
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
11
|
+
#include "./util.h"
|
13
12
|
|
14
13
|
#include "./blob.h"
|
15
|
-
|
16
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
17
|
-
|
18
14
|
#ifdef HAVE_DUCKDB_APPENDER_CREATE
|
19
15
|
|
20
16
|
#include "./appender.h"
|
@@ -30,19 +26,8 @@
|
|
30
26
|
extern VALUE mDuckDB;
|
31
27
|
extern VALUE cDuckDBDatabase;
|
32
28
|
extern VALUE cDuckDBConnection;
|
33
|
-
|
34
|
-
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
35
|
-
|
36
29
|
extern VALUE cDuckDBBlob;
|
37
|
-
|
38
|
-
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
39
|
-
|
40
|
-
#ifdef HAVE_DUCKDB_CREATE_CONFIG
|
41
|
-
|
42
30
|
extern VALUE cDuckDBConfig;
|
43
|
-
|
44
|
-
#endif /* HAVE_DUCKDB_CREATE_CONFIG */
|
45
|
-
|
46
31
|
extern VALUE eDuckDBError;
|
47
32
|
|
48
33
|
#endif
|
data/ext/duckdb/util.c
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#include "ruby-duckdb.h"
|
2
|
+
|
3
|
+
#ifdef HAVE_DUCKDB_APPEND_DATE
|
4
|
+
|
5
|
+
duckdb_date to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day) {
|
6
|
+
duckdb_date_struct dt_struct;
|
7
|
+
|
8
|
+
dt_struct.year = NUM2INT(year);
|
9
|
+
dt_struct.month = NUM2INT(month);
|
10
|
+
dt_struct.day = NUM2INT(day);
|
11
|
+
|
12
|
+
return duckdb_to_date(dt_struct);
|
13
|
+
}
|
14
|
+
|
15
|
+
duckdb_time to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
16
|
+
duckdb_time_struct time_st;
|
17
|
+
|
18
|
+
time_st.hour = NUM2INT(hour);
|
19
|
+
time_st.min = NUM2INT(min);
|
20
|
+
time_st.sec = NUM2INT(sec);
|
21
|
+
time_st.micros = NUM2INT(micros);
|
22
|
+
|
23
|
+
return duckdb_to_time(time_st);
|
24
|
+
}
|
25
|
+
|
26
|
+
duckdb_timestamp to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
27
|
+
duckdb_timestamp_struct timestamp_st;
|
28
|
+
|
29
|
+
timestamp_st.date.year = NUM2INT(year);
|
30
|
+
timestamp_st.date.month = NUM2INT(month);
|
31
|
+
timestamp_st.date.day = NUM2INT(day);
|
32
|
+
timestamp_st.time.hour = NUM2INT(hour);
|
33
|
+
timestamp_st.time.min = NUM2INT(min);
|
34
|
+
timestamp_st.time.sec = NUM2INT(sec);
|
35
|
+
timestamp_st.time.micros = NUM2INT(micros);
|
36
|
+
|
37
|
+
return duckdb_to_timestamp(timestamp_st);
|
38
|
+
}
|
39
|
+
|
40
|
+
void to_duckdb_interval_from_value(duckdb_interval* interval, VALUE months, VALUE days, VALUE micros) {
|
41
|
+
interval->months = NUM2INT(months);
|
42
|
+
interval->days = NUM2INT(days);
|
43
|
+
interval->micros = NUM2LL(micros);
|
44
|
+
}
|
45
|
+
#endif
|
data/ext/duckdb/util.h
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef RUBY_DUCKDB_UTIL_H
|
2
|
+
#define RUBY_DUCKDB_UTIL_H
|
3
|
+
|
4
|
+
#ifdef HAVE_DUCKDB_APPEND_DATE
|
5
|
+
|
6
|
+
duckdb_date to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day);
|
7
|
+
duckdb_time to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
8
|
+
duckdb_timestamp to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
9
|
+
void to_duckdb_interval_from_value(duckdb_interval* interval, VALUE months, VALUE days, VALUE micros);
|
10
|
+
|
11
|
+
#endif
|
12
|
+
|
13
|
+
#endif
|
data/lib/duckdb/appender.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'time'
|
3
|
+
require_relative './converter'
|
3
4
|
|
4
5
|
module DuckDB
|
5
6
|
if defined?(DuckDB::Appender)
|
@@ -13,6 +14,8 @@ module DuckDB
|
|
13
14
|
# appender.append_row(1, 'Alice')
|
14
15
|
#
|
15
16
|
class Appender
|
17
|
+
include DuckDB::Converter
|
18
|
+
|
16
19
|
RANGE_INT16 = -32_768..32_767
|
17
20
|
RANGE_INT32 = -2_147_483_648..2_147_483_647
|
18
21
|
RANGE_INT64 = -9_223_372_036_854_775_808..9_223_372_036_854_775_807
|
@@ -197,11 +200,7 @@ module DuckDB
|
|
197
200
|
append_hugeint(value)
|
198
201
|
end
|
199
202
|
when String
|
200
|
-
|
201
|
-
blob?(value) ? append_blob(value) : append_varchar(value)
|
202
|
-
else
|
203
|
-
append_varchar(value)
|
204
|
-
end
|
203
|
+
blob?(value) ? append_blob(value) : append_varchar(value)
|
205
204
|
when TrueClass, FalseClass
|
206
205
|
append_bool(value)
|
207
206
|
when Time
|
@@ -246,53 +245,6 @@ module DuckDB
|
|
246
245
|
def blob?(value)
|
247
246
|
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
248
247
|
end
|
249
|
-
|
250
|
-
def iso8601_interval_to_hash(value)
|
251
|
-
digit = ''
|
252
|
-
time = false
|
253
|
-
hash = {}
|
254
|
-
hash.default = 0
|
255
|
-
|
256
|
-
value.each_char do |c|
|
257
|
-
if '-0123456789.'.include?(c)
|
258
|
-
digit += c
|
259
|
-
elsif c == 'T'
|
260
|
-
time = true
|
261
|
-
digit = ''
|
262
|
-
elsif c == 'M'
|
263
|
-
m_interval_to_hash(hash, digit, time)
|
264
|
-
digit = ''
|
265
|
-
elsif c == 'S'
|
266
|
-
s_interval_to_hash(hash, digit)
|
267
|
-
digit = ''
|
268
|
-
elsif 'YDH'.include?(c)
|
269
|
-
hash[c] = digit.to_i
|
270
|
-
digit = ''
|
271
|
-
elsif c != 'P'
|
272
|
-
raise ArgumentError, "The argument `#{value}` can't be parse."
|
273
|
-
end
|
274
|
-
end
|
275
|
-
hash
|
276
|
-
end
|
277
|
-
|
278
|
-
def m_interval_to_hash(hash, digit, time)
|
279
|
-
key = time ? 'TM' : 'M'
|
280
|
-
hash[key] = digit.to_i
|
281
|
-
end
|
282
|
-
|
283
|
-
def s_interval_to_hash(hash, digit)
|
284
|
-
sec, msec = digit.split('.')
|
285
|
-
hash['S'] = sec.to_i
|
286
|
-
hash['MS'] = "#{msec}000000"[0, 6].to_i
|
287
|
-
hash['MS'] *= -1 if hash['S'].negative?
|
288
|
-
end
|
289
|
-
|
290
|
-
def hash_to__append_interval_args(hash)
|
291
|
-
months = hash['Y'] * 12 + hash['M']
|
292
|
-
days = hash['D']
|
293
|
-
micros = (hash['H'] * 3600 + hash['TM'] * 60 + hash['S']) * 1_000_000 + hash['MS']
|
294
|
-
[months, days, micros]
|
295
|
-
end
|
296
248
|
end
|
297
249
|
end
|
298
250
|
end
|
data/lib/duckdb/config.rb
CHANGED
@@ -34,10 +34,7 @@ module DuckDB
|
|
34
34
|
# configs['default_order'] # => "The order type used when none is specified ([ASC] or DESC)"
|
35
35
|
#
|
36
36
|
def key_descriptions
|
37
|
-
|
38
|
-
|
39
|
-
n = size
|
40
|
-
@key_descriptions = (0...n).each_with_object({}) do |i, hash|
|
37
|
+
@key_descriptions ||= (0...size).each_with_object({}) do |i, hash|
|
41
38
|
key, description = key_description(i)
|
42
39
|
hash[key] = description
|
43
40
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module DuckDB
|
2
|
+
module Converter
|
3
|
+
private
|
4
|
+
|
5
|
+
def iso8601_interval_to_hash(value)
|
6
|
+
digit = ''
|
7
|
+
time = false
|
8
|
+
hash = {}
|
9
|
+
hash.default = 0
|
10
|
+
|
11
|
+
value.each_char do |c|
|
12
|
+
if '-0123456789.'.include?(c)
|
13
|
+
digit += c
|
14
|
+
elsif c == 'T'
|
15
|
+
time = true
|
16
|
+
digit = ''
|
17
|
+
elsif c == 'M'
|
18
|
+
m_interval_to_hash(hash, digit, time)
|
19
|
+
digit = ''
|
20
|
+
elsif c == 'S'
|
21
|
+
s_interval_to_hash(hash, digit)
|
22
|
+
digit = ''
|
23
|
+
elsif 'YDH'.include?(c)
|
24
|
+
hash[c] = digit.to_i
|
25
|
+
digit = ''
|
26
|
+
elsif c != 'P'
|
27
|
+
raise ArgumentError, "The argument `#{value}` can't be parse."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
|
33
|
+
def m_interval_to_hash(hash, digit, time)
|
34
|
+
key = time ? 'TM' : 'M'
|
35
|
+
hash[key] = digit.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def s_interval_to_hash(hash, digit)
|
39
|
+
sec, msec = digit.split('.')
|
40
|
+
hash['S'] = sec.to_i
|
41
|
+
hash['MS'] = "#{msec}000000"[0, 6].to_i
|
42
|
+
hash['MS'] *= -1 if hash['S'].negative?
|
43
|
+
end
|
44
|
+
|
45
|
+
def hash_to__append_interval_args(hash)
|
46
|
+
months = hash['Y'] * 12 + hash['M']
|
47
|
+
days = hash['D']
|
48
|
+
micros = (hash['H'] * 3600 + hash['TM'] * 60 + hash['S']) * 1_000_000 + hash['MS']
|
49
|
+
[months, days, micros]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'date'
|
2
|
+
require_relative './converter'
|
2
3
|
|
3
4
|
module DuckDB
|
4
5
|
# The DuckDB::PreparedStatement encapsulates connection with DuckDB prepared
|
@@ -12,6 +13,7 @@ module DuckDB
|
|
12
13
|
# stmt.bind(1, 'email@example.com')
|
13
14
|
# stmt.execute
|
14
15
|
class PreparedStatement
|
16
|
+
include DuckDB::Converter
|
15
17
|
|
16
18
|
RANGE_INT16 = -32768..32767
|
17
19
|
RANGE_INT32 = -2147483648..2147483647
|
@@ -27,8 +29,114 @@ module DuckDB
|
|
27
29
|
end
|
28
30
|
|
29
31
|
# binds i-th parameter with SQL prepared statement.
|
30
|
-
# The first argument is index of parameter.
|
31
|
-
# 1 not 0.
|
32
|
+
# The first argument is index of parameter.
|
33
|
+
# The index of first parameter is 1 not 0.
|
34
|
+
# The second argument value is to expected date.
|
35
|
+
#
|
36
|
+
# require 'duckdb'
|
37
|
+
# db = DuckDB::Database.open('duckdb_database')
|
38
|
+
# con = db.connect
|
39
|
+
# sql ='SELECT name FROM users WHERE birth_day = ?'
|
40
|
+
# stmt = PreparedStatement.new(con, sql)
|
41
|
+
# stmt.bind(1, Date.today)
|
42
|
+
# # or you can specify date string.
|
43
|
+
# # stmt.bind(1, '2021-02-23')
|
44
|
+
def bind_date(i, value)
|
45
|
+
case value
|
46
|
+
when Date, Time
|
47
|
+
date = value
|
48
|
+
else
|
49
|
+
begin
|
50
|
+
date = Date.parse(value)
|
51
|
+
rescue => e
|
52
|
+
raise(ArgumentError, "Cannot parse argument value to date. #{e.message}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
_bind_date(i, date.year, date.month, date.day)
|
57
|
+
end
|
58
|
+
|
59
|
+
# binds i-th parameter with SQL prepared statement.
|
60
|
+
# The first argument is index of parameter.
|
61
|
+
# The index of first parameter is 1 not 0.
|
62
|
+
# The second argument value is to expected time value.
|
63
|
+
#
|
64
|
+
# require 'duckdb'
|
65
|
+
# db = DuckDB::Database.open('duckdb_database')
|
66
|
+
# con = db.connect
|
67
|
+
# sql ='SELECT name FROM users WHERE birth_time = ?'
|
68
|
+
# stmt = PreparedStatement.new(con, sql)
|
69
|
+
# stmt.bind(1, Time.now)
|
70
|
+
# # or you can specify time string.
|
71
|
+
# # stmt.bind(1, '07:39:45')
|
72
|
+
def bind_time(i, value)
|
73
|
+
case value
|
74
|
+
when Time
|
75
|
+
time = value
|
76
|
+
else
|
77
|
+
begin
|
78
|
+
time = Time.parse(value)
|
79
|
+
rescue => e
|
80
|
+
raise(ArgumentError, "Cannot parse argument value to time. #{e.message}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
_bind_time(i, time.hour, time.min, time.sec, time.usec)
|
85
|
+
end
|
86
|
+
|
87
|
+
# binds i-th parameter with SQL prepared statement.
|
88
|
+
# The first argument is index of parameter.
|
89
|
+
# The index of first parameter is 1 not 0.
|
90
|
+
# The second argument value is to expected time value.
|
91
|
+
#
|
92
|
+
# require 'duckdb'
|
93
|
+
# db = DuckDB::Database.open('duckdb_database')
|
94
|
+
# con = db.connect
|
95
|
+
# sql ='SELECT name FROM users WHERE created_at = ?'
|
96
|
+
# stmt = PreparedStatement.new(con, sql)
|
97
|
+
# stmt.bind(1, Time.now)
|
98
|
+
# # or you can specify timestamp string.
|
99
|
+
# # stmt.bind(1, '2022-02-23 07:39:45')
|
100
|
+
def bind_timestamp(i, value)
|
101
|
+
case value
|
102
|
+
when Time
|
103
|
+
time = value
|
104
|
+
else
|
105
|
+
begin
|
106
|
+
time = Time.parse(value)
|
107
|
+
rescue => e
|
108
|
+
raise(ArgumentError, "Cannot parse argument value to time. #{e.message}")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
_bind_timestamp(i, time.year, time.month, time.day, time.hour, time.min, time.sec, time.usec)
|
113
|
+
end
|
114
|
+
|
115
|
+
# binds i-th parameter with SQL prepared statement.
|
116
|
+
# The first argument is index of parameter.
|
117
|
+
# The index of first parameter is 1 not 0.
|
118
|
+
# The second argument value is to expected ISO8601 time interval string.
|
119
|
+
#
|
120
|
+
# require 'duckdb'
|
121
|
+
# db = DuckDB::Database.open('duckdb_database')
|
122
|
+
# con = db.connect
|
123
|
+
# sql ='SELECT value FROM intervals WHERE interval = ?'
|
124
|
+
# stmt = PreparedStatement.new(con, sql)
|
125
|
+
# stmt.bind(1, 'P1Y2D')
|
126
|
+
def bind_interval(i, value)
|
127
|
+
raise(DuckDB::Error, 'bind_interval is not available with your duckdb version. please install duckdb latest version at first') unless respond_to?(:_bind_interval, true)
|
128
|
+
raise ArgumentError, "Argument `#{value}` must be a string." unless value.is_a?(String)
|
129
|
+
|
130
|
+
hash = iso8601_interval_to_hash(value)
|
131
|
+
|
132
|
+
months, days, micros = hash_to__append_interval_args(hash)
|
133
|
+
|
134
|
+
_bind_interval(i, months, days, micros)
|
135
|
+
end
|
136
|
+
|
137
|
+
# binds i-th parameter with SQL prepared statement.
|
138
|
+
# The first argument is index of parameter.
|
139
|
+
# The index of first parameter is 1 not 0.
|
32
140
|
# The second argument value is the value of prepared statement parameter.
|
33
141
|
#
|
34
142
|
# require 'duckdb'
|
@@ -40,7 +148,7 @@ module DuckDB
|
|
40
148
|
def bind(i, value)
|
41
149
|
case value
|
42
150
|
when NilClass
|
43
|
-
|
151
|
+
bind_null(i)
|
44
152
|
when Float
|
45
153
|
bind_double(i, value)
|
46
154
|
when Integer
|
@@ -51,11 +159,7 @@ module DuckDB
|
|
51
159
|
bind_varchar(i, value.to_s)
|
52
160
|
end
|
53
161
|
when String
|
54
|
-
|
55
|
-
blob?(value) ? bind_blob(i, value) : bind_varchar(i, value)
|
56
|
-
else
|
57
|
-
bind_varchar(i, value)
|
58
|
-
end
|
162
|
+
blob?(value) ? bind_blob(i, value) : bind_varchar(i, value)
|
59
163
|
when TrueClass, FalseClass
|
60
164
|
bind_bool(i, value)
|
61
165
|
when Time
|
data/lib/duckdb/version.rb
CHANGED
data/lib/duckdb.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duckdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masaki Suketa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,10 +108,13 @@ files:
|
|
108
108
|
- ext/duckdb/result.c
|
109
109
|
- ext/duckdb/result.h
|
110
110
|
- ext/duckdb/ruby-duckdb.h
|
111
|
+
- ext/duckdb/util.c
|
112
|
+
- ext/duckdb/util.h
|
111
113
|
- lib/duckdb.rb
|
112
114
|
- lib/duckdb/appender.rb
|
113
115
|
- lib/duckdb/config.rb
|
114
116
|
- lib/duckdb/connection.rb
|
117
|
+
- lib/duckdb/converter.rb
|
115
118
|
- lib/duckdb/database.rb
|
116
119
|
- lib/duckdb/prepared_statement.rb
|
117
120
|
- lib/duckdb/result.rb
|
@@ -138,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
141
|
- !ruby/object:Gem::Version
|
139
142
|
version: '0'
|
140
143
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
144
|
+
rubygems_version: 3.3.7
|
142
145
|
signing_key:
|
143
146
|
specification_version: 4
|
144
147
|
summary: This module is Ruby binding for DuckDB database engine.
|