duckdb 0.0.9 → 0.2.6.1
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 +28 -0
- data/.github/workflows/test_on_ubuntu.yml +66 -0
- data/.travis.yml +6 -5
- data/CHANGELOG.md +37 -0
- data/Gemfile.lock +5 -5
- data/README.md +90 -0
- data/ext/duckdb/appender.c +315 -0
- data/ext/duckdb/appender.h +17 -0
- data/ext/duckdb/blob.c +11 -0
- data/ext/duckdb/blob.h +14 -0
- data/ext/duckdb/connection.c +2 -0
- data/ext/duckdb/connection.h +0 -2
- data/ext/duckdb/database.c +2 -0
- data/ext/duckdb/database.h +0 -2
- data/ext/duckdb/duckdb.c +12 -0
- data/ext/duckdb/error.c +2 -0
- data/ext/duckdb/error.h +0 -2
- data/ext/duckdb/extconf.rb +3 -0
- data/ext/duckdb/prepared_statement.c +43 -11
- data/ext/duckdb/result.c +15 -0
- data/ext/duckdb/ruby-duckdb.h +22 -0
- data/lib/duckdb.rb +1 -0
- data/lib/duckdb/appender.rb +102 -0
- data/lib/duckdb/connection.rb +29 -0
- data/lib/duckdb/prepared_statement.rb +31 -3
- data/lib/duckdb/version.rb +1 -1
- metadata +13 -7
- data/.github/workflows/test_by_github.yml +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e40641b43de4613a5417e6f06fb50e23277394f4ba54aadc524afa319e15dbb
|
4
|
+
data.tar.gz: a5c578bb6fd9dee33ca0ab5af5d853e623fefec7fc9b74a43b4d6432cdec6fb5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2db7f176dc767856e43a2f8e4991c0bd6229f4174e2c1e91595436f36320f4f2b2eb1db52186644641b0ed45e38798a2bf76688e398abe27d4c3b81eda780939
|
7
|
+
data.tar.gz: 0343b460f0f62393ecd6e550ce468fa28c0098ce236a87968ad2bc8eb2f4764e87448c7df80f328e39b1f07da1acef6e5a931dfafe91af222dc201ef41812f36
|
@@ -0,0 +1,28 @@
|
|
1
|
+
name: MacOS
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: macos-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: ['2.5.8', '2.6.7', '2.7.3', '3.0.1', 'head']
|
11
|
+
|
12
|
+
steps:
|
13
|
+
- uses: actions/checkout@v2
|
14
|
+
|
15
|
+
- name: Set up Ruby
|
16
|
+
uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: ${{ matrix.ruby }}
|
19
|
+
|
20
|
+
- name: Install latest duckdb by brew
|
21
|
+
run: |
|
22
|
+
brew install duckdb
|
23
|
+
|
24
|
+
- name: Build and test with Rake with Ruby ${{ matrix.ruby }}
|
25
|
+
run: |
|
26
|
+
ruby -v
|
27
|
+
bundle install --jobs 4 --retry 3
|
28
|
+
bundle exec rake
|
@@ -0,0 +1,66 @@
|
|
1
|
+
name: Ubuntu
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
strategy:
|
10
|
+
matrix:
|
11
|
+
ruby: ['2.5.8', '2.6.7', '2.7.3', '3.0.1', 'head']
|
12
|
+
duckdb: ['0.2.6', '0.2.5']
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
|
17
|
+
- name: Set up Ruby
|
18
|
+
uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby }}
|
21
|
+
|
22
|
+
- name: duckdb 0.2.6 cache
|
23
|
+
id: duckdb-cache-v0_2_6
|
24
|
+
uses: actions/cache@v1.1.0
|
25
|
+
with:
|
26
|
+
path: duckdb-v0.2.6
|
27
|
+
key: ${{ runner.os }}-duckdb-v0_2_6_001
|
28
|
+
restore-keys: |
|
29
|
+
${{ runner.os }}-duckdb-v0_2_6
|
30
|
+
|
31
|
+
- name: duckdb 0.2.5 cache
|
32
|
+
id: duckdb-cache-v0_2_5
|
33
|
+
uses: actions/cache@v1.1.0
|
34
|
+
with:
|
35
|
+
path: duckdb-v0.2.5
|
36
|
+
key: ${{ runner.os }}-duckdb-v0_2_5_001
|
37
|
+
restore-keys: |
|
38
|
+
${{ runner.os }}-duckdb-v0_2_5
|
39
|
+
|
40
|
+
- name: Build duckdb 0.2.6
|
41
|
+
if: steps.duckdb-cache-v0_2_6.outputs.cache-hit != 'true'
|
42
|
+
run: |
|
43
|
+
git clone -b v0.2.6 https://github.com/cwida/duckdb.git duckdb-tmp-v0.2.6
|
44
|
+
cd duckdb-tmp-v0.2.6 && make && cd ..
|
45
|
+
rm -rf duckdb-v0.2.6
|
46
|
+
mkdir -p duckdb-v0.2.6/build/release/src duckdb-v0.2.6/src
|
47
|
+
cp -rip duckdb-tmp-v0.2.6/build/release/src/*.so duckdb-v0.2.6/build/release/src
|
48
|
+
cp -rip duckdb-tmp-v0.2.6/src/include duckdb-v0.2.6/src/
|
49
|
+
|
50
|
+
- name: Build duckdb 0.2.5
|
51
|
+
if: steps.duckdb-cache-v0_2_5.outputs.cache-hit != 'true'
|
52
|
+
run: |
|
53
|
+
git clone -b v0.2.5 https://github.com/cwida/duckdb.git duckdb-tmp-v0.2.5
|
54
|
+
cd duckdb-tmp-v0.2.5 && make && cd ..
|
55
|
+
rm -rf duckdb-v0.2.5
|
56
|
+
mkdir -p duckdb-v0.2.5/build/release/src duckdb-v0.2.5/src
|
57
|
+
cp -rip duckdb-tmp-v0.2.5/build/release/src/*.so duckdb-v0.2.5/build/release/src
|
58
|
+
cp -rip duckdb-tmp-v0.2.5/src/include duckdb-v0.2.5/src/
|
59
|
+
|
60
|
+
- name: Build and test with Rake with Ruby ${{ matrix.ruby }}
|
61
|
+
env:
|
62
|
+
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
63
|
+
run: |
|
64
|
+
gem install bundler
|
65
|
+
bundle install --jobs 4 --retry 3
|
66
|
+
bundle exec rake -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/
|
data/.travis.yml
CHANGED
@@ -2,16 +2,17 @@ language: ruby
|
|
2
2
|
cache:
|
3
3
|
bundler: true
|
4
4
|
directories:
|
5
|
-
- ${HOME}/duckdb-v0.2.
|
5
|
+
- ${HOME}/duckdb-v0.2.6
|
6
6
|
before_install:
|
7
7
|
- yes | gem update --system
|
8
|
-
- if [[ ! -d ${HOME}/duckdb-v0.2.
|
8
|
+
- if [[ ! -d ${HOME}/duckdb-v0.2.6/build ]]; then cd ${HOME} && git clone -b v0.2.6 https://github.com/cwida/duckdb.git duckdb-v0.2.6 && cd duckdb-v0.2.6 && make && cd ${TRAVIS_BUILD_DIR}; fi
|
9
9
|
|
10
10
|
env:
|
11
|
-
- DUCKDB_VERSION=0.2.
|
11
|
+
- DUCKDB_VERSION=0.2.6
|
12
12
|
rvm:
|
13
13
|
- 2.5.8
|
14
|
-
- 2.6.
|
15
|
-
- 2.7.
|
14
|
+
- 2.6.7
|
15
|
+
- 2.7.3
|
16
|
+
- 3.0.1
|
16
17
|
- ruby-head
|
17
18
|
script: bundle exec rake -- --with-duckdb-include=${HOME}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${HOME}/duckdb-v${DUCKDB_VERSION}/build/release/src/
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,42 @@
|
|
1
1
|
# ChangeLog
|
2
2
|
|
3
|
+
# 0.2.6.1
|
4
|
+
|
5
|
+
- add DuckDB::PreparedStatement#bind_int8
|
6
|
+
- DuckDB::Connection#appender accepts block.
|
7
|
+
- add DuckDB::Appender#append_row.
|
8
|
+
- support HUGEINT type.
|
9
|
+
- add DuckDB::Appender#append.
|
10
|
+
- rename PreparedStatement#bind_boolean to PreparedStatement#bind_bool.
|
11
|
+
- add DuckDB::Connection#appender.
|
12
|
+
|
13
|
+
# 0.2.6.0
|
14
|
+
|
15
|
+
- change version policy
|
16
|
+
- ruby-duckdb W.X.Y.Z supports duckdb W.X.Y
|
17
|
+
- add DuckDB::Appender
|
18
|
+
- bump DuckDB to v0.2.6 in CI.
|
19
|
+
- remove unnecessary duckdb header file from MacOS CI.
|
20
|
+
- add DuckDB::Connection#prepared_statement.
|
21
|
+
|
22
|
+
## 0.0.12
|
23
|
+
|
24
|
+
- bump DuckDB to v0.2.5
|
25
|
+
- support BLOB type (with DuckDB version 0.2.5 or later)
|
26
|
+
|
27
|
+
## 0.0.11
|
28
|
+
|
29
|
+
- fix failure in test_close in test/duckdb_test/database_test.rb because DuckDB error message was changed.
|
30
|
+
- bump DuckDb to v0.2.4
|
31
|
+
- add test CI with Ruby 3.0.0
|
32
|
+
- add test CI on MacOS.
|
33
|
+
- bunp DuckDB to v0.2.3
|
34
|
+
|
35
|
+
## 0.0.10
|
36
|
+
|
37
|
+
- bump DuckDB to v0.2.2
|
38
|
+
- fix to build failure on MacOS.
|
39
|
+
|
3
40
|
## 0.0.9
|
4
41
|
|
5
42
|
- bump DuckDB to v0.2.1
|
data/Gemfile.lock
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
duckdb (0.
|
4
|
+
duckdb (0.2.6.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
minitest (5.14.
|
10
|
-
rake (13.0.
|
9
|
+
minitest (5.14.4)
|
10
|
+
rake (13.0.3)
|
11
11
|
rake-compiler (1.1.1)
|
12
12
|
rake
|
13
13
|
|
14
14
|
PLATFORMS
|
15
|
-
|
15
|
+
x86_64-linux
|
16
16
|
|
17
17
|
DEPENDENCIES
|
18
18
|
bundler (~> 2.0)
|
@@ -22,4 +22,4 @@ DEPENDENCIES
|
|
22
22
|
rake-compiler
|
23
23
|
|
24
24
|
BUNDLED WITH
|
25
|
-
2.
|
25
|
+
2.2.17
|
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.com/suketa/ruby-duckdb)
|
4
4
|
[](https://github.com/suketa/ruby-duckdb/actions?query=workflow%3AUbuntu)
|
5
|
+
[](https://github.com/suketa/ruby-duckdb/actions?query=workflow%3AMacOS)
|
5
6
|
|
6
7
|
## Description
|
7
8
|
|
@@ -63,3 +64,92 @@ DuckDB::Database.open do |db|
|
|
63
64
|
end
|
64
65
|
end
|
65
66
|
```
|
67
|
+
|
68
|
+
### using BLOB column
|
69
|
+
|
70
|
+
BLOB is available with DuckDB v0.2.5 or later.
|
71
|
+
Use `DuckDB::Blob.new` or use sting#force_encoding(Encoding::BINARY)
|
72
|
+
|
73
|
+
```
|
74
|
+
require 'duckdb'
|
75
|
+
|
76
|
+
DuckDB::Database.open do |db|
|
77
|
+
db.connect do |con|
|
78
|
+
con.query('CREATE TABLE blob_table (binary_data BLOB)')
|
79
|
+
stmt = DuckDB::PreparedStatement.new(con, 'INSERT INTO blob_table VALUES ($1)')
|
80
|
+
|
81
|
+
stmt.bind(1, DuckDB::Blob.new("\0\1\2\3\4\5"))
|
82
|
+
# stmt.bind(1, "\0\1\2\3\4\5".force_encoding(Encoding::BINARY))
|
83
|
+
stmt.execute
|
84
|
+
|
85
|
+
result = con.query('SELECT binary_data FROM blob_table')
|
86
|
+
p result.first.first
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
### Appender
|
92
|
+
|
93
|
+
Appender class provides Ruby interface of [DuckDB Appender](https://duckdb.org/docs/data/appender)
|
94
|
+
|
95
|
+
```
|
96
|
+
require 'duckdb'
|
97
|
+
require 'benchmark'
|
98
|
+
|
99
|
+
def insert
|
100
|
+
DuckDB::Database.open do |db|
|
101
|
+
db.connect do |con|
|
102
|
+
con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
103
|
+
10000.times do
|
104
|
+
con.query("INSERT into users VALUES(1, 'Alice')")
|
105
|
+
end
|
106
|
+
# r = con.query('SELECT count(*) from users')
|
107
|
+
# p r.each.first
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def prepare
|
113
|
+
DuckDB::Database.open do |db|
|
114
|
+
db.connect do |con|
|
115
|
+
con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
116
|
+
stmt = con.prepared_statement('INSERT INTO users VALUES($1, $2)')
|
117
|
+
10000.times do
|
118
|
+
stmt.bind(1, 1)
|
119
|
+
stmt.bind(2, 'Alice')
|
120
|
+
stmt.execute
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def append
|
127
|
+
DuckDB::Database.open do |db|
|
128
|
+
db.connect do |con|
|
129
|
+
con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
130
|
+
appender = con.appender('users')
|
131
|
+
10000.times do
|
132
|
+
appender.begin_row
|
133
|
+
appender.append(1)
|
134
|
+
appender.append('Alice')
|
135
|
+
appender.end_row
|
136
|
+
end
|
137
|
+
appender.flush
|
138
|
+
# r = con.query('SELECT count(*) from users')
|
139
|
+
# p r.each.first
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
Benchmark.bm(8) do |x|
|
145
|
+
x.report('insert') { insert }
|
146
|
+
x.report('prepare') { prepare }
|
147
|
+
x.report('append') { append }
|
148
|
+
end
|
149
|
+
|
150
|
+
# =>
|
151
|
+
# user system total real
|
152
|
+
# insert 0.637439 0.000000 0.637439 ( 0.637486 )
|
153
|
+
# prepare 0.230457 0.000000 0.230457 ( 0.230460 )
|
154
|
+
# append 0.012666 0.000000 0.012666 ( 0.012670 )
|
155
|
+
```
|
@@ -0,0 +1,315 @@
|
|
1
|
+
#include "ruby-duckdb.h"
|
2
|
+
|
3
|
+
#ifdef HAVE_DUCKDB_APPENDER_CREATE
|
4
|
+
|
5
|
+
static VALUE cDuckDBAppender;
|
6
|
+
|
7
|
+
static void deallocate(void *);
|
8
|
+
static VALUE allocate(VALUE klass);
|
9
|
+
static VALUE appender_initialize(VALUE klass, VALUE con, VALUE schema, VALUE table);
|
10
|
+
static VALUE appender_begin_row(VALUE self);
|
11
|
+
static VALUE appender_end_row(VALUE self);
|
12
|
+
static VALUE appender_append_bool(VALUE self, VALUE val);
|
13
|
+
static VALUE appender_append_int8(VALUE self, VALUE val);
|
14
|
+
static VALUE appender_append_int16(VALUE self, VALUE val);
|
15
|
+
static VALUE appender_append_int32(VALUE self, VALUE val);
|
16
|
+
static VALUE appender_append_int64(VALUE self, VALUE val);
|
17
|
+
static VALUE appender_append_uint8(VALUE self, VALUE val);
|
18
|
+
static VALUE appender_append_uint16(VALUE self, VALUE val);
|
19
|
+
static VALUE appender_append_uint32(VALUE self, VALUE val);
|
20
|
+
static VALUE appender_append_uint64(VALUE self, VALUE val);
|
21
|
+
static VALUE appender_append_float(VALUE self, VALUE val);
|
22
|
+
static VALUE appender_append_double(VALUE self, VALUE val);
|
23
|
+
static VALUE appender_append_varchar(VALUE self, VALUE val);
|
24
|
+
static VALUE appender_append_varchar_length(VALUE self, VALUE val, VALUE len);
|
25
|
+
static VALUE appender_append_blob(VALUE self, VALUE val);
|
26
|
+
static VALUE appender_append_null(VALUE self);
|
27
|
+
static VALUE appender_flush(VALUE self);
|
28
|
+
static VALUE appender_close(VALUE self);
|
29
|
+
|
30
|
+
static void deallocate(void * ctx)
|
31
|
+
{
|
32
|
+
rubyDuckDBAppender *p = (rubyDuckDBAppender *)ctx;
|
33
|
+
|
34
|
+
duckdb_appender_destroy(&(p->appender));
|
35
|
+
xfree(p);
|
36
|
+
}
|
37
|
+
|
38
|
+
static VALUE allocate(VALUE klass)
|
39
|
+
{
|
40
|
+
rubyDuckDBAppender *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBAppender));
|
41
|
+
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
42
|
+
}
|
43
|
+
|
44
|
+
static VALUE appender_initialize(VALUE self, VALUE con, VALUE schema, VALUE table) {
|
45
|
+
|
46
|
+
rubyDuckDBConnection *ctxcon;
|
47
|
+
rubyDuckDBAppender *ctx;
|
48
|
+
char *pschema = 0;
|
49
|
+
|
50
|
+
if (!rb_obj_is_kind_of(con, cDuckDBConnection)) {
|
51
|
+
rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection");
|
52
|
+
}
|
53
|
+
|
54
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
55
|
+
Data_Get_Struct(con, rubyDuckDBConnection, ctxcon);
|
56
|
+
|
57
|
+
if (schema != Qnil) {
|
58
|
+
pschema = StringValuePtr(schema);
|
59
|
+
}
|
60
|
+
|
61
|
+
if (duckdb_appender_create(ctxcon->con, pschema, StringValuePtr(table), &(ctx->appender)) == DuckDBError) {
|
62
|
+
rb_raise(eDuckDBError, "failed to create appender");
|
63
|
+
}
|
64
|
+
return self;
|
65
|
+
}
|
66
|
+
|
67
|
+
static VALUE appender_begin_row(VALUE self) {
|
68
|
+
rubyDuckDBAppender *ctx;
|
69
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
70
|
+
|
71
|
+
if (duckdb_appender_begin_row(ctx->appender) == DuckDBError) {
|
72
|
+
rb_raise(eDuckDBError, "failed to flush");
|
73
|
+
}
|
74
|
+
return self;
|
75
|
+
}
|
76
|
+
|
77
|
+
static VALUE appender_end_row(VALUE self) {
|
78
|
+
rubyDuckDBAppender *ctx;
|
79
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
80
|
+
|
81
|
+
if (duckdb_appender_end_row(ctx->appender) == DuckDBError) {
|
82
|
+
rb_raise(eDuckDBError, "failed to flush");
|
83
|
+
}
|
84
|
+
return self;
|
85
|
+
}
|
86
|
+
|
87
|
+
static VALUE appender_append_bool(VALUE self, VALUE val) {
|
88
|
+
rubyDuckDBAppender *ctx;
|
89
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
90
|
+
|
91
|
+
if (val != Qtrue && val != Qfalse) {
|
92
|
+
rb_raise(rb_eArgError, "argument must be boolean");
|
93
|
+
}
|
94
|
+
|
95
|
+
if (duckdb_append_bool(ctx->appender, (val == Qtrue)) == DuckDBError) {
|
96
|
+
rb_raise(eDuckDBError, "failed to append boolean");
|
97
|
+
}
|
98
|
+
return self;
|
99
|
+
}
|
100
|
+
|
101
|
+
static VALUE appender_append_int8(VALUE self, VALUE val) {
|
102
|
+
rubyDuckDBAppender *ctx;
|
103
|
+
int8_t i8val = (int8_t)NUM2INT(val);
|
104
|
+
|
105
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
106
|
+
|
107
|
+
if (duckdb_append_int8(ctx->appender, i8val) == DuckDBError) {
|
108
|
+
rb_raise(eDuckDBError, "failed to append");
|
109
|
+
}
|
110
|
+
return self;
|
111
|
+
}
|
112
|
+
|
113
|
+
static VALUE appender_append_int16(VALUE self, VALUE val) {
|
114
|
+
rubyDuckDBAppender *ctx;
|
115
|
+
int16_t i16val = (int16_t)NUM2INT(val);
|
116
|
+
|
117
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
118
|
+
|
119
|
+
if (duckdb_append_int16(ctx->appender, i16val) == DuckDBError) {
|
120
|
+
rb_raise(eDuckDBError, "failed to append");
|
121
|
+
}
|
122
|
+
return self;
|
123
|
+
}
|
124
|
+
|
125
|
+
static VALUE appender_append_int32(VALUE self, VALUE val) {
|
126
|
+
rubyDuckDBAppender *ctx;
|
127
|
+
int32_t i32val = (int32_t)NUM2INT(val);
|
128
|
+
|
129
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
130
|
+
|
131
|
+
if (duckdb_append_int32(ctx->appender, i32val) == DuckDBError) {
|
132
|
+
rb_raise(eDuckDBError, "failed to append");
|
133
|
+
}
|
134
|
+
return self;
|
135
|
+
}
|
136
|
+
|
137
|
+
static VALUE appender_append_int64(VALUE self, VALUE val) {
|
138
|
+
rubyDuckDBAppender *ctx;
|
139
|
+
int64_t i64val = (int64_t)NUM2LL(val);
|
140
|
+
|
141
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
142
|
+
|
143
|
+
if (duckdb_append_int64(ctx->appender, i64val) == DuckDBError) {
|
144
|
+
rb_raise(eDuckDBError, "failed to append");
|
145
|
+
}
|
146
|
+
return self;
|
147
|
+
}
|
148
|
+
|
149
|
+
static VALUE appender_append_uint8(VALUE self, VALUE val) {
|
150
|
+
rubyDuckDBAppender *ctx;
|
151
|
+
int8_t ui8val = (uint8_t)NUM2UINT(val);
|
152
|
+
|
153
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
154
|
+
|
155
|
+
if (duckdb_append_uint8(ctx->appender, ui8val) == DuckDBError) {
|
156
|
+
rb_raise(eDuckDBError, "failed to append");
|
157
|
+
}
|
158
|
+
return self;
|
159
|
+
}
|
160
|
+
|
161
|
+
static VALUE appender_append_uint16(VALUE self, VALUE val) {
|
162
|
+
rubyDuckDBAppender *ctx;
|
163
|
+
uint16_t ui16val = (uint16_t)NUM2UINT(val);
|
164
|
+
|
165
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
166
|
+
|
167
|
+
if (duckdb_append_uint16(ctx->appender, ui16val) == DuckDBError) {
|
168
|
+
rb_raise(eDuckDBError, "failed to append");
|
169
|
+
}
|
170
|
+
return self;
|
171
|
+
}
|
172
|
+
|
173
|
+
static VALUE appender_append_uint32(VALUE self, VALUE val) {
|
174
|
+
rubyDuckDBAppender *ctx;
|
175
|
+
uint32_t ui32val = (uint32_t)NUM2UINT(val);
|
176
|
+
|
177
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
178
|
+
|
179
|
+
if (duckdb_append_uint32(ctx->appender, ui32val) == DuckDBError) {
|
180
|
+
rb_raise(eDuckDBError, "failed to append");
|
181
|
+
}
|
182
|
+
return self;
|
183
|
+
}
|
184
|
+
|
185
|
+
static VALUE appender_append_uint64(VALUE self, VALUE val) {
|
186
|
+
rubyDuckDBAppender *ctx;
|
187
|
+
uint64_t ui64val = (uint64_t)NUM2ULL(val);
|
188
|
+
|
189
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
190
|
+
|
191
|
+
if (duckdb_append_uint64(ctx->appender, ui64val) == DuckDBError) {
|
192
|
+
rb_raise(eDuckDBError, "failed to append");
|
193
|
+
}
|
194
|
+
return self;
|
195
|
+
}
|
196
|
+
|
197
|
+
static VALUE appender_append_float(VALUE self, VALUE val) {
|
198
|
+
rubyDuckDBAppender *ctx;
|
199
|
+
float fval = (float)NUM2DBL(val);
|
200
|
+
|
201
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
202
|
+
|
203
|
+
if (duckdb_append_float(ctx->appender, fval) == DuckDBError) {
|
204
|
+
rb_raise(eDuckDBError, "failed to append");
|
205
|
+
}
|
206
|
+
return self;
|
207
|
+
}
|
208
|
+
|
209
|
+
static VALUE appender_append_double(VALUE self, VALUE val) {
|
210
|
+
rubyDuckDBAppender *ctx;
|
211
|
+
double dval = NUM2DBL(val);
|
212
|
+
|
213
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
214
|
+
|
215
|
+
if (duckdb_append_double(ctx->appender, dval) == DuckDBError) {
|
216
|
+
rb_raise(eDuckDBError, "failed to append");
|
217
|
+
}
|
218
|
+
return self;
|
219
|
+
}
|
220
|
+
|
221
|
+
static VALUE appender_append_varchar(VALUE self, VALUE val) {
|
222
|
+
rubyDuckDBAppender *ctx;
|
223
|
+
char *pval = StringValuePtr(val);
|
224
|
+
|
225
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
226
|
+
|
227
|
+
if (duckdb_append_varchar(ctx->appender, pval) == DuckDBError) {
|
228
|
+
rb_raise(eDuckDBError, "failed to append");
|
229
|
+
}
|
230
|
+
return self;
|
231
|
+
}
|
232
|
+
|
233
|
+
static VALUE appender_append_varchar_length(VALUE self, VALUE val, VALUE len) {
|
234
|
+
rubyDuckDBAppender *ctx;
|
235
|
+
|
236
|
+
char *pval = StringValuePtr(val);
|
237
|
+
idx_t length = (idx_t)NUM2ULL(len);
|
238
|
+
|
239
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
240
|
+
|
241
|
+
if (duckdb_append_varchar_length(ctx->appender, pval, length) == DuckDBError) {
|
242
|
+
rb_raise(eDuckDBError, "failed to append");
|
243
|
+
}
|
244
|
+
return self;
|
245
|
+
}
|
246
|
+
|
247
|
+
static VALUE appender_append_blob(VALUE self, VALUE val) {
|
248
|
+
rubyDuckDBAppender *ctx;
|
249
|
+
|
250
|
+
char *pval = StringValuePtr(val);
|
251
|
+
idx_t length = (idx_t)RSTRING_LEN(val);
|
252
|
+
|
253
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
254
|
+
|
255
|
+
if (duckdb_append_blob(ctx->appender, (void *)pval, length) == DuckDBError) {
|
256
|
+
rb_raise(eDuckDBError, "failed to append");
|
257
|
+
}
|
258
|
+
return self;
|
259
|
+
}
|
260
|
+
|
261
|
+
static VALUE appender_append_null(VALUE self) {
|
262
|
+
rubyDuckDBAppender *ctx;
|
263
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
264
|
+
|
265
|
+
if (duckdb_append_null(ctx->appender) == DuckDBError) {
|
266
|
+
rb_raise(eDuckDBError, "failed to append");
|
267
|
+
}
|
268
|
+
return self;
|
269
|
+
}
|
270
|
+
|
271
|
+
static VALUE appender_flush(VALUE self) {
|
272
|
+
rubyDuckDBAppender *ctx;
|
273
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
274
|
+
|
275
|
+
if (duckdb_appender_flush(ctx->appender) == DuckDBError) {
|
276
|
+
rb_raise(eDuckDBError, "failed to flush");
|
277
|
+
}
|
278
|
+
return self;
|
279
|
+
}
|
280
|
+
|
281
|
+
static VALUE appender_close(VALUE self) {
|
282
|
+
rubyDuckDBAppender *ctx;
|
283
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
284
|
+
|
285
|
+
if (duckdb_appender_close(ctx->appender) == DuckDBError) {
|
286
|
+
rb_raise(eDuckDBError, "failed to flush");
|
287
|
+
}
|
288
|
+
return self;
|
289
|
+
}
|
290
|
+
|
291
|
+
void init_duckdb_appender(void) {
|
292
|
+
cDuckDBAppender = rb_define_class_under(mDuckDB, "Appender", rb_cObject);
|
293
|
+
rb_define_alloc_func(cDuckDBAppender, allocate);
|
294
|
+
rb_define_method(cDuckDBAppender, "initialize", appender_initialize, 3);
|
295
|
+
rb_define_method(cDuckDBAppender, "begin_row", appender_begin_row, 0);
|
296
|
+
rb_define_method(cDuckDBAppender, "end_row", appender_end_row, 0);
|
297
|
+
rb_define_method(cDuckDBAppender, "append_bool", appender_append_bool, 1);
|
298
|
+
rb_define_method(cDuckDBAppender, "append_int8", appender_append_int8, 1);
|
299
|
+
rb_define_method(cDuckDBAppender, "append_int16", appender_append_int16, 1);
|
300
|
+
rb_define_method(cDuckDBAppender, "append_int32", appender_append_int32, 1);
|
301
|
+
rb_define_method(cDuckDBAppender, "append_int64", appender_append_int64, 1);
|
302
|
+
rb_define_method(cDuckDBAppender, "append_uint8", appender_append_uint8, 1);
|
303
|
+
rb_define_method(cDuckDBAppender, "append_uint16", appender_append_uint16, 1);
|
304
|
+
rb_define_method(cDuckDBAppender, "append_uint32", appender_append_uint32, 1);
|
305
|
+
rb_define_method(cDuckDBAppender, "append_uint64", appender_append_uint64, 1);
|
306
|
+
rb_define_method(cDuckDBAppender, "append_float", appender_append_float, 1);
|
307
|
+
rb_define_method(cDuckDBAppender, "append_double", appender_append_double, 1);
|
308
|
+
rb_define_method(cDuckDBAppender, "append_varchar", appender_append_varchar, 1);
|
309
|
+
rb_define_method(cDuckDBAppender, "append_varchar_length", appender_append_varchar_length, 2);
|
310
|
+
rb_define_method(cDuckDBAppender, "append_blob", appender_append_blob, 1);
|
311
|
+
rb_define_method(cDuckDBAppender, "append_null", appender_append_null, 0);
|
312
|
+
rb_define_method(cDuckDBAppender, "flush", appender_flush, 0);
|
313
|
+
rb_define_method(cDuckDBAppender, "close", appender_close, 0);
|
314
|
+
}
|
315
|
+
#endif /* HAVE_DUCKDB_APPENDER_CREATE */
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef RUBY_DUCKDB_APPENDER_H
|
2
|
+
#define RUBY_DUCKDB_APPENDER_H
|
3
|
+
|
4
|
+
#ifdef HAVE_DUCKDB_APPENDER_CREATE
|
5
|
+
|
6
|
+
struct _rubyDuckDBAppender {
|
7
|
+
duckdb_appender appender;
|
8
|
+
};
|
9
|
+
|
10
|
+
typedef struct _rubyDuckDBAppender rubyDuckDBAppender;
|
11
|
+
|
12
|
+
void init_duckdb_appender(void);
|
13
|
+
|
14
|
+
#endif
|
15
|
+
|
16
|
+
#endif
|
17
|
+
|
data/ext/duckdb/blob.c
ADDED
data/ext/duckdb/blob.h
ADDED
data/ext/duckdb/connection.c
CHANGED
data/ext/duckdb/connection.h
CHANGED
data/ext/duckdb/database.c
CHANGED
data/ext/duckdb/database.h
CHANGED
data/ext/duckdb/duckdb.c
CHANGED
@@ -12,4 +12,16 @@ Init_duckdb_native(void)
|
|
12
12
|
init_duckdb_connection();
|
13
13
|
init_duckdb_result();
|
14
14
|
init_duckdb_prepared_statement();
|
15
|
+
|
16
|
+
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
17
|
+
|
18
|
+
init_duckdb_blob();
|
19
|
+
|
20
|
+
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
21
|
+
|
22
|
+
#ifdef HAVE_DUCKDB_APPENDER_CREATE
|
23
|
+
|
24
|
+
init_duckdb_appender();
|
25
|
+
|
26
|
+
#endif /* HAVE_DUCKDB_APPENDER_CREATE */
|
15
27
|
}
|
data/ext/duckdb/error.c
CHANGED
data/ext/duckdb/error.h
CHANGED
data/ext/duckdb/extconf.rb
CHANGED
@@ -70,7 +70,7 @@ static idx_t check_index(VALUE vidx)
|
|
70
70
|
return idx;
|
71
71
|
}
|
72
72
|
|
73
|
-
static VALUE
|
73
|
+
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val)
|
74
74
|
{
|
75
75
|
rubyDuckDBPreparedStatement *ctx;
|
76
76
|
idx_t idx = check_index(vidx);
|
@@ -81,7 +81,21 @@ static VALUE duckdb_prepared_statement_bind_boolean(VALUE self, VALUE vidx, VALU
|
|
81
81
|
}
|
82
82
|
|
83
83
|
if (duckdb_bind_boolean(ctx->prepared_statement, idx, (val == Qtrue)) == DuckDBError) {
|
84
|
-
rb_raise(eDuckDBError, "fail to bind %
|
84
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
85
|
+
}
|
86
|
+
return self;
|
87
|
+
}
|
88
|
+
|
89
|
+
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val)
|
90
|
+
{
|
91
|
+
rubyDuckDBPreparedStatement *ctx;
|
92
|
+
idx_t idx = check_index(vidx);
|
93
|
+
int8_t i8val = (int8_t)NUM2INT(val);
|
94
|
+
|
95
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
96
|
+
|
97
|
+
if (duckdb_bind_int8(ctx->prepared_statement, idx, i8val) == DuckDBError) {
|
98
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
85
99
|
}
|
86
100
|
return self;
|
87
101
|
}
|
@@ -95,7 +109,7 @@ static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE
|
|
95
109
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
96
110
|
|
97
111
|
if (duckdb_bind_int16(ctx->prepared_statement, idx, i16val) == DuckDBError) {
|
98
|
-
rb_raise(eDuckDBError, "fail to bind %
|
112
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
99
113
|
}
|
100
114
|
return self;
|
101
115
|
}
|
@@ -104,12 +118,12 @@ static VALUE duckdb_prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE
|
|
104
118
|
{
|
105
119
|
rubyDuckDBPreparedStatement *ctx;
|
106
120
|
idx_t idx = check_index(vidx);
|
107
|
-
int32_t i32val =
|
121
|
+
int32_t i32val = NUM2INT(val);
|
108
122
|
|
109
123
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
110
124
|
|
111
125
|
if (duckdb_bind_int32(ctx->prepared_statement, idx, i32val) == DuckDBError) {
|
112
|
-
rb_raise(eDuckDBError, "fail to bind %
|
126
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
113
127
|
}
|
114
128
|
return self;
|
115
129
|
}
|
@@ -123,7 +137,7 @@ static VALUE duckdb_prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE
|
|
123
137
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
124
138
|
|
125
139
|
if (duckdb_bind_int64(ctx->prepared_statement, idx, i64val) == DuckDBError) {
|
126
|
-
rb_raise(eDuckDBError, "fail to bind %
|
140
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
127
141
|
}
|
128
142
|
return self;
|
129
143
|
}
|
@@ -137,7 +151,7 @@ static VALUE duckdb_prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE
|
|
137
151
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
138
152
|
|
139
153
|
if (duckdb_bind_float(ctx->prepared_statement, idx, (float)dbl) == DuckDBError) {
|
140
|
-
rb_raise(eDuckDBError, "fail to bind %
|
154
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
141
155
|
}
|
142
156
|
return self;
|
143
157
|
}
|
@@ -151,7 +165,7 @@ static VALUE duckdb_prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE
|
|
151
165
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
152
166
|
|
153
167
|
if (duckdb_bind_double(ctx->prepared_statement, idx, dbl) == DuckDBError) {
|
154
|
-
rb_raise(eDuckDBError, "fail to bind %
|
168
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
155
169
|
}
|
156
170
|
return self;
|
157
171
|
}
|
@@ -163,10 +177,24 @@ static VALUE duckdb_prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALU
|
|
163
177
|
|
164
178
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
165
179
|
if (duckdb_bind_varchar(ctx->prepared_statement, idx, StringValuePtr(str)) == DuckDBError) {
|
166
|
-
rb_raise(eDuckDBError, "fail to bind %
|
180
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
181
|
+
}
|
182
|
+
return self;
|
183
|
+
}
|
184
|
+
|
185
|
+
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
186
|
+
static VALUE duckdb_prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob)
|
187
|
+
{
|
188
|
+
rubyDuckDBPreparedStatement *ctx;
|
189
|
+
idx_t idx = check_index(vidx);
|
190
|
+
|
191
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
192
|
+
if (duckdb_bind_blob(ctx->prepared_statement, idx, (const void *)StringValuePtr(blob), (idx_t)RSTRING_LEN(blob)) == DuckDBError) {
|
193
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
167
194
|
}
|
168
195
|
return self;
|
169
196
|
}
|
197
|
+
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
170
198
|
|
171
199
|
static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
|
172
200
|
{
|
@@ -175,7 +203,7 @@ static VALUE duckdb_prepared_statement_bind_null(VALUE self, VALUE vidx)
|
|
175
203
|
|
176
204
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
177
205
|
if (duckdb_bind_null(ctx->prepared_statement, idx) == DuckDBError) {
|
178
|
-
rb_raise(eDuckDBError, "fail to bind %
|
206
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
179
207
|
}
|
180
208
|
return self;
|
181
209
|
}
|
@@ -189,12 +217,16 @@ void init_duckdb_prepared_statement(void)
|
|
189
217
|
rb_define_method(cDuckDBPreparedStatement, "initialize", duckdb_prepared_statement_initialize, 2);
|
190
218
|
rb_define_method(cDuckDBPreparedStatement, "execute", duckdb_prepared_statement_execute, 0);
|
191
219
|
rb_define_method(cDuckDBPreparedStatement, "nparams", duckdb_prepared_statement_nparams, 0);
|
192
|
-
rb_define_method(cDuckDBPreparedStatement, "
|
220
|
+
rb_define_method(cDuckDBPreparedStatement, "bind_bool", duckdb_prepared_statement_bind_bool, 2);
|
221
|
+
rb_define_method(cDuckDBPreparedStatement, "bind_int8", duckdb_prepared_statement_bind_int8, 2);
|
193
222
|
rb_define_method(cDuckDBPreparedStatement, "bind_int16", duckdb_prepared_statement_bind_int16, 2);
|
194
223
|
rb_define_method(cDuckDBPreparedStatement, "bind_int32", duckdb_prepared_statement_bind_int32, 2);
|
195
224
|
rb_define_method(cDuckDBPreparedStatement, "bind_int64", duckdb_prepared_statement_bind_int64, 2);
|
196
225
|
rb_define_method(cDuckDBPreparedStatement, "bind_float", duckdb_prepared_statement_bind_float, 2);
|
197
226
|
rb_define_method(cDuckDBPreparedStatement, "bind_double", duckdb_prepared_statement_bind_double, 2);
|
198
227
|
rb_define_method(cDuckDBPreparedStatement, "bind_varchar", duckdb_prepared_statement_bind_varchar, 2);
|
228
|
+
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
229
|
+
rb_define_method(cDuckDBPreparedStatement, "bind_blob", duckdb_prepared_statement_bind_blob, 2);
|
230
|
+
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
199
231
|
rb_define_method(cDuckDBPreparedStatement, "bind_null", duckdb_prepared_statement_bind_null, 1);
|
200
232
|
}
|
data/ext/duckdb/result.c
CHANGED
@@ -52,6 +52,14 @@ static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_
|
|
52
52
|
return DBL2NUM(dval);
|
53
53
|
}
|
54
54
|
|
55
|
+
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
56
|
+
static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
57
|
+
{
|
58
|
+
duckdb_blob bval = duckdb_value_blob(result, col_idx, row_idx);
|
59
|
+
return rb_str_new(bval.data, bval.size);
|
60
|
+
}
|
61
|
+
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
62
|
+
|
55
63
|
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
56
64
|
{
|
57
65
|
char *p;
|
@@ -72,10 +80,17 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
|
72
80
|
return to_ruby_obj_float(result, col_idx, row_idx);
|
73
81
|
case DUCKDB_TYPE_DOUBLE:
|
74
82
|
return to_ruby_obj_double(result, col_idx, row_idx);
|
83
|
+
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
84
|
+
case DUCKDB_TYPE_BLOB:
|
85
|
+
return to_ruby_obj_string_from_blob(result, col_idx, row_idx);
|
86
|
+
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
75
87
|
default:
|
76
88
|
p = duckdb_value_varchar(result, col_idx, row_idx);
|
77
89
|
obj = rb_str_new2(p);
|
78
90
|
free(p);
|
91
|
+
if (result->columns[col_idx].type == DUCKDB_TYPE_HUGEINT) {
|
92
|
+
obj = rb_funcall(obj, rb_intern("to_i"), 0);
|
93
|
+
}
|
79
94
|
}
|
80
95
|
return obj;
|
81
96
|
}
|
data/ext/duckdb/ruby-duckdb.h
CHANGED
@@ -9,6 +9,28 @@
|
|
9
9
|
#include "./result.h"
|
10
10
|
#include "./prepared_statement.h"
|
11
11
|
|
12
|
+
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
13
|
+
|
14
|
+
#include "./blob.h"
|
15
|
+
|
16
|
+
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
17
|
+
|
18
|
+
#ifdef HAVE_DUCKDB_APPENDER_CREATE
|
19
|
+
|
20
|
+
#include "./appender.h"
|
21
|
+
|
22
|
+
#endif /* HAVE_DUCKDB_APPENDER_CREATE */
|
23
|
+
|
12
24
|
extern VALUE mDuckDB;
|
25
|
+
extern VALUE cDuckDBDatabase;
|
26
|
+
extern VALUE cDuckDBConnection;
|
27
|
+
|
28
|
+
#ifdef HAVE_DUCKDB_VALUE_BLOB
|
29
|
+
|
30
|
+
extern VALUE cDuckDBBlob;
|
31
|
+
|
32
|
+
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
33
|
+
|
34
|
+
extern VALUE eDuckDBError;
|
13
35
|
|
14
36
|
#endif
|
data/lib/duckdb.rb
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module DuckDB
|
4
|
+
if defined?(DuckDB::Appender)
|
5
|
+
# The DuckDB::Appender encapsulates DuckDB Appender.
|
6
|
+
#
|
7
|
+
# require 'duckdb'
|
8
|
+
# db = DuckDB::Database.open
|
9
|
+
# con = db.connect
|
10
|
+
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
11
|
+
# appender = con.appender('users')
|
12
|
+
# appender.append_row(1, 'Alice')
|
13
|
+
#
|
14
|
+
class Appender
|
15
|
+
RANGE_INT16 = (-32_768..32_767).freeze
|
16
|
+
RANGE_INT32 = (-2_147_483_648..2_147_483_647).freeze
|
17
|
+
RANGE_INT64 = (-9_223_372_036_854_775_808..9_223_372_036_854_775_807).freeze
|
18
|
+
|
19
|
+
def append_hugeint(value)
|
20
|
+
case value
|
21
|
+
when Integer
|
22
|
+
append_varchar(value.to_s)
|
23
|
+
else
|
24
|
+
rb_raise(ArgumentError, "2nd argument `#{value}` must be Integer.")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# appends value.
|
30
|
+
#
|
31
|
+
# require 'duckdb'
|
32
|
+
# db = DuckDB::Database.open
|
33
|
+
# con = db.connect
|
34
|
+
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
35
|
+
# appender = con.appender('users')
|
36
|
+
# appender.begin_row
|
37
|
+
# appender.append(1)
|
38
|
+
# appender.append('Alice')
|
39
|
+
# appender.end_row
|
40
|
+
#
|
41
|
+
def append(value)
|
42
|
+
case value
|
43
|
+
when NilClass
|
44
|
+
append_null
|
45
|
+
when Float
|
46
|
+
append_double(value)
|
47
|
+
when Integer
|
48
|
+
case value
|
49
|
+
when RANGE_INT16
|
50
|
+
append_int16(value)
|
51
|
+
when RANGE_INT32
|
52
|
+
append_int32(value)
|
53
|
+
when RANGE_INT64
|
54
|
+
append_int64(value)
|
55
|
+
else
|
56
|
+
append_hugeint(value)
|
57
|
+
end
|
58
|
+
when String
|
59
|
+
if defined?(DuckDB::Blob)
|
60
|
+
blob?(value) ? append_blob(value) : append_varchar(value)
|
61
|
+
else
|
62
|
+
append_varchar(value)
|
63
|
+
end
|
64
|
+
when TrueClass, FalseClass
|
65
|
+
append_bool(value)
|
66
|
+
when Time
|
67
|
+
append_varchar(value.strftime('%Y-%m-%d %H:%M:%S.%N'))
|
68
|
+
when Date
|
69
|
+
append_varchar(value.strftime('%Y-%m-%d'))
|
70
|
+
else
|
71
|
+
rb_raise(DuckDB::Error, "not supported type #{value} (value.class)")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# append a row.
|
77
|
+
#
|
78
|
+
# appender.append_row(1, 'Alice')
|
79
|
+
#
|
80
|
+
# is same as:
|
81
|
+
#
|
82
|
+
# appender.begin_row
|
83
|
+
# appender.append(1)
|
84
|
+
# appender.append('Alice')
|
85
|
+
# appender.end_row
|
86
|
+
#
|
87
|
+
def append_row(*args)
|
88
|
+
begin_row
|
89
|
+
args.each do |arg|
|
90
|
+
append(arg)
|
91
|
+
end
|
92
|
+
end_row
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def blob?(value)
|
98
|
+
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/duckdb/connection.rb
CHANGED
@@ -44,6 +44,35 @@ module DuckDB
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
#
|
48
|
+
# returns PreparedStatement object.
|
49
|
+
# The first argument is SQL string.
|
50
|
+
#
|
51
|
+
def prepared_statement(str)
|
52
|
+
PreparedStatement.new(self, str)
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# returns Appender object.
|
57
|
+
# The first argument is table name
|
58
|
+
#
|
59
|
+
def appender(table)
|
60
|
+
appender = create_appender(table)
|
61
|
+
|
62
|
+
return appender unless block_given?
|
63
|
+
|
64
|
+
yield appender
|
65
|
+
appender.flush
|
66
|
+
appender.close
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def create_appender(table)
|
72
|
+
t1, t2 = table.split('.')
|
73
|
+
t2 ? Appender.new(self, t1, t2) : Appender.new(self, t2, t1)
|
74
|
+
end
|
75
|
+
|
47
76
|
alias execute query
|
48
77
|
alias open connect
|
49
78
|
alias close disconnect
|
@@ -13,6 +13,19 @@ module DuckDB
|
|
13
13
|
# stmt.execute
|
14
14
|
class PreparedStatement
|
15
15
|
|
16
|
+
RANGE_INT16 = -32768..32767
|
17
|
+
RANGE_INT32 = -2147483648..2147483647
|
18
|
+
RANGE_INT64 = -9223372036854775808..9223372036854775807
|
19
|
+
|
20
|
+
def bind_hugeint(i, value)
|
21
|
+
case value
|
22
|
+
when Integer
|
23
|
+
bind_varchar(i, value.to_s)
|
24
|
+
else
|
25
|
+
rb_raise(ArgumentError, "2nd argument `#{value}` must be Integer.")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
16
29
|
# binds i-th parameter with SQL prepared statement.
|
17
30
|
# The first argument is index of parameter. The index of first parameter is
|
18
31
|
# 1 not 0.
|
@@ -31,11 +44,20 @@ module DuckDB
|
|
31
44
|
when Float
|
32
45
|
bind_double(i, value)
|
33
46
|
when Integer
|
34
|
-
|
47
|
+
case value
|
48
|
+
when RANGE_INT64
|
49
|
+
bind_int64(i, value)
|
50
|
+
else
|
51
|
+
bind_varchar(i, value.to_s)
|
52
|
+
end
|
35
53
|
when String
|
36
|
-
|
54
|
+
if defined?(DuckDB::Blob)
|
55
|
+
blob?(value) ? bind_blob(i, value) : bind_varchar(i, value)
|
56
|
+
else
|
57
|
+
bind_varchar(i, value)
|
58
|
+
end
|
37
59
|
when TrueClass, FalseClass
|
38
|
-
|
60
|
+
bind_bool(i, value)
|
39
61
|
when Time
|
40
62
|
bind_varchar(i, value.strftime('%Y-%m-%d %H:%M:%S.%N'))
|
41
63
|
when Date
|
@@ -44,5 +66,11 @@ module DuckDB
|
|
44
66
|
rb_raise(DuckDB::Error, "not supported type #{value} (value.class)")
|
45
67
|
end
|
46
68
|
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def blob?(value)
|
73
|
+
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
74
|
+
end
|
47
75
|
end
|
48
76
|
end
|
data/lib/duckdb/version.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.
|
4
|
+
version: 0.2.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masaki Suketa
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,7 +75,8 @@ extensions:
|
|
75
75
|
- ext/duckdb/extconf.rb
|
76
76
|
extra_rdoc_files: []
|
77
77
|
files:
|
78
|
-
- ".github/workflows/
|
78
|
+
- ".github/workflows/test_on_macos.yml"
|
79
|
+
- ".github/workflows/test_on_ubuntu.yml"
|
79
80
|
- ".gitignore"
|
80
81
|
- ".travis.yml"
|
81
82
|
- CHANGELOG.md
|
@@ -87,6 +88,10 @@ files:
|
|
87
88
|
- bin/console
|
88
89
|
- bin/setup
|
89
90
|
- duckdb.gemspec
|
91
|
+
- ext/duckdb/appender.c
|
92
|
+
- ext/duckdb/appender.h
|
93
|
+
- ext/duckdb/blob.c
|
94
|
+
- ext/duckdb/blob.h
|
90
95
|
- ext/duckdb/connection.c
|
91
96
|
- ext/duckdb/connection.h
|
92
97
|
- ext/duckdb/database.c
|
@@ -101,6 +106,7 @@ files:
|
|
101
106
|
- ext/duckdb/result.h
|
102
107
|
- ext/duckdb/ruby-duckdb.h
|
103
108
|
- lib/duckdb.rb
|
109
|
+
- lib/duckdb/appender.rb
|
104
110
|
- lib/duckdb/connection.rb
|
105
111
|
- lib/duckdb/database.rb
|
106
112
|
- lib/duckdb/prepared_statement.rb
|
@@ -113,7 +119,7 @@ metadata:
|
|
113
119
|
homepage_uri: https://github.com/suketa/ruby-duckdb
|
114
120
|
source_code_uri: https://github.com/suketa/ruby-duckdb
|
115
121
|
changelog_uri: https://github.com/suketa/ruby-duckdb/blob/master/CHANGELOG.md
|
116
|
-
post_install_message:
|
122
|
+
post_install_message:
|
117
123
|
rdoc_options: []
|
118
124
|
require_paths:
|
119
125
|
- lib
|
@@ -128,8 +134,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
134
|
- !ruby/object:Gem::Version
|
129
135
|
version: '0'
|
130
136
|
requirements: []
|
131
|
-
rubygems_version: 3.
|
132
|
-
signing_key:
|
137
|
+
rubygems_version: 3.2.15
|
138
|
+
signing_key:
|
133
139
|
specification_version: 4
|
134
140
|
summary: This module is Ruby binding for DuckDB database engine.
|
135
141
|
test_files: []
|
@@ -1,66 +0,0 @@
|
|
1
|
-
name: Ubuntu
|
2
|
-
|
3
|
-
on: [push]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
build:
|
7
|
-
|
8
|
-
runs-on: ubuntu-latest
|
9
|
-
strategy:
|
10
|
-
matrix:
|
11
|
-
ruby: ['2.5.8', '2.6.6', '2.7.2', 'head']
|
12
|
-
duckdb: ['0.2.0', '0.2.1']
|
13
|
-
|
14
|
-
steps:
|
15
|
-
- uses: actions/checkout@v2
|
16
|
-
|
17
|
-
- name: Set up Ruby
|
18
|
-
uses: ruby/setup-ruby@v1
|
19
|
-
with:
|
20
|
-
ruby-version: ${{ matrix.ruby }}
|
21
|
-
|
22
|
-
- name: duckdb 0.2.0 cache
|
23
|
-
id: duckdb-cache-v0_2_0
|
24
|
-
uses: actions/cache@v1.1.0
|
25
|
-
with:
|
26
|
-
path: duckdb-v0.2.0
|
27
|
-
key: ${{ runner.os }}-duckdb-v0_2_0_001
|
28
|
-
restore-keys: |
|
29
|
-
${{ runner.os }}-duckdb-v0_2_0
|
30
|
-
|
31
|
-
- name: duckdb 0.2.1 cache
|
32
|
-
id: duckdb-cache-v0_2_1
|
33
|
-
uses: actions/cache@v1.1.0
|
34
|
-
with:
|
35
|
-
path: duckdb-v0.2.1
|
36
|
-
key: ${{ runner.os }}-duckdb-v0_2_1_001
|
37
|
-
restore-keys: |
|
38
|
-
${{ runner.os }}-duckdb-v0_2_1
|
39
|
-
|
40
|
-
- name: Build duckdb 0.2.0
|
41
|
-
if: steps.duckdb-cache-v0_2_0.outputs.cache-hit != 'true'
|
42
|
-
run: |
|
43
|
-
git clone -b v0.2.0 https://github.com/cwida/duckdb.git duckdb-tmp-v0.2.0
|
44
|
-
cd duckdb-tmp-v0.2.0 && make && cd ..
|
45
|
-
rm -rf duckdb-v0.2.0
|
46
|
-
mkdir -p duckdb-v0.2.0/build/release/src duckdb-v0.2.0/src
|
47
|
-
cp -rip duckdb-tmp-v0.2.0/build/release/src/*.so duckdb-v0.2.0/build/release/src
|
48
|
-
cp -rip duckdb-tmp-v0.2.0/src/include duckdb-v0.2.0/src/
|
49
|
-
|
50
|
-
- name: Build duckdb 0.2.1
|
51
|
-
if: steps.duckdb-cache-v0_2_1.outputs.cache-hit != 'true'
|
52
|
-
run: |
|
53
|
-
git clone -b v0.2.1 https://github.com/cwida/duckdb.git duckdb-tmp-v0.2.1
|
54
|
-
cd duckdb-tmp-v0.2.1 && make && cd ..
|
55
|
-
rm -rf duckdb-v0.2.1
|
56
|
-
mkdir -p duckdb-v0.2.1/build/release/src duckdb-v0.2.1/src
|
57
|
-
cp -rip duckdb-tmp-v0.2.1/build/release/src/*.so duckdb-v0.2.1/build/release/src
|
58
|
-
cp -rip duckdb-tmp-v0.2.1/src/include duckdb-v0.2.1/src/
|
59
|
-
|
60
|
-
- name: Build and test with Rake with Ruby ${{ matrix.ruby }}
|
61
|
-
env:
|
62
|
-
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
63
|
-
run: |
|
64
|
-
gem install bundler
|
65
|
-
bundle install --jobs 4 --retry 3
|
66
|
-
bundle exec rake -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/
|