duckdb 0.2.8.0 → 0.2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test_on_macos.yml +27 -3
- data/.github/workflows/test_on_ubuntu.yml +17 -36
- data/.github/workflows/test_on_windows.yml +11 -5
- data/CHANGELOG.md +20 -0
- data/CONTRIBUTION.md +24 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -3
- data/duckdb.gemspec +2 -2
- data/ext/duckdb/appender.c +136 -0
- data/ext/duckdb/config.c +1 -1
- data/ext/duckdb/extconf.rb +12 -0
- data/ext/duckdb/prepared_statement.c +9 -1
- data/ext/duckdb/result.c +44 -30
- data/lib/duckdb/appender.rb +206 -5
- data/lib/duckdb/prepared_statement.rb +3 -3
- data/lib/duckdb/version.rb +1 -1
- metadata +4 -4
- data/.travis.yml +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af998f52f46c0ef8f51501333cbaf39d720daaa389eb618d7d7ad79627d70ad9
|
4
|
+
data.tar.gz: 8e1c5323fa2f917c9ab6050a0350e5e25b646559492501f636af026b79cb20f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14809adeffb7bc79f2102e29f89a6fe6ea276ab38eaeabed9f3c18a023566c3bbad06c1ab31e55499e77d3f0f9ced186d618c24639b8c16ceff1ee61304f9f67
|
7
|
+
data.tar.gz: 15d164af6af9d985765d7b9fa87dcf7f9cf89fb2d691c9d44ea2d2bb72341a77213647cb08bcacc66094eb1622d250fe203f41a9529866af9f358518800f7183
|
@@ -7,7 +7,8 @@ jobs:
|
|
7
7
|
runs-on: macos-latest
|
8
8
|
strategy:
|
9
9
|
matrix:
|
10
|
-
ruby: ['2.
|
10
|
+
ruby: ['2.6.8', '2.7.4', '3.0.2', 'head']
|
11
|
+
duckdb: ['0.2.8', '0.2.9']
|
11
12
|
|
12
13
|
steps:
|
13
14
|
- uses: actions/checkout@v2
|
@@ -17,9 +18,32 @@ jobs:
|
|
17
18
|
with:
|
18
19
|
ruby-version: ${{ matrix.ruby }}
|
19
20
|
|
20
|
-
- name:
|
21
|
+
- name: duckdb cache
|
22
|
+
id: duckdb-cache
|
23
|
+
uses: actions/cache@v2
|
24
|
+
with:
|
25
|
+
path: /usr/local/Cellar/duckdb@${{ matrix.duckdb }}
|
26
|
+
key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }}
|
27
|
+
|
28
|
+
- name: Install duckdb v${{ matrix.duckdb }} by brew
|
29
|
+
env:
|
30
|
+
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
31
|
+
if: steps.duckdb-cache.outputs.cache-hit != 'true'
|
32
|
+
run: |
|
33
|
+
brew tap-new duckdb/taps
|
34
|
+
brew extract duckdb duckdb/taps --version $DUCKDB_VERSION
|
35
|
+
brew install duckdb/taps/duckdb@$DUCKDB_VERSION
|
36
|
+
|
37
|
+
- name: setup duckdb v${{ matrix.duckdb }} headers and libraries
|
38
|
+
env:
|
39
|
+
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
21
40
|
run: |
|
22
|
-
|
41
|
+
if [ ! -L /usr/local/include/duckdb.h ]; then
|
42
|
+
header=`find /usr/local/Cellar/duckdb@$DUCKDB_VERSION -name "duckdb.h"`
|
43
|
+
lib=`find /usr/local/Cellar/duckdb@$DUCKDB_VERSION -name "libduckdb.dylib"`
|
44
|
+
ln -s $header /usr/local/include/duckdb.h
|
45
|
+
ln -s $lib /usr/local/lib/libduckdb.dylib
|
46
|
+
fi
|
23
47
|
|
24
48
|
- name: Build and test with Rake with Ruby ${{ matrix.ruby }}
|
25
49
|
run: |
|
@@ -8,8 +8,8 @@ jobs:
|
|
8
8
|
runs-on: ubuntu-latest
|
9
9
|
strategy:
|
10
10
|
matrix:
|
11
|
-
ruby: ['2.
|
12
|
-
duckdb: ['0.2.8', '0.2.
|
11
|
+
ruby: ['2.6.8', '2.7.4', '3.0.2', 'head']
|
12
|
+
duckdb: ['0.2.8', '0.2.9']
|
13
13
|
|
14
14
|
steps:
|
15
15
|
- uses: actions/checkout@v2
|
@@ -19,43 +19,24 @@ jobs:
|
|
19
19
|
with:
|
20
20
|
ruby-version: ${{ matrix.ruby }}
|
21
21
|
|
22
|
-
- name: duckdb
|
23
|
-
id: duckdb-cache
|
24
|
-
uses: actions/cache@
|
22
|
+
- name: duckdb cache
|
23
|
+
id: duckdb-cache
|
24
|
+
uses: actions/cache@v2
|
25
25
|
with:
|
26
|
-
path: duckdb-
|
27
|
-
key: ${{ runner.os }}-duckdb-
|
28
|
-
restore-keys: |
|
29
|
-
${{ runner.os }}-duckdb-v0_2_8
|
26
|
+
path: duckdb-v${{ matrix.duckdb }}
|
27
|
+
key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }}
|
30
28
|
|
31
|
-
- name: duckdb
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
path: duckdb-v0.2.7
|
36
|
-
key: ${{ runner.os }}-duckdb-v0_2_7_001
|
37
|
-
restore-keys: |
|
38
|
-
${{ runner.os }}-duckdb-v0_2_7
|
39
|
-
|
40
|
-
- name: Build duckdb 0.2.8
|
41
|
-
if: steps.duckdb-cache-v0_2_8.outputs.cache-hit != 'true'
|
42
|
-
run: |
|
43
|
-
git clone -b v0.2.8 https://github.com/cwida/duckdb.git duckdb-tmp-v0.2.8
|
44
|
-
cd duckdb-tmp-v0.2.8 && make && cd ..
|
45
|
-
rm -rf duckdb-v0.2.8
|
46
|
-
mkdir -p duckdb-v0.2.8/build/release/src duckdb-v0.2.8/src
|
47
|
-
cp -rip duckdb-tmp-v0.2.8/build/release/src/*.so duckdb-v0.2.8/build/release/src
|
48
|
-
cp -rip duckdb-tmp-v0.2.8/src/include duckdb-v0.2.8/src/
|
49
|
-
|
50
|
-
- name: Build duckdb 0.2.7
|
51
|
-
if: steps.duckdb-cache-v0_2_7.outputs.cache-hit != 'true'
|
29
|
+
- name: Build duckdb ${{ matrix.duckdb }}
|
30
|
+
env:
|
31
|
+
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
32
|
+
if: steps.duckdb-cache.outputs.cache-hit != 'true'
|
52
33
|
run: |
|
53
|
-
git clone -b
|
54
|
-
cd duckdb-tmp-
|
55
|
-
rm -rf duckdb-
|
56
|
-
mkdir -p duckdb-
|
57
|
-
cp -rip duckdb-tmp-
|
58
|
-
cp -rip duckdb-tmp-
|
34
|
+
git clone -b v$DUCKDB_VERSION https://github.com/cwida/duckdb.git duckdb-tmp-v$DUCKDB_VERSION
|
35
|
+
cd duckdb-tmp-v$DUCKDB_VERSION && make && cd ..
|
36
|
+
rm -rf duckdb-v$DUCKDB_VERSION
|
37
|
+
mkdir -p duckdb-v$DUCKDB_VERSION/build/release/src duckdb-v$DUCKDB_VERSION/src
|
38
|
+
cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.so duckdb-v$DUCKDB_VERSION/build/release/src
|
39
|
+
cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/
|
59
40
|
|
60
41
|
- name: Build and test with Rake with Ruby ${{ matrix.ruby }}
|
61
42
|
env:
|
@@ -7,7 +7,8 @@ jobs:
|
|
7
7
|
runs-on: windows-latest
|
8
8
|
strategy:
|
9
9
|
matrix:
|
10
|
-
ruby: ['2.
|
10
|
+
ruby: ['2.6.8', '2.7.4', '3.0.2', 'head']
|
11
|
+
duckdb: ['0.2.8', '0.2.9']
|
11
12
|
|
12
13
|
steps:
|
13
14
|
- uses: actions/checkout@v2
|
@@ -18,8 +19,10 @@ jobs:
|
|
18
19
|
ruby-version: ${{ matrix.ruby }}
|
19
20
|
|
20
21
|
- name: download duckdb binary for windows 64bit
|
22
|
+
env:
|
23
|
+
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
21
24
|
run: |
|
22
|
-
curl -OL https://github.com/duckdb/duckdb/releases/download/
|
25
|
+
curl -OL https://github.com/duckdb/duckdb/releases/download/v${env:DUCKDB_VERSION}/libduckdb-windows-amd64.zip
|
23
26
|
|
24
27
|
- name: extract zip file
|
25
28
|
run: |
|
@@ -29,9 +32,12 @@ jobs:
|
|
29
32
|
run: |
|
30
33
|
bundle install
|
31
34
|
bundle exec rake build -- --with-duckdb-include=../../../.. --with-duckdb-lib=../../../..
|
35
|
+
- name: setup duckdb.dll
|
36
|
+
run: |
|
37
|
+
cp duckdb.dll C:/Windows/System32/
|
32
38
|
|
33
39
|
# FIXME: rake test fails with LoadError
|
34
40
|
# C:/hostedtoolcache/windows/Ruby/2.7.3/x64/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:83:in `require': 126: The specified module could not be found. - D:/a/ruby-duckdb/ruby-duckdb/lib/duckdb/duckdb_native.so (LoadError)`
|
35
|
-
|
36
|
-
|
37
|
-
|
41
|
+
- name: rake test
|
42
|
+
run: |
|
43
|
+
rake test
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# ChangeLog
|
2
2
|
|
3
|
+
# 0.2.9.0
|
4
|
+
|
5
|
+
- add DuckDB::Appender#append
|
6
|
+
- breaking change.
|
7
|
+
- append_timestamp is called when the argument is Time object.
|
8
|
+
- append_date is called when the argument is Date object.
|
9
|
+
- add DuckDB::Appender#append_timestamp.
|
10
|
+
- add DuckDB::Appender#append_interval. append_interval is expremental.
|
11
|
+
- add DuckDB::Result#rows_changed
|
12
|
+
- refactoring DuckDB::Append#append_hugeint with duckdb v0.2.9
|
13
|
+
- test 2 versions of duckdb on github actions macos CI.
|
14
|
+
- fix windows CI failes
|
15
|
+
- update github actions CI on ubuntu
|
16
|
+
- fix to build with duckdb v0.2.9
|
17
|
+
- use duckdb_prepare_error when get error message of prepared statement.
|
18
|
+
- add DuckDB::Appender#append_date
|
19
|
+
- add DuckDB::Appender#append_time
|
20
|
+
|
21
|
+
# 0.2.8.0
|
22
|
+
|
3
23
|
- DuckDB::Database.open accepts 2-nd argument as DuckDB::Config object.
|
4
24
|
- add DuckDB::Config
|
5
25
|
- bump duckdb to 0.2.8 in CI
|
data/CONTRIBUTION.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Contribution Guide
|
2
|
+
|
3
|
+
## Issue
|
4
|
+
|
5
|
+
If you spot a problem, [search if an issue already exists](https://github.com/suketa/ruby-duckdb/issues).
|
6
|
+
If a related issue doesn't exist, you can open a [new issue](https://github.com/suketa/ruby-duckdb/issues/new).
|
7
|
+
|
8
|
+
|
9
|
+
## Fix Issues or Add New Features.
|
10
|
+
|
11
|
+
1. install [Ruby](https://www.ruby-lang.org/) into your local machine.
|
12
|
+
2. install [duckdb](https://duckdb.org/) into your local machine.
|
13
|
+
3. fork the repository and `git clone` to your local machine.
|
14
|
+
4. run `bundle install`
|
15
|
+
5. run `rake build`
|
16
|
+
or you might run with C duckdb header and library directories:
|
17
|
+
`rake build -- --with-duckdb-include=/duckdb_header_directory --with-duckdb-lib=/duckdb_library_directory`
|
18
|
+
6. run `rake test`
|
19
|
+
7. create new branch to change the code.
|
20
|
+
8. change the code.
|
21
|
+
9. write test.
|
22
|
+
10. run `rake test` and confirm all tests pass.
|
23
|
+
11. git push.
|
24
|
+
12. create PR.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# ruby-duckdb
|
2
2
|
|
3
|
-
[](https://travis-ci.com/suketa/ruby-duckdb)
|
4
3
|
[](https://github.com/suketa/ruby-duckdb/actions?query=workflow%3AUbuntu)
|
5
4
|
[](https://github.com/suketa/ruby-duckdb/actions?query=workflow%3AMacOS)
|
5
|
+
[](https://github.com/suketa/ruby-duckdb/actions?query=workflow%3AWindows)
|
6
6
|
|
7
7
|
## Description
|
8
8
|
|
@@ -18,10 +18,10 @@ You must have [DuckDB](http://www.duckdb.org) engine installed in order to build
|
|
18
18
|
gem install duckdb
|
19
19
|
```
|
20
20
|
|
21
|
-
or you must specify the location of the
|
21
|
+
or you must specify the location of the C header and library files:
|
22
22
|
|
23
23
|
```
|
24
|
-
gem install duckdb -- --with-duckdb-include=/
|
24
|
+
gem install duckdb -- --with-duckdb-include=/duckdb_header_directory --with-duckdb-lib=/duckdb_library_directory
|
25
25
|
```
|
26
26
|
|
27
27
|
## Usage
|
data/duckdb.gemspec
CHANGED
@@ -21,12 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
# Specify which files should be added to the gem when it is released.
|
23
23
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
-
spec.files = Dir.chdir(File.expand_path(
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
25
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
26
|
end
|
27
27
|
spec.require_paths = ['lib']
|
28
28
|
spec.extensions = ['ext/duckdb/extconf.rb']
|
29
|
-
spec.required_ruby_version = '>= 2.
|
29
|
+
spec.required_ruby_version = '>= 2.6.0'
|
30
30
|
|
31
31
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
32
32
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
data/ext/duckdb/appender.c
CHANGED
@@ -24,6 +24,27 @@ static VALUE appender_append_varchar(VALUE self, VALUE val);
|
|
24
24
|
static VALUE appender_append_varchar_length(VALUE self, VALUE val, VALUE len);
|
25
25
|
static VALUE appender_append_blob(VALUE self, VALUE val);
|
26
26
|
static VALUE appender_append_null(VALUE self);
|
27
|
+
|
28
|
+
#ifdef HAVE_DUCKDB_APPEND_DATE
|
29
|
+
static VALUE appender__append_date(VALUE self, VALUE yearval, VALUE monthval, VALUE dayval);
|
30
|
+
#endif
|
31
|
+
|
32
|
+
#ifdef HAVE_DUCKDB_APPEND_INTERVAL
|
33
|
+
static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VALUE micros);
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#ifdef HAVE_DUCKDB_APPEND_TIME
|
37
|
+
static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
38
|
+
#endif
|
39
|
+
|
40
|
+
#ifdef HAVE_DUCKDB_APPEND_TIMESTAMP
|
41
|
+
static VALUE appender__append_timestamp(VALUE self, VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
42
|
+
#endif
|
43
|
+
|
44
|
+
#ifdef HAVE_DUCKDB_APPEND_HUGEINT
|
45
|
+
static VALUE appender__append_hugeint(VALUE self, VALUE lower, VALUE upper);
|
46
|
+
#endif
|
47
|
+
|
27
48
|
static VALUE appender_flush(VALUE self);
|
28
49
|
static VALUE appender_close(VALUE self);
|
29
50
|
|
@@ -268,6 +289,106 @@ static VALUE appender_append_null(VALUE self) {
|
|
268
289
|
return self;
|
269
290
|
}
|
270
291
|
|
292
|
+
#ifdef HAVE_DUCKDB_APPEND_DATE
|
293
|
+
static VALUE appender__append_date(VALUE self, VALUE yearval, VALUE monthval, VALUE dayval) {
|
294
|
+
duckdb_date_struct dt_struct;
|
295
|
+
duckdb_date dt;
|
296
|
+
rubyDuckDBAppender *ctx;
|
297
|
+
|
298
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
299
|
+
dt_struct.year = NUM2INT(yearval);
|
300
|
+
dt_struct.month = NUM2INT(monthval);
|
301
|
+
dt_struct.day = NUM2INT(dayval);
|
302
|
+
dt = duckdb_to_date(dt_struct);
|
303
|
+
|
304
|
+
if (duckdb_append_date(ctx->appender, dt) == DuckDBError) {
|
305
|
+
rb_raise(eDuckDBError, "failed to append date");
|
306
|
+
}
|
307
|
+
return self;
|
308
|
+
}
|
309
|
+
#endif
|
310
|
+
|
311
|
+
#ifdef HAVE_DUCKDB_APPEND_INTERVAL
|
312
|
+
static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VALUE micros) {
|
313
|
+
duckdb_interval interval;
|
314
|
+
rubyDuckDBAppender *ctx;
|
315
|
+
|
316
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
317
|
+
interval.months = NUM2INT(months);
|
318
|
+
interval.days = NUM2INT(days);
|
319
|
+
interval.micros = NUM2LL(micros);
|
320
|
+
|
321
|
+
if (duckdb_append_interval(ctx->appender, interval) == DuckDBError) {
|
322
|
+
rb_raise(eDuckDBError, "failed to append interval");
|
323
|
+
}
|
324
|
+
return self;
|
325
|
+
}
|
326
|
+
#endif
|
327
|
+
|
328
|
+
#ifdef HAVE_DUCKDB_APPEND_TIME
|
329
|
+
static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
330
|
+
duckdb_time_struct time_st;
|
331
|
+
duckdb_time time;
|
332
|
+
rubyDuckDBAppender *ctx;
|
333
|
+
|
334
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
335
|
+
time_st.hour = NUM2INT(hour);
|
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);
|
341
|
+
|
342
|
+
if (duckdb_append_time(ctx->appender, time) == DuckDBError) {
|
343
|
+
rb_raise(eDuckDBError, "failed to append time");
|
344
|
+
}
|
345
|
+
return self;
|
346
|
+
}
|
347
|
+
#endif
|
348
|
+
|
349
|
+
#ifdef HAVE_DUCKDB_APPEND_TIMESTAMP
|
350
|
+
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
|
+
duckdb_timestamp timestamp;
|
353
|
+
|
354
|
+
rubyDuckDBAppender *ctx;
|
355
|
+
|
356
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
357
|
+
|
358
|
+
timestamp_st.date.year = NUM2INT(year);
|
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);
|
367
|
+
|
368
|
+
if (duckdb_append_timestamp(ctx->appender, timestamp) == DuckDBError) {
|
369
|
+
rb_raise(eDuckDBError, "failed to append timestamp");
|
370
|
+
}
|
371
|
+
return self;
|
372
|
+
}
|
373
|
+
#endif
|
374
|
+
|
375
|
+
#ifdef HAVE_DUCKDB_APPEND_HUGEINT
|
376
|
+
static VALUE appender__append_hugeint(VALUE self, VALUE lower, VALUE upper) {
|
377
|
+
duckdb_hugeint hugeint;
|
378
|
+
|
379
|
+
hugeint.lower = NUM2ULL(lower);
|
380
|
+
hugeint.upper = NUM2LL(upper);
|
381
|
+
|
382
|
+
rubyDuckDBAppender *ctx;
|
383
|
+
|
384
|
+
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
385
|
+
if (duckdb_append_hugeint(ctx->appender, hugeint) == DuckDBError) {
|
386
|
+
rb_raise(eDuckDBError, "failed to append hugeint");
|
387
|
+
}
|
388
|
+
return self;
|
389
|
+
}
|
390
|
+
#endif
|
391
|
+
|
271
392
|
static VALUE appender_flush(VALUE self) {
|
272
393
|
rubyDuckDBAppender *ctx;
|
273
394
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
@@ -309,6 +430,21 @@ void init_duckdb_appender(void) {
|
|
309
430
|
rb_define_method(cDuckDBAppender, "append_varchar_length", appender_append_varchar_length, 2);
|
310
431
|
rb_define_method(cDuckDBAppender, "append_blob", appender_append_blob, 1);
|
311
432
|
rb_define_method(cDuckDBAppender, "append_null", appender_append_null, 0);
|
433
|
+
#ifdef HAVE_DUCKDB_APPEND_DATE
|
434
|
+
rb_define_private_method(cDuckDBAppender, "_append_date", appender__append_date, 3);
|
435
|
+
#endif
|
436
|
+
#ifdef HAVE_DUCKDB_APPEND_INTERVAL
|
437
|
+
rb_define_private_method(cDuckDBAppender, "_append_interval", appender__append_interval, 3);
|
438
|
+
#endif
|
439
|
+
#ifdef HAVE_DUCKDB_APPEND_TIME
|
440
|
+
rb_define_private_method(cDuckDBAppender, "_append_time", appender__append_time, 4);
|
441
|
+
#endif
|
442
|
+
#ifdef HAVE_DUCKDB_APPEND_TIMESTAMP
|
443
|
+
rb_define_private_method(cDuckDBAppender, "_append_timestamp", appender__append_timestamp, 7);
|
444
|
+
#endif
|
445
|
+
#ifdef HAVE_DUCKDB_APPEND_HUGEINT
|
446
|
+
rb_define_private_method(cDuckDBAppender, "_append_hugeint", appender__append_hugeint, 2);
|
447
|
+
#endif
|
312
448
|
rb_define_method(cDuckDBAppender, "flush", appender_flush, 0);
|
313
449
|
rb_define_method(cDuckDBAppender, "close", appender_close, 0);
|
314
450
|
}
|
data/ext/duckdb/config.c
CHANGED
data/ext/duckdb/extconf.rb
CHANGED
@@ -2,11 +2,23 @@ require 'mkmf'
|
|
2
2
|
|
3
3
|
dir_config('duckdb')
|
4
4
|
if have_library('duckdb')
|
5
|
+
if have_func('duckdb_nparams(NULL)', 'duckdb.h')
|
6
|
+
$defs << '-DHAVE_DUCKDB_NPARAMS_029'
|
7
|
+
elsif have_func('duckdb_nparams(NULL, NULL)', 'duckdb.h')
|
8
|
+
$defs << '-DHAVE_DUCKDB_NPARAMS_028'
|
9
|
+
end
|
10
|
+
|
5
11
|
have_func('duckdb_value_blob', 'duckdb.h')
|
6
12
|
have_func('duckdb_bind_blob', 'duckdb.h')
|
7
13
|
have_func('duckdb_appender_create', 'duckdb.h')
|
8
14
|
have_func('duckdb_free', 'duckdb.h')
|
9
15
|
have_func('duckdb_create_config', 'duckdb.h')
|
10
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')
|
11
23
|
create_makefile('duckdb/duckdb_native')
|
12
24
|
end
|
@@ -29,8 +29,13 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q
|
|
29
29
|
Data_Get_Struct(con, rubyDuckDBConnection, ctxcon);
|
30
30
|
|
31
31
|
if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) {
|
32
|
+
#ifdef HAVE_DUCKDB_PREPARE_ERROR
|
33
|
+
const char *error = duckdb_prepare_error(ctx->prepared_statement);
|
34
|
+
rb_raise(eDuckDBError, "%s", error);
|
35
|
+
#else
|
32
36
|
/* TODO: include query parameter information in error message. */
|
33
37
|
rb_raise(eDuckDBError, "failed to prepare statement");
|
38
|
+
#endif
|
34
39
|
}
|
35
40
|
return self;
|
36
41
|
}
|
@@ -39,11 +44,14 @@ static VALUE duckdb_prepared_statement_nparams(VALUE self)
|
|
39
44
|
{
|
40
45
|
rubyDuckDBPreparedStatement *ctx;
|
41
46
|
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
42
|
-
|
47
|
+
#ifdef HAVE_DUCKDB_NPARAMS_029
|
48
|
+
return rb_int2big(duckdb_nparams(ctx->prepared_statement));
|
49
|
+
#else
|
43
50
|
if (duckdb_nparams(ctx->prepared_statement, &(ctx->nparams)) == DuckDBError) {
|
44
51
|
rb_raise(eDuckDBError, "failed to get number of parameters");
|
45
52
|
}
|
46
53
|
return rb_int2big(ctx->nparams);
|
54
|
+
#endif
|
47
55
|
}
|
48
56
|
|
49
57
|
|
data/ext/duckdb/result.c
CHANGED
@@ -2,59 +2,50 @@
|
|
2
2
|
|
3
3
|
static VALUE cDuckDBResult;
|
4
4
|
|
5
|
-
static void deallocate(void *ctx)
|
6
|
-
{
|
5
|
+
static void deallocate(void *ctx) {
|
7
6
|
rubyDuckDBResult *p = (rubyDuckDBResult *)ctx;
|
8
7
|
|
9
8
|
duckdb_destroy_result(&(p->result));
|
10
9
|
xfree(p);
|
11
10
|
}
|
12
11
|
|
13
|
-
static VALUE allocate(VALUE klass)
|
14
|
-
{
|
12
|
+
static VALUE allocate(VALUE klass) {
|
15
13
|
rubyDuckDBResult *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBResult));
|
16
14
|
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
|
17
15
|
}
|
18
16
|
|
19
|
-
static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
20
|
-
{
|
17
|
+
static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
21
18
|
bool bval = duckdb_value_boolean(result, col_idx, row_idx);
|
22
19
|
return bval ? Qtrue : Qnil;
|
23
20
|
}
|
24
21
|
|
25
|
-
static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
26
|
-
{
|
22
|
+
static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
27
23
|
int16_t i16val = duckdb_value_int16(result, col_idx, row_idx);
|
28
24
|
return INT2FIX(i16val);
|
29
25
|
}
|
30
26
|
|
31
|
-
static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
32
|
-
{
|
27
|
+
static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
33
28
|
int32_t i32val = duckdb_value_int32(result, col_idx, row_idx);
|
34
29
|
return INT2NUM(i32val);
|
35
30
|
}
|
36
31
|
|
37
|
-
static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
38
|
-
{
|
32
|
+
static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
39
33
|
int64_t i64val = duckdb_value_int64(result, col_idx, row_idx);
|
40
34
|
return rb_int2big(i64val);
|
41
35
|
}
|
42
36
|
|
43
|
-
static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
44
|
-
{
|
37
|
+
static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
45
38
|
float fval = duckdb_value_float(result, col_idx, row_idx);
|
46
39
|
return DBL2NUM(fval);
|
47
40
|
}
|
48
41
|
|
49
|
-
static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
50
|
-
{
|
42
|
+
static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
51
43
|
double dval = duckdb_value_double(result, col_idx, row_idx);
|
52
44
|
return DBL2NUM(dval);
|
53
45
|
}
|
54
46
|
|
55
47
|
#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
|
-
{
|
48
|
+
static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
58
49
|
VALUE str;
|
59
50
|
duckdb_blob bval = duckdb_value_blob(result, col_idx, row_idx);
|
60
51
|
str = rb_str_new(bval.data, bval.size);
|
@@ -71,8 +62,7 @@ static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx,
|
|
71
62
|
}
|
72
63
|
#endif /* HAVE_DUCKDB_VALUE_BLOB */
|
73
64
|
|
74
|
-
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
75
|
-
{
|
65
|
+
static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) {
|
76
66
|
char *p;
|
77
67
|
VALUE obj = Qnil;
|
78
68
|
if (result->columns[col_idx].nullmask[row_idx]) {
|
@@ -112,8 +102,7 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
|
112
102
|
return obj;
|
113
103
|
}
|
114
104
|
|
115
|
-
static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx)
|
116
|
-
{
|
105
|
+
static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx) {
|
117
106
|
idx_t col_idx;
|
118
107
|
VALUE ary = rb_ary_new2(ctx->result.column_count);
|
119
108
|
for(col_idx = 0; col_idx < ctx->result.column_count; col_idx++) {
|
@@ -122,16 +111,14 @@ static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx)
|
|
122
111
|
return ary;
|
123
112
|
}
|
124
113
|
|
125
|
-
static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj)
|
126
|
-
{
|
114
|
+
static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj) {
|
127
115
|
rubyDuckDBResult *ctx;
|
128
116
|
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
129
117
|
|
130
118
|
return LONG2FIX(ctx->result.row_count);
|
131
119
|
}
|
132
120
|
|
133
|
-
static VALUE duckdb_result_each(VALUE oDuckDBResult)
|
134
|
-
{
|
121
|
+
static VALUE duckdb_result_each(VALUE oDuckDBResult) {
|
135
122
|
rubyDuckDBResult *ctx;
|
136
123
|
idx_t row_idx = 0;
|
137
124
|
|
@@ -144,15 +131,42 @@ static VALUE duckdb_result_each(VALUE oDuckDBResult)
|
|
144
131
|
return oDuckDBResult;
|
145
132
|
}
|
146
133
|
|
147
|
-
|
148
|
-
|
134
|
+
/*
|
135
|
+
* call-seq:
|
136
|
+
* result.rows_changed -> integer
|
137
|
+
*
|
138
|
+
* Returns the count of rows changed.
|
139
|
+
*
|
140
|
+
* DuckDB::Database.open do |db|
|
141
|
+
* db.connect do |con|
|
142
|
+
* r = con.query('CREATE TABLE t2 (id INT)')
|
143
|
+
* r.rows_changed # => 0
|
144
|
+
* r = con.query('INSERT INTO t2 VALUES (1), (2), (3)')
|
145
|
+
* r.rows_changed # => 3
|
146
|
+
* r = con.query('UPDATE t2 SET id = id + 1 WHERE id > 1')
|
147
|
+
* r.rows_changed # => 2
|
148
|
+
* r = con.query('DELETE FROM t2 WHERE id = 0')
|
149
|
+
* r.rows_changed # => 0
|
150
|
+
* r = con.query('DELETE FROM t2 WHERE id = 4')
|
151
|
+
* r.rows_changed # => 1
|
152
|
+
* end
|
153
|
+
* end
|
154
|
+
*
|
155
|
+
*/
|
156
|
+
static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult) {
|
157
|
+
rubyDuckDBResult *ctx;
|
158
|
+
Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx);
|
159
|
+
return LL2NUM(ctx->result.rows_changed);
|
160
|
+
}
|
161
|
+
|
162
|
+
VALUE create_result(void) {
|
149
163
|
return allocate(cDuckDBResult);
|
150
164
|
}
|
151
165
|
|
152
|
-
void init_duckdb_result(void)
|
153
|
-
{
|
166
|
+
void init_duckdb_result(void) {
|
154
167
|
cDuckDBResult = rb_define_class_under(mDuckDB, "Result", rb_cObject);
|
155
168
|
rb_define_alloc_func(cDuckDBResult, allocate);
|
156
169
|
|
157
170
|
rb_define_method(cDuckDBResult, "each", duckdb_result_each, 0);
|
171
|
+
rb_define_method(cDuckDBResult, "rows_changed", duckdb_result_rows_changed, 0);
|
158
172
|
}
|
data/lib/duckdb/appender.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'time'
|
2
3
|
|
3
4
|
module DuckDB
|
4
5
|
if defined?(DuckDB::Appender)
|
@@ -16,13 +17,158 @@ module DuckDB
|
|
16
17
|
RANGE_INT32 = -2_147_483_648..2_147_483_647
|
17
18
|
RANGE_INT64 = -9_223_372_036_854_775_808..9_223_372_036_854_775_807
|
18
19
|
|
20
|
+
#
|
21
|
+
# appends huge int value.
|
22
|
+
#
|
23
|
+
# require 'duckdb'
|
24
|
+
# db = DuckDB::Database.open
|
25
|
+
# con = db.connect
|
26
|
+
# con.query('CREATE TABLE numbers (num HUGEINT)')
|
27
|
+
# appender = con.appender('numbers')
|
28
|
+
# appender
|
29
|
+
# .begin_row
|
30
|
+
# .append_hugeint(-170_141_183_460_469_231_731_687_303_715_884_105_727)
|
31
|
+
# .end_row
|
32
|
+
#
|
19
33
|
def append_hugeint(value)
|
20
34
|
case value
|
21
35
|
when Integer
|
22
|
-
|
36
|
+
if respond_to?(:_append_hugeint, true)
|
37
|
+
half = 1 << 64
|
38
|
+
upper = value / half
|
39
|
+
lower = value - upper * half
|
40
|
+
_append_hugeint(lower, upper)
|
41
|
+
else
|
42
|
+
append_varchar(value.to_s)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
raise(ArgumentError, "2nd argument `#{value}` must be Integer.")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# appends date value.
|
51
|
+
#
|
52
|
+
# require 'duckdb'
|
53
|
+
# db = DuckDB::Database.open
|
54
|
+
# con = db.connect
|
55
|
+
# con.query('CREATE TABLE dates (date_value DATE)')
|
56
|
+
# appender = con.appender('dates')
|
57
|
+
# appender.begin_row
|
58
|
+
# appender.append_date(Date.today)
|
59
|
+
# # or
|
60
|
+
# # appender.append_date(Time.now)
|
61
|
+
# # appender.append_date('2021-10-10')
|
62
|
+
# appender.end_row
|
63
|
+
# appender.flush
|
64
|
+
#
|
65
|
+
def append_date(value)
|
66
|
+
case value
|
67
|
+
when Date, Time
|
68
|
+
date = value
|
69
|
+
when String
|
70
|
+
begin
|
71
|
+
date = Date.parse(value)
|
72
|
+
rescue
|
73
|
+
raise(ArgumentError, "Cannot parse argument `#{value}` to Date.")
|
74
|
+
end
|
75
|
+
else
|
76
|
+
raise(ArgumentError, "Argument `#{value}` must be Date, Time or String.")
|
77
|
+
end
|
78
|
+
|
79
|
+
_append_date(date.year, date.month, date.day)
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# appends time value.
|
84
|
+
#
|
85
|
+
# require 'duckdb'
|
86
|
+
# db = DuckDB::Database.open
|
87
|
+
# con = db.connect
|
88
|
+
# con.query('CREATE TABLE times (time_value TIME)')
|
89
|
+
# appender = con.appender('times')
|
90
|
+
# appender.begin_row
|
91
|
+
# appender.append_time(Time.now)
|
92
|
+
# # or
|
93
|
+
# # appender.append_time('01:01:01')
|
94
|
+
# appender.end_row
|
95
|
+
# appender.flush
|
96
|
+
#
|
97
|
+
def append_time(value)
|
98
|
+
case value
|
99
|
+
when Time
|
100
|
+
time = value
|
101
|
+
when String
|
102
|
+
begin
|
103
|
+
time = Time.parse(value)
|
104
|
+
rescue
|
105
|
+
raise(ArgumentError, "Cannot parse argument `#{value}` to Time.")
|
106
|
+
end
|
107
|
+
else
|
108
|
+
raise(ArgumentError, "Argument `#{value}` must be Time or String.")
|
109
|
+
end
|
110
|
+
|
111
|
+
_append_time(time.hour, time.min, time.sec, time.usec)
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# appends timestamp value.
|
116
|
+
#
|
117
|
+
# require 'duckdb'
|
118
|
+
# db = DuckDB::Database.open
|
119
|
+
# con = db.connect
|
120
|
+
# con.query('CREATE TABLE timestamps (timestamp_value TIMESTAMP)')
|
121
|
+
# appender = con.appender('timestamps')
|
122
|
+
# appender.begin_row
|
123
|
+
# appender.append_time(Time.now)
|
124
|
+
# # or
|
125
|
+
# # appender.append_time(Date.today)
|
126
|
+
# # appender.append_time('2021-08-01 01:01:01')
|
127
|
+
# appender.end_row
|
128
|
+
# appender.flush
|
129
|
+
#
|
130
|
+
def append_timestamp(value)
|
131
|
+
case value
|
132
|
+
when Time
|
133
|
+
time = value
|
134
|
+
when Date
|
135
|
+
time = value.to_time
|
136
|
+
when String
|
137
|
+
begin
|
138
|
+
time = Time.parse(value)
|
139
|
+
rescue
|
140
|
+
raise(ArgumentError, "Cannot parse argument `#{value.class} #{value}` to Time.")
|
141
|
+
end
|
23
142
|
else
|
24
|
-
|
143
|
+
raise(ArgumentError, "Argument `#{value.class} #{value}` must be Time or Date or String.")
|
25
144
|
end
|
145
|
+
_append_timestamp(time.year, time.month, time.day, time.hour, time.min, time.sec, time.nsec / 1000)
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# appends interval.
|
150
|
+
# The argument must be ISO8601 duration format.
|
151
|
+
# WARNING: This method is expremental.
|
152
|
+
#
|
153
|
+
# require 'duckdb'
|
154
|
+
# db = DuckDB::Database.open
|
155
|
+
# con = db.connect
|
156
|
+
# con.query('CREATE TABLE intervals (interval_value INTERVAL)')
|
157
|
+
# appender = con.appender('intervals')
|
158
|
+
# appender
|
159
|
+
# .begin_row
|
160
|
+
# .append_interval('P1Y2D') # => append 1 year 2 days interval.
|
161
|
+
# .end_row
|
162
|
+
# .flush
|
163
|
+
#
|
164
|
+
def append_interval(value)
|
165
|
+
raise ArgumentError, "Argument `#{value}` must be a string." unless value.is_a?(String)
|
166
|
+
|
167
|
+
hash = iso8601_interval_to_hash(value)
|
168
|
+
|
169
|
+
months, days, micros = hash_to__append_interval_args(hash)
|
170
|
+
|
171
|
+
_append_interval(months, days, micros)
|
26
172
|
end
|
27
173
|
|
28
174
|
#
|
@@ -64,11 +210,19 @@ module DuckDB
|
|
64
210
|
when TrueClass, FalseClass
|
65
211
|
append_bool(value)
|
66
212
|
when Time
|
67
|
-
|
213
|
+
if respond_to?(:append_timestamp)
|
214
|
+
append_timestamp(value)
|
215
|
+
else
|
216
|
+
append_varchar(value.strftime('%Y-%m-%d %H:%M:%S.%N'))
|
217
|
+
end
|
68
218
|
when Date
|
69
|
-
|
219
|
+
if respond_to?(:append_date)
|
220
|
+
append_date(value)
|
221
|
+
else
|
222
|
+
append_varchar(value.strftime('%Y-%m-%d'))
|
223
|
+
end
|
70
224
|
else
|
71
|
-
|
225
|
+
raise(DuckDB::Error, "not supported type #{value} (#{value.class})")
|
72
226
|
end
|
73
227
|
end
|
74
228
|
|
@@ -97,6 +251,53 @@ module DuckDB
|
|
97
251
|
def blob?(value)
|
98
252
|
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
99
253
|
end
|
254
|
+
|
255
|
+
def iso8601_interval_to_hash(value)
|
256
|
+
digit = ''
|
257
|
+
time = false
|
258
|
+
hash = {}
|
259
|
+
hash.default = 0
|
260
|
+
|
261
|
+
value.each_char do |c|
|
262
|
+
if '-0123456789.'.include?(c)
|
263
|
+
digit += c
|
264
|
+
elsif c == 'T'
|
265
|
+
time = true
|
266
|
+
digit = ''
|
267
|
+
elsif c == 'M'
|
268
|
+
m_interval_to_hash(hash, digit, time)
|
269
|
+
digit = ''
|
270
|
+
elsif c == 'S'
|
271
|
+
s_interval_to_hash(hash, digit)
|
272
|
+
digit = ''
|
273
|
+
elsif 'YDH'.include?(c)
|
274
|
+
hash[c] = digit.to_i
|
275
|
+
digit = ''
|
276
|
+
elsif c != 'P'
|
277
|
+
raise ArgumentError, "The argument `#{value}` can't be parse."
|
278
|
+
end
|
279
|
+
end
|
280
|
+
hash
|
281
|
+
end
|
282
|
+
|
283
|
+
def m_interval_to_hash(hash, digit, time)
|
284
|
+
key = time ? 'TM' : 'M'
|
285
|
+
hash[key] = digit.to_i
|
286
|
+
end
|
287
|
+
|
288
|
+
def s_interval_to_hash(hash, digit)
|
289
|
+
sec, msec = digit.split('.')
|
290
|
+
hash['S'] = sec.to_i
|
291
|
+
hash['MS'] = "#{msec}000000"[0, 6].to_i
|
292
|
+
hash['MS'] *= -1 if hash['S'].negative?
|
293
|
+
end
|
294
|
+
|
295
|
+
def hash_to__append_interval_args(hash)
|
296
|
+
months = hash['Y'] * 12 + hash['M']
|
297
|
+
days = hash['D']
|
298
|
+
micros = (hash['H'] * 3600 + hash['TM'] * 60 + hash['S']) * 1_000_000 + hash['MS']
|
299
|
+
[months, days, micros]
|
300
|
+
end
|
100
301
|
end
|
101
302
|
end
|
102
303
|
end
|
@@ -22,7 +22,7 @@ module DuckDB
|
|
22
22
|
when Integer
|
23
23
|
bind_varchar(i, value.to_s)
|
24
24
|
else
|
25
|
-
|
25
|
+
raise(ArgumentError, "2nd argument `#{value}` must be Integer.")
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -40,7 +40,7 @@ module DuckDB
|
|
40
40
|
def bind(i, value)
|
41
41
|
case value
|
42
42
|
when NilClass
|
43
|
-
respond_to?(:bind_null) ? bind_null(i) :
|
43
|
+
respond_to?(:bind_null) ? bind_null(i) : raise(DuckDB::Error, 'This bind method does not support nil value. Re-compile ruby-duckdb with DuckDB version >= 0.1.1')
|
44
44
|
when Float
|
45
45
|
bind_double(i, value)
|
46
46
|
when Integer
|
@@ -63,7 +63,7 @@ module DuckDB
|
|
63
63
|
when Date
|
64
64
|
bind_varchar(i, value.strftime('%Y-%m-%d'))
|
65
65
|
else
|
66
|
-
|
66
|
+
raise(DuckDB::Error, "not supported type `#{value}` (#{value.class})")
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
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.2.
|
4
|
+
version: 0.2.9.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: 2021-
|
11
|
+
date: 2021-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -79,8 +79,8 @@ files:
|
|
79
79
|
- ".github/workflows/test_on_ubuntu.yml"
|
80
80
|
- ".github/workflows/test_on_windows.yml"
|
81
81
|
- ".gitignore"
|
82
|
-
- ".travis.yml"
|
83
82
|
- CHANGELOG.md
|
83
|
+
- CONTRIBUTION.md
|
84
84
|
- Gemfile
|
85
85
|
- Gemfile.lock
|
86
86
|
- LICENSE
|
@@ -131,7 +131,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
131
|
requirements:
|
132
132
|
- - ">="
|
133
133
|
- !ruby/object:Gem::Version
|
134
|
-
version: 2.
|
134
|
+
version: 2.6.0
|
135
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
137
|
- - ">="
|
data/.travis.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
cache:
|
3
|
-
bundler: true
|
4
|
-
directories:
|
5
|
-
- ${HOME}/duckdb-v0.2.8
|
6
|
-
before_install:
|
7
|
-
- yes | gem update --system
|
8
|
-
- if [[ ! -d ${HOME}/duckdb-v0.2.8/build ]]; then cd ${HOME} && git clone -b v0.2.8 https://github.com/cwida/duckdb.git duckdb-v0.2.8 && cd duckdb-v0.2.8 && make && cd ${TRAVIS_BUILD_DIR}; fi
|
9
|
-
|
10
|
-
env:
|
11
|
-
- DUCKDB_VERSION=0.2.8
|
12
|
-
rvm:
|
13
|
-
- 2.5.8
|
14
|
-
- 2.6.8
|
15
|
-
- 2.7.4
|
16
|
-
- 3.0.2
|
17
|
-
- ruby-head
|
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/
|