duckdb 0.3.1.0 → 0.3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|