duckdb 0.9.1.2 → 0.9.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitattributes +1 -0
- data/.github/workflows/test_on_macos.yml +3 -3
- data/.github/workflows/test_on_ubuntu.yml +3 -4
- data/.github/workflows/test_on_windows.yml +1 -1
- data/CHANGELOG.md +22 -11
- data/Dockerfile +1 -1
- data/Gemfile.lock +5 -5
- data/README.md +17 -1
- data/benchmark/async_query.rb +90 -0
- data/ext/duckdb/extconf.rb +46 -13
- data/ext/duckdb/pending_result.c +20 -4
- data/ext/duckdb/prepared_statement.c +1 -1
- data/ext/duckdb/result.c +124 -67
- data/ext/duckdb/ruby-duckdb.h +1 -0
- data/lib/duckdb/connection.rb +27 -5
- data/lib/duckdb/converter.rb +12 -0
- data/lib/duckdb/interval.rb +4 -0
- data/lib/duckdb/prepared_statement.rb +6 -0
- data/lib/duckdb/result.rb +8 -2
- data/lib/duckdb/version.rb +1 -1
- data/sample/async_query.rb +24 -0
- data/sample/async_query_stream.rb +24 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b83a52918000c5a6b188eede2053e8f6d3118baad3e451b6a0db48aa0ab8b977
|
4
|
+
data.tar.gz: 12dec4bf0fbf2819067e58f57047a8fd2a0b5f0a6e329fa89d8dc0edc59ed338
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '014489d9944bf9cb36c883450f654be009fccee51a3af1215e2f64e525d13ca8faed8ffed08df60368cd5c7c93e29b773626f9e6b4cccbd00593992d0465af28'
|
7
|
+
data.tar.gz: '08a0fc5a78f29fd006c3e308ab0346df3f18944d337747af8d753a213232bd9c68e1ce5985b040dd00330d8ac6233a233633e466b0d26b4f045dfd9f9835155a'
|
data/.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.rb diff=ruby
|
@@ -15,8 +15,8 @@ jobs:
|
|
15
15
|
runs-on: macos-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-
|
19
|
-
duckdb: ['0.9.
|
18
|
+
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-rc1', 'head']
|
19
|
+
duckdb: ['0.9.2', '0.8.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v3
|
@@ -59,7 +59,7 @@ jobs:
|
|
59
59
|
|
60
60
|
- name: run test with Ruby ${{ matrix.ruby }}
|
61
61
|
run: |
|
62
|
-
rake test
|
62
|
+
env RUBYOPT=-W:deprecated rake test
|
63
63
|
|
64
64
|
post-test:
|
65
65
|
name: All tests passed on macos
|
@@ -15,8 +15,8 @@ jobs:
|
|
15
15
|
runs-on: ubuntu-latest
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
|
-
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-
|
19
|
-
duckdb: ['0.9.
|
18
|
+
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-rc1', 'head']
|
19
|
+
duckdb: ['0.9.2', '0.8.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v3
|
@@ -49,7 +49,6 @@ jobs:
|
|
49
49
|
env:
|
50
50
|
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
51
51
|
run: |
|
52
|
-
gem install bundler
|
53
52
|
bundle install --jobs 4 --retry 3
|
54
53
|
bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/
|
55
54
|
|
@@ -57,7 +56,7 @@ jobs:
|
|
57
56
|
env:
|
58
57
|
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
59
58
|
run: |
|
60
|
-
rake test
|
59
|
+
env RUBYOPT=-W:deprecated rake test
|
61
60
|
|
62
61
|
post-test:
|
63
62
|
name: All tests passed on Ubuntu
|
data/CHANGELOG.md
CHANGED
@@ -1,16 +1,27 @@
|
|
1
1
|
# ChangeLog
|
2
2
|
|
3
|
+
# 0.9.2.1
|
4
|
+
- support Time column in `DuckDB#Result#chunk_each`.
|
5
|
+
- add `DuckDB::Interval#eql?`.
|
6
|
+
|
7
|
+
# 0.9.2
|
8
|
+
- add `DuckDB::Connection#async_query_stream`.
|
9
|
+
- `DuckDB::PendingResult` accepts second argument. If the second argument is
|
10
|
+
true, `PendingResult#execute_pending` returns streaming `DuckDB::Result` object.
|
11
|
+
- add `DuckDB::PreparedStatement#pending_prepared_stream`
|
12
|
+
- add `DuckDB::Result#streaming?`.
|
13
|
+
|
3
14
|
# 0.9.1.2
|
4
|
-
- add DuckDB::Connection#interrupt
|
5
|
-
- add DuckDB::Connection#async_query
|
15
|
+
- add `DuckDB::Connection#interrupt`, `DuckDB::Connection#query_progress`.
|
16
|
+
- add `DuckDB::Connection#async_query`, alias method `async_execute`.
|
6
17
|
|
7
18
|
# 0.9.1.1
|
8
19
|
- change default branch to main from master.
|
9
|
-
- add DuckDB::PendingResult class.
|
10
|
-
- add DuckDB::PendingResult#state
|
11
|
-
- add DuckDB::PendingResult#execute_task
|
12
|
-
- add DuckDB::PendingResult#execute_pending
|
13
|
-
- add DuckDB::PreparedStatement#pending_prepared
|
20
|
+
- add `DuckDB::PendingResult` class.
|
21
|
+
- add `DuckDB::PendingResult#state`.
|
22
|
+
- add `DuckDB::PendingResult#execute_task`.
|
23
|
+
- add `DuckDB::PendingResult#execute_pending`.
|
24
|
+
- add `DuckDB::PreparedStatement#pending_prepared`.
|
14
25
|
|
15
26
|
## Breaking Changes
|
16
27
|
- drop duckdb v0.7.x.
|
@@ -21,16 +32,16 @@
|
|
21
32
|
|
22
33
|
# 0.9.0.1
|
23
34
|
- add `DuckDB::PreparedStatement#bind_parameter_index`.
|
24
|
-
- DuckDB::Connection#query accepts SQL with named bind parameters.
|
35
|
+
- `DuckDB::Connection#query` accepts SQL with named bind parameters.
|
25
36
|
|
26
37
|
# 0.9.0
|
27
38
|
- bump duckdb to 0.9.0.
|
28
39
|
|
29
40
|
## Breaking Changes
|
30
|
-
- deprecation warning when DuckDB::Result.each calling with `DuckDB::Result.use_chunk_each` is false.
|
41
|
+
- deprecation warning when `DuckDB::Result.each` calling with `DuckDB::Result.use_chunk_each` is false.
|
31
42
|
The `each` behavior will be same as `DuckDB::Result.chunk_each` in the future.
|
32
43
|
set `DuckDB::Result.use_chunk_each = true` to suppress the warning.
|
33
|
-
- DuckDB::Result#
|
44
|
+
- `DuckDB::Result#chunk_each` returns `DuckDB::Interval` class when the column type is INTERVAL.
|
34
45
|
|
35
46
|
# 0.8.1.3
|
36
47
|
- Fix BigDecimal conversion.
|
@@ -57,7 +68,7 @@
|
|
57
68
|
But `DuckDB::Result#each` behavior will be changed like as `DuckDB::Result#chunk_each` in near future release.
|
58
69
|
And there are some breaking changes.
|
59
70
|
Write `DuckdDB::Result.use_chunk_each = true` if you want to try new behavior.
|
60
|
-
```
|
71
|
+
```ruby
|
61
72
|
DuckDB::Result.use_chunk_each = true
|
62
73
|
|
63
74
|
result = con.query('SELECT ....')
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,24 +1,24 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
duckdb (0.9.1
|
4
|
+
duckdb (0.9.2.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
benchmark-ips (2.
|
9
|
+
benchmark-ips (2.13.0)
|
10
10
|
mini_portile2 (2.8.5)
|
11
11
|
minitest (5.20.0)
|
12
|
-
nokogiri (1.15.
|
12
|
+
nokogiri (1.15.5)
|
13
13
|
mini_portile2 (~> 2.8.2)
|
14
14
|
racc (~> 1.4)
|
15
|
-
nokogiri (1.15.
|
15
|
+
nokogiri (1.15.5-x86_64-linux)
|
16
16
|
racc (~> 1.4)
|
17
17
|
racc (1.7.3)
|
18
18
|
rake (13.1.0)
|
19
19
|
rake-compiler (1.2.5)
|
20
20
|
rake
|
21
|
-
ruby_memcheck (2.
|
21
|
+
ruby_memcheck (2.3.0)
|
22
22
|
nokogiri
|
23
23
|
stackprof (0.2.25)
|
24
24
|
|
data/README.md
CHANGED
@@ -104,10 +104,25 @@ con.query('SELECT * FROM users WHERE name = ? AND email = ?', 'Alice', 'alice@ex
|
|
104
104
|
con.query('SELECT * FROM users WHERE name = $name AND email = $email', name: 'Alice', email: 'alice@example.com')
|
105
105
|
```
|
106
106
|
|
107
|
+
### using async query
|
108
|
+
|
109
|
+
You can use async query.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
DuckDB::Result.use_chunk_each = true # must be true.
|
113
|
+
...
|
114
|
+
|
115
|
+
pending_result = con.async_query_stream('SLOW QUERY')
|
116
|
+
pending_result.execute_task while pending_result.state == :not_ready
|
117
|
+
|
118
|
+
result = pending_result.execute_pending
|
119
|
+
result.each.first
|
120
|
+
```
|
121
|
+
|
122
|
+
Here is [the benchmark](./benchmark/async_query.rb).
|
107
123
|
|
108
124
|
### using BLOB column
|
109
125
|
|
110
|
-
BLOB is available with DuckDB v0.2.5 or later.
|
111
126
|
Use `DuckDB::Blob.new` or use sting#force_encoding(Encoding::BINARY)
|
112
127
|
|
113
128
|
```ruby
|
@@ -119,6 +134,7 @@ DuckDB::Database.open do |db|
|
|
119
134
|
stmt = DuckDB::PreparedStatement.new(con, 'INSERT INTO blob_table VALUES ($1)')
|
120
135
|
|
121
136
|
stmt.bind(1, DuckDB::Blob.new("\0\1\2\3\4\5"))
|
137
|
+
# or
|
122
138
|
# stmt.bind(1, "\0\1\2\3\4\5".force_encoding(Encoding::BINARY))
|
123
139
|
stmt.execute
|
124
140
|
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'duckdb'
|
3
|
+
require 'benchmark/ips'
|
4
|
+
|
5
|
+
|
6
|
+
DuckDB::Result.use_chunk_each = true
|
7
|
+
DuckDB::Database.open do |db|
|
8
|
+
db.connect do |con|
|
9
|
+
con.query('SET threads=1')
|
10
|
+
con.query('CREATE TABLE tbl as SELECT range a, mod(range, 10) b FROM range(100000)')
|
11
|
+
con.query('CREATE TABLE tbl2 as SELECT range a, mod(range, 10) b FROM range(100000)')
|
12
|
+
query_sql = 'SELECT * FROM tbl where b = (SELECT min(b) FROM tbl2)'
|
13
|
+
print <<~END_OF_HEAD
|
14
|
+
|
15
|
+
Benchmark: Get first record ======================================
|
16
|
+
END_OF_HEAD
|
17
|
+
|
18
|
+
Benchmark.ips do |x|
|
19
|
+
x.report('async_query') do
|
20
|
+
pending_result = con.async_query(query_sql)
|
21
|
+
|
22
|
+
pending_result.execute_task while pending_result.state == :not_ready
|
23
|
+
result = pending_result.execute_pending
|
24
|
+
result.each.first
|
25
|
+
end
|
26
|
+
x.report('query') do
|
27
|
+
result = con.query(query_sql)
|
28
|
+
result.each.first
|
29
|
+
end
|
30
|
+
x.report('async_query_stream') do
|
31
|
+
pending_result = con.async_query_stream(query_sql)
|
32
|
+
|
33
|
+
pending_result.execute_task while pending_result.state == :not_ready
|
34
|
+
result = pending_result.execute_pending
|
35
|
+
result.each.first
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
print <<~END_OF_HEAD
|
40
|
+
|
41
|
+
|
42
|
+
Benchmark: Get all records ======================================
|
43
|
+
END_OF_HEAD
|
44
|
+
|
45
|
+
Benchmark.ips do |x|
|
46
|
+
x.report('async_query') do
|
47
|
+
pending_result = con.async_query(query_sql)
|
48
|
+
|
49
|
+
pending_result.execute_task while pending_result.state == :not_ready
|
50
|
+
result = pending_result.execute_pending
|
51
|
+
result.each.to_a
|
52
|
+
end
|
53
|
+
x.report('query') do
|
54
|
+
result = con.query(query_sql)
|
55
|
+
result.each.to_a
|
56
|
+
end
|
57
|
+
x.report('async_query_stream') do
|
58
|
+
pending_result = con.async_query_stream(query_sql)
|
59
|
+
|
60
|
+
pending_result.execute_task while pending_result.state == :not_ready
|
61
|
+
result = pending_result.execute_pending
|
62
|
+
result.each.to_a
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
__END__
|
69
|
+
|
70
|
+
results:
|
71
|
+
Benchmark: Get first record ======================================
|
72
|
+
Warming up --------------------------------------
|
73
|
+
async_query 70.000 i/100ms
|
74
|
+
query 88.000 i/100ms
|
75
|
+
async_query_stream 188.000 i/100ms
|
76
|
+
Calculating -------------------------------------
|
77
|
+
async_query 847.191 (± 4.6%) i/s - 4.270k in 5.051650s
|
78
|
+
query 850.509 (± 3.8%) i/s - 4.312k in 5.078167s
|
79
|
+
async_query_stream 1.757k (± 7.3%) i/s - 8.836k in 5.057142s
|
80
|
+
|
81
|
+
|
82
|
+
Benchmark: Get all records ======================================
|
83
|
+
Warming up --------------------------------------
|
84
|
+
async_query 40.000 i/100ms
|
85
|
+
query 40.000 i/100ms
|
86
|
+
async_query_stream 39.000 i/100ms
|
87
|
+
Calculating -------------------------------------
|
88
|
+
async_query 402.567 (± 0.5%) i/s - 2.040k in 5.067639s
|
89
|
+
query 406.632 (± 0.7%) i/s - 2.040k in 5.017079s
|
90
|
+
async_query_stream 395.532 (± 0.8%) i/s - 1.989k in 5.028955s
|
data/ext/duckdb/extconf.rb
CHANGED
@@ -1,31 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'mkmf'
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
DUCKDB_REQUIRED_VERSION = '0.8.0'
|
6
|
+
|
7
|
+
def check_duckdb_header(header, version)
|
8
|
+
found = find_header(
|
9
|
+
header,
|
10
|
+
'/opt/homebrew/include',
|
11
|
+
'/opt/homebrew/opt/duckdb/include',
|
12
|
+
'/opt/local/include'
|
13
|
+
)
|
14
|
+
return if found
|
15
|
+
|
16
|
+
msg = "#{header} is not found. Install #{header} of duckdb >= #{version}."
|
17
|
+
print_message(msg)
|
18
|
+
raise msg
|
7
19
|
end
|
8
20
|
|
9
|
-
def check_duckdb_library(func, version)
|
10
|
-
|
21
|
+
def check_duckdb_library(library, func, version)
|
22
|
+
found = find_library(
|
23
|
+
library,
|
24
|
+
func,
|
25
|
+
'/opt/homebrew/lib',
|
26
|
+
'/opt/homebrew/opt/duckdb/lib',
|
27
|
+
'/opt/local/lib'
|
28
|
+
)
|
29
|
+
return if found
|
11
30
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
puts msg
|
16
|
-
puts '*' * 80
|
17
|
-
puts ''
|
31
|
+
library_name = duckdb_library_name(library)
|
32
|
+
msg = "#{library_name} is not found. Install #{library_name} of duckdb >= #{version}."
|
33
|
+
print_message(msg)
|
18
34
|
raise msg
|
19
35
|
end
|
20
36
|
|
37
|
+
def duckdb_library_name(library)
|
38
|
+
"lib#{library}.(so|dylib|dll)"
|
39
|
+
end
|
40
|
+
|
41
|
+
def print_message(msg)
|
42
|
+
print <<~END_OF_MESSAGE
|
43
|
+
|
44
|
+
#{'*' * 80}
|
45
|
+
#{msg}
|
46
|
+
#{'*' * 80}
|
47
|
+
|
48
|
+
END_OF_MESSAGE
|
49
|
+
end
|
50
|
+
|
21
51
|
dir_config('duckdb')
|
22
52
|
|
53
|
+
check_duckdb_header('duckdb.h', DUCKDB_REQUIRED_VERSION)
|
54
|
+
|
23
55
|
# check duckdb >= 0.8.0
|
24
|
-
check_duckdb_library('
|
56
|
+
check_duckdb_library('duckdb', 'duckdb_string_is_inlined', DUCKDB_REQUIRED_VERSION)
|
25
57
|
|
26
58
|
# check duckdb >= 0.9.0
|
27
59
|
have_func('duckdb_bind_parameter_index', 'duckdb.h')
|
28
60
|
|
61
|
+
# duckdb_parameter_name is not found on Windows.
|
29
62
|
have_func('duckdb_parameter_name', 'duckdb.h')
|
30
63
|
|
31
64
|
create_makefile('duckdb/duckdb_native')
|
data/ext/duckdb/pending_result.c
CHANGED
@@ -5,7 +5,7 @@ static VALUE cDuckDBPendingResult;
|
|
5
5
|
static void deallocate(void *ctx);
|
6
6
|
static VALUE allocate(VALUE klass);
|
7
7
|
static size_t memsize(const void *p);
|
8
|
-
static VALUE duckdb_pending_result_initialize(VALUE
|
8
|
+
static VALUE duckdb_pending_result_initialize(int argc, VALUE *args, VALUE self);
|
9
9
|
static VALUE duckdb_pending_result_execute_task(VALUE self);
|
10
10
|
static VALUE duckdb_pending_result_execute_pending(VALUE self);
|
11
11
|
|
@@ -38,11 +38,27 @@ static size_t memsize(const void *p) {
|
|
38
38
|
return sizeof(rubyDuckDBPendingResult);
|
39
39
|
}
|
40
40
|
|
41
|
-
static VALUE duckdb_pending_result_initialize(VALUE
|
41
|
+
static VALUE duckdb_pending_result_initialize(int argc, VALUE *argv, VALUE self) {
|
42
|
+
VALUE oDuckDBPreparedStatement;
|
43
|
+
VALUE streaming_p = Qfalse;
|
44
|
+
duckdb_state state;
|
45
|
+
|
46
|
+
rb_scan_args(argc, argv, "11", &oDuckDBPreparedStatement, &streaming_p);
|
47
|
+
|
48
|
+
if (rb_obj_is_kind_of(oDuckDBPreparedStatement, cDuckDBPreparedStatement) != Qtrue) {
|
49
|
+
rb_raise(rb_eTypeError, "1st argument must be DuckDB::PreparedStatement");
|
50
|
+
}
|
51
|
+
|
42
52
|
rubyDuckDBPendingResult *ctx = get_struct_pending_result(self);
|
43
53
|
rubyDuckDBPreparedStatement *stmt = get_struct_prepared_statement(oDuckDBPreparedStatement);
|
44
54
|
|
45
|
-
if (
|
55
|
+
if (!NIL_P(streaming_p) && streaming_p == Qtrue) {
|
56
|
+
state = duckdb_pending_prepared_streaming(stmt->prepared_statement, &(ctx->pending_result));
|
57
|
+
} else {
|
58
|
+
state = duckdb_pending_prepared(stmt->prepared_statement, &(ctx->pending_result));
|
59
|
+
}
|
60
|
+
|
61
|
+
if (state == DuckDBError) {
|
46
62
|
rb_raise(eDuckDBError, "%s", duckdb_pending_error(ctx->pending_result));
|
47
63
|
}
|
48
64
|
return self;
|
@@ -112,7 +128,7 @@ void rbduckdb_init_duckdb_pending_result(void) {
|
|
112
128
|
cDuckDBPendingResult = rb_define_class_under(mDuckDB, "PendingResult", rb_cObject);
|
113
129
|
rb_define_alloc_func(cDuckDBPendingResult, allocate);
|
114
130
|
|
115
|
-
rb_define_method(cDuckDBPendingResult, "initialize", duckdb_pending_result_initialize, 1);
|
131
|
+
rb_define_method(cDuckDBPendingResult, "initialize", duckdb_pending_result_initialize, -1);
|
116
132
|
rb_define_method(cDuckDBPendingResult, "execute_task", duckdb_pending_result_execute_task, 0);
|
117
133
|
rb_define_method(cDuckDBPendingResult, "execute_pending", duckdb_pending_result_execute_pending, 0);
|
118
134
|
|
data/ext/duckdb/result.c
CHANGED
@@ -19,6 +19,11 @@ static VALUE duckdb_result_column_count(VALUE oDuckDBResult);
|
|
19
19
|
static VALUE duckdb_result_row_count(VALUE oDuckDBResult);
|
20
20
|
static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult);
|
21
21
|
static VALUE duckdb_result_columns(VALUE oDuckDBResult);
|
22
|
+
static VALUE duckdb_result_streaming_p(VALUE oDuckDBResult);
|
23
|
+
static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult);
|
24
|
+
|
25
|
+
static VALUE duckdb_result__chunk_stream(VALUE oDuckDBResult);
|
26
|
+
static void yield_rows(duckdb_data_chunk chunk, idx_t col_count);
|
22
27
|
static VALUE duckdb_result__column_type(VALUE oDuckDBResult, VALUE col_idx);
|
23
28
|
static VALUE duckdb_result__is_null(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx);
|
24
29
|
static VALUE duckdb_result__to_boolean(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx);
|
@@ -39,6 +44,7 @@ static VALUE duckdb_result__enum_dictionary_value(VALUE oDuckDBResult, VALUE col
|
|
39
44
|
|
40
45
|
static VALUE vector_date(void *vector_data, idx_t row_idx);
|
41
46
|
static VALUE vector_timestamp(void* vector_data, idx_t row_idx);
|
47
|
+
static VALUE vector_time(void* vector_data, idx_t row_idx);
|
42
48
|
static VALUE vector_interval(void* vector_data, idx_t row_idx);
|
43
49
|
static VALUE vector_blob(void* vector_data, idx_t row_idx);
|
44
50
|
static VALUE vector_varchar(void* vector_data, idx_t row_idx);
|
@@ -50,7 +56,6 @@ static VALUE vector_map(duckdb_logical_type ty, duckdb_vector vector, idx_t row_
|
|
50
56
|
static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx);
|
51
57
|
static VALUE vector_uuid(void* vector_data, idx_t row_idx);
|
52
58
|
static VALUE vector_value(duckdb_vector vector, idx_t row_idx);
|
53
|
-
static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult);
|
54
59
|
|
55
60
|
static const rb_data_type_t result_data_type = {
|
56
61
|
"DuckDB/Result",
|
@@ -235,6 +240,79 @@ static VALUE duckdb_result_columns(VALUE oDuckDBResult) {
|
|
235
240
|
return ary;
|
236
241
|
}
|
237
242
|
|
243
|
+
/*
|
244
|
+
* call-seq:
|
245
|
+
* result.streaming? -> Boolean
|
246
|
+
*
|
247
|
+
* Returns true if the result is streaming, otherwise false.
|
248
|
+
*
|
249
|
+
*/
|
250
|
+
static VALUE duckdb_result_streaming_p(VALUE oDuckDBResult) {
|
251
|
+
rubyDuckDBResult *ctx;
|
252
|
+
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
253
|
+
return duckdb_result_is_streaming(ctx->result) ? Qtrue : Qfalse;
|
254
|
+
}
|
255
|
+
|
256
|
+
static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult) {
|
257
|
+
rubyDuckDBResult *ctx;
|
258
|
+
idx_t col_count;
|
259
|
+
idx_t chunk_count;
|
260
|
+
idx_t chunk_idx;
|
261
|
+
duckdb_data_chunk chunk;
|
262
|
+
|
263
|
+
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
264
|
+
|
265
|
+
col_count = duckdb_column_count(&(ctx->result));
|
266
|
+
chunk_count = duckdb_result_chunk_count(ctx->result);
|
267
|
+
|
268
|
+
RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
|
269
|
+
|
270
|
+
for (chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) {
|
271
|
+
chunk = duckdb_result_get_chunk(ctx->result, chunk_idx);
|
272
|
+
yield_rows(chunk, col_count);
|
273
|
+
duckdb_destroy_data_chunk(&chunk);
|
274
|
+
}
|
275
|
+
return Qnil;
|
276
|
+
}
|
277
|
+
|
278
|
+
static VALUE duckdb_result__chunk_stream(VALUE oDuckDBResult) {
|
279
|
+
rubyDuckDBResult *ctx;
|
280
|
+
duckdb_data_chunk chunk;
|
281
|
+
idx_t col_count;
|
282
|
+
|
283
|
+
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
284
|
+
|
285
|
+
RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
|
286
|
+
|
287
|
+
col_count = duckdb_column_count(&(ctx->result));
|
288
|
+
|
289
|
+
while((chunk = duckdb_stream_fetch_chunk(ctx->result)) != NULL) {
|
290
|
+
yield_rows(chunk, col_count);
|
291
|
+
duckdb_destroy_data_chunk(&chunk);
|
292
|
+
}
|
293
|
+
return Qnil;
|
294
|
+
}
|
295
|
+
|
296
|
+
static void yield_rows(duckdb_data_chunk chunk, idx_t col_count) {
|
297
|
+
idx_t row_count;
|
298
|
+
idx_t row_idx;
|
299
|
+
idx_t col_idx;
|
300
|
+
duckdb_vector vector;
|
301
|
+
VALUE row;
|
302
|
+
VALUE val;
|
303
|
+
|
304
|
+
row_count = duckdb_data_chunk_get_size(chunk);
|
305
|
+
for (row_idx = 0; row_idx < row_count; row_idx++) {
|
306
|
+
row = rb_ary_new2(col_count);
|
307
|
+
for (col_idx = 0; col_idx < col_count; col_idx++) {
|
308
|
+
vector = duckdb_data_chunk_get_vector(chunk, col_idx);
|
309
|
+
val = vector_value(vector, row_idx);
|
310
|
+
rb_ary_store(row, col_idx, val);
|
311
|
+
}
|
312
|
+
rb_yield(row);
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
238
316
|
static VALUE duckdb_result__column_type(VALUE oDuckDBResult, VALUE col_idx) {
|
239
317
|
rubyDuckDBResult *ctx;
|
240
318
|
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
@@ -405,32 +483,43 @@ static VALUE vector_date(void *vector_data, idx_t row_idx) {
|
|
405
483
|
duckdb_date_struct date = duckdb_from_date(((duckdb_date *) vector_data)[row_idx]);
|
406
484
|
|
407
485
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_date"), 3,
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
486
|
+
INT2FIX(date.year),
|
487
|
+
INT2FIX(date.month),
|
488
|
+
INT2FIX(date.day)
|
489
|
+
);
|
412
490
|
}
|
413
491
|
|
414
492
|
static VALUE vector_timestamp(void* vector_data, idx_t row_idx) {
|
415
493
|
duckdb_timestamp_struct data = duckdb_from_timestamp(((duckdb_timestamp *)vector_data)[row_idx]);
|
416
494
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_time"), 7,
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
495
|
+
INT2FIX(data.date.year),
|
496
|
+
INT2FIX(data.date.month),
|
497
|
+
INT2FIX(data.date.day),
|
498
|
+
INT2FIX(data.time.hour),
|
499
|
+
INT2FIX(data.time.min),
|
500
|
+
INT2FIX(data.time.sec),
|
501
|
+
INT2NUM(data.time.micros)
|
502
|
+
);
|
503
|
+
}
|
504
|
+
|
505
|
+
static VALUE vector_time(void* vector_data, idx_t row_idx) {
|
506
|
+
duckdb_time_struct data = duckdb_from_time(((duckdb_time *)vector_data)[row_idx]);
|
507
|
+
return rb_funcall(mDuckDBConverter, rb_intern("_to_time_from_duckdb_time"), 4,
|
508
|
+
INT2FIX(data.hour),
|
509
|
+
INT2FIX(data.min),
|
510
|
+
INT2FIX(data.sec),
|
511
|
+
INT2NUM(data.micros)
|
512
|
+
);
|
425
513
|
}
|
426
514
|
|
515
|
+
|
427
516
|
static VALUE vector_interval(void* vector_data, idx_t row_idx) {
|
428
517
|
duckdb_interval data = ((duckdb_interval *)vector_data)[row_idx];
|
429
518
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_interval_from_vector"), 3,
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
519
|
+
INT2NUM(data.months),
|
520
|
+
INT2NUM(data.days),
|
521
|
+
LL2NUM(data.micros)
|
522
|
+
);
|
434
523
|
}
|
435
524
|
|
436
525
|
static VALUE vector_blob(void* vector_data, idx_t row_idx) {
|
@@ -454,9 +543,9 @@ static VALUE vector_varchar(void* vector_data, idx_t row_idx) {
|
|
454
543
|
static VALUE vector_hugeint(void* vector_data, idx_t row_idx) {
|
455
544
|
duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
|
456
545
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_hugeint_from_vector"), 2,
|
457
|
-
|
458
|
-
|
459
|
-
|
546
|
+
ULL2NUM(hugeint.lower),
|
547
|
+
LL2NUM(hugeint.upper)
|
548
|
+
);
|
460
549
|
}
|
461
550
|
|
462
551
|
static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
|
@@ -477,11 +566,11 @@ static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row
|
|
477
566
|
}
|
478
567
|
|
479
568
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_decimal_from_vector"), 4,
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
569
|
+
INT2FIX(width),
|
570
|
+
INT2FIX(scale),
|
571
|
+
ULL2NUM(value.lower),
|
572
|
+
LL2NUM(value.upper)
|
573
|
+
);
|
485
574
|
}
|
486
575
|
|
487
576
|
static VALUE vector_enum(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
|
@@ -577,9 +666,9 @@ static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t r
|
|
577
666
|
static VALUE vector_uuid(void* vector_data, idx_t row_idx) {
|
578
667
|
duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
|
579
668
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_uuid_from_vector"), 2,
|
580
|
-
|
581
|
-
|
582
|
-
|
669
|
+
ULL2NUM(hugeint.lower),
|
670
|
+
LL2NUM(hugeint.upper)
|
671
|
+
);
|
583
672
|
}
|
584
673
|
|
585
674
|
static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
@@ -617,7 +706,7 @@ static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
|
617
706
|
case DUCKDB_TYPE_BIGINT:
|
618
707
|
obj = LL2NUM(((int64_t *) vector_data)[row_idx]);
|
619
708
|
break;
|
620
|
-
|
709
|
+
case DUCKDB_TYPE_UTINYINT:
|
621
710
|
obj = INT2FIX(((uint8_t *) vector_data)[row_idx]);
|
622
711
|
break;
|
623
712
|
case DUCKDB_TYPE_USMALLINT:
|
@@ -644,6 +733,9 @@ static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
|
644
733
|
case DUCKDB_TYPE_TIMESTAMP:
|
645
734
|
obj = vector_timestamp(vector_data, row_idx);
|
646
735
|
break;
|
736
|
+
case DUCKDB_TYPE_TIME:
|
737
|
+
obj = vector_time(vector_data, row_idx);
|
738
|
+
break;
|
647
739
|
case DUCKDB_TYPE_INTERVAL:
|
648
740
|
obj = vector_interval(vector_data, row_idx);
|
649
741
|
break;
|
@@ -680,43 +772,6 @@ static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
|
680
772
|
return obj;
|
681
773
|
}
|
682
774
|
|
683
|
-
static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult) {
|
684
|
-
rubyDuckDBResult *ctx;
|
685
|
-
VALUE row;
|
686
|
-
idx_t col_count;
|
687
|
-
idx_t row_count;
|
688
|
-
idx_t chunk_count;
|
689
|
-
idx_t col_idx;
|
690
|
-
idx_t row_idx;
|
691
|
-
idx_t chunk_idx;
|
692
|
-
duckdb_data_chunk chunk;
|
693
|
-
duckdb_vector vector;
|
694
|
-
VALUE val;
|
695
|
-
|
696
|
-
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
697
|
-
|
698
|
-
col_count = duckdb_column_count(&(ctx->result));
|
699
|
-
chunk_count = duckdb_result_chunk_count(ctx->result);
|
700
|
-
|
701
|
-
RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
|
702
|
-
|
703
|
-
for (chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) {
|
704
|
-
chunk = duckdb_result_get_chunk(ctx->result, chunk_idx);
|
705
|
-
row_count = duckdb_data_chunk_get_size(chunk);
|
706
|
-
for (row_idx = 0; row_idx < row_count; row_idx++) {
|
707
|
-
row = rb_ary_new2(col_count);
|
708
|
-
for (col_idx = 0; col_idx < col_count; col_idx++) {
|
709
|
-
vector = duckdb_data_chunk_get_vector(chunk, col_idx);
|
710
|
-
val = vector_value(vector, row_idx);
|
711
|
-
rb_ary_store(row, col_idx, val);
|
712
|
-
}
|
713
|
-
rb_yield(row);
|
714
|
-
}
|
715
|
-
duckdb_destroy_data_chunk(&chunk);
|
716
|
-
}
|
717
|
-
return Qnil;
|
718
|
-
}
|
719
|
-
|
720
775
|
void rbduckdb_init_duckdb_result(void) {
|
721
776
|
cDuckDBResult = rb_define_class_under(mDuckDB, "Result", rb_cObject);
|
722
777
|
rb_define_alloc_func(cDuckDBResult, allocate);
|
@@ -725,6 +780,9 @@ void rbduckdb_init_duckdb_result(void) {
|
|
725
780
|
rb_define_method(cDuckDBResult, "row_count", duckdb_result_row_count, 0);
|
726
781
|
rb_define_method(cDuckDBResult, "rows_changed", duckdb_result_rows_changed, 0);
|
727
782
|
rb_define_method(cDuckDBResult, "columns", duckdb_result_columns, 0);
|
783
|
+
rb_define_method(cDuckDBResult, "streaming?", duckdb_result_streaming_p, 0);
|
784
|
+
rb_define_method(cDuckDBResult, "chunk_each", duckdb_result_chunk_each, 0);
|
785
|
+
rb_define_private_method(cDuckDBResult, "_chunk_stream", duckdb_result__chunk_stream, 0);
|
728
786
|
rb_define_private_method(cDuckDBResult, "_column_type", duckdb_result__column_type, 1);
|
729
787
|
rb_define_private_method(cDuckDBResult, "_null?", duckdb_result__is_null, 2);
|
730
788
|
rb_define_private_method(cDuckDBResult, "_to_boolean", duckdb_result__to_boolean, 2);
|
@@ -742,5 +800,4 @@ void rbduckdb_init_duckdb_result(void) {
|
|
742
800
|
rb_define_private_method(cDuckDBResult, "_enum_internal_type", duckdb_result__enum_internal_type, 1);
|
743
801
|
rb_define_private_method(cDuckDBResult, "_enum_dictionary_size", duckdb_result__enum_dictionary_size, 1);
|
744
802
|
rb_define_private_method(cDuckDBResult, "_enum_dictionary_value", duckdb_result__enum_dictionary_value, 2);
|
745
|
-
rb_define_method(cDuckDBResult, "chunk_each", duckdb_result_chunk_each, 0);
|
746
803
|
}
|
data/ext/duckdb/ruby-duckdb.h
CHANGED
data/lib/duckdb/connection.rb
CHANGED
@@ -42,14 +42,12 @@ module DuckDB
|
|
42
42
|
# require 'duckdb'
|
43
43
|
# db = DuckDB::Database.open('duckdb_file')
|
44
44
|
# con = db.connect
|
45
|
-
# pending_result = con.async_query('SELECT * FROM users')
|
46
|
-
# sql = 'SELECT * FROM users WHERE name = ? AND email = ?'
|
47
|
-
# pending_result = con.async_query(sql, 'Dave', 'dave@example.com')
|
48
|
-
#
|
49
|
-
# # or You can use named parameter.
|
50
45
|
#
|
51
46
|
# sql = 'SELECT * FROM users WHERE name = $name AND email = $email'
|
52
47
|
# pending_result = con.async_query(sql, name: 'Dave', email: 'dave@example.com')
|
48
|
+
# pending_result.execute_task while pending_result.state == :not_ready
|
49
|
+
# result = pending_result.execute_pending
|
50
|
+
# result.each.first
|
53
51
|
#
|
54
52
|
def async_query(sql, *args, **kwargs)
|
55
53
|
stmt = PreparedStatement.new(self, sql)
|
@@ -57,6 +55,30 @@ module DuckDB
|
|
57
55
|
stmt.pending_prepared
|
58
56
|
end
|
59
57
|
|
58
|
+
#
|
59
|
+
# executes sql with args asynchronously and provides streaming result.
|
60
|
+
# The first argument sql must be SQL string.
|
61
|
+
# The rest arguments are parameters of SQL string.
|
62
|
+
# This method returns DuckDB::PendingResult object.
|
63
|
+
#
|
64
|
+
# require 'duckdb'
|
65
|
+
# DuckDB::Result.use_chunk_each = true # must be true
|
66
|
+
# db = DuckDB::Database.open('duckdb_file')
|
67
|
+
# con = db.connect
|
68
|
+
#
|
69
|
+
# sql = 'SELECT * FROM users WHERE name = $name AND email = $email'
|
70
|
+
# pending_result = con.async_query_stream(sql, name: 'Dave', email: 'dave@example.com')
|
71
|
+
#
|
72
|
+
# pending_result.execute_task while pending_result.state == :not_ready
|
73
|
+
# result = pending_result.execute_pending
|
74
|
+
# result.each.first
|
75
|
+
#
|
76
|
+
def async_query_stream(sql, *args, **kwargs)
|
77
|
+
stmt = PreparedStatement.new(self, sql)
|
78
|
+
stmt.bind_args(*args, **kwargs)
|
79
|
+
stmt.pending_prepared_stream
|
80
|
+
end
|
81
|
+
|
60
82
|
#
|
61
83
|
# connects DuckDB database
|
62
84
|
# The first argument is DuckDB::Database object
|
data/lib/duckdb/converter.rb
CHANGED
@@ -19,6 +19,18 @@ module DuckDB
|
|
19
19
|
Time.local(year, month, day, hour, minute, second, microsecond)
|
20
20
|
end
|
21
21
|
|
22
|
+
def _to_time_from_duckdb_time(hour, minute, second, microsecond)
|
23
|
+
Time.parse(
|
24
|
+
format(
|
25
|
+
'%<hour>02d:%<minute>02d:%<second>02d.%<microsecond>06d',
|
26
|
+
hour: hour,
|
27
|
+
minute: minute,
|
28
|
+
second: second,
|
29
|
+
microsecond: microsecond
|
30
|
+
)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
22
34
|
def _to_hugeint_from_vector(lower, upper)
|
23
35
|
(upper << HALF_HUGEINT_BIT) + lower
|
24
36
|
end
|
data/lib/duckdb/interval.rb
CHANGED
@@ -24,6 +24,12 @@ module DuckDB
|
|
24
24
|
PendingResult.new(self)
|
25
25
|
end
|
26
26
|
|
27
|
+
def pending_prepared_stream
|
28
|
+
raise DuckDB::Error, 'DuckDB::Result.use_chunk_each must be true.' unless DuckDB::Result.use_chunk_each?
|
29
|
+
|
30
|
+
PendingResult.new(self, true)
|
31
|
+
end
|
32
|
+
|
27
33
|
# binds all parameters with SQL prepared statement.
|
28
34
|
#
|
29
35
|
# require 'duckdb'
|
data/lib/duckdb/result.rb
CHANGED
@@ -58,9 +58,15 @@ module DuckDB
|
|
58
58
|
|
59
59
|
def each
|
60
60
|
if self.class.use_chunk_each?
|
61
|
-
|
61
|
+
if streaming?
|
62
|
+
return _chunk_stream unless block_given?
|
62
63
|
|
63
|
-
|
64
|
+
_chunk_stream { |row| yield row }
|
65
|
+
else
|
66
|
+
return chunk_each unless block_given?
|
67
|
+
|
68
|
+
chunk_each { |row| yield row }
|
69
|
+
end
|
64
70
|
else
|
65
71
|
warn('this `each` behavior will be deprecated in the future. set `DuckDB::Result.use_chunk_each = true` to use new `each` behavior.')
|
66
72
|
return to_enum { row_size } unless block_given?
|
data/lib/duckdb/version.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'duckdb'
|
2
|
+
|
3
|
+
DuckDB::Result.use_chunk_each = true
|
4
|
+
DuckDB::Database.open do |db|
|
5
|
+
db.connect do |con|
|
6
|
+
con.query('SET threads=1')
|
7
|
+
con.query('CREATE TABLE tbl as SELECT range a, mod(range, 10) b FROM range(10000)')
|
8
|
+
con.query('CREATE TABLE tbl2 as SELECT range a, mod(range, 10) b FROM range(10000)')
|
9
|
+
# con.query('SET ENABLE_PROGRESS_BAR=true')
|
10
|
+
# con.query('SET ENABLE_PROGRESS_BAR_PRINT=false')
|
11
|
+
pending_result = con.async_query('SELECT * FROM tbl where b = (SELECT min(b) FROM tbl2)')
|
12
|
+
|
13
|
+
# con.interrupt
|
14
|
+
while pending_result.state == :not_ready
|
15
|
+
pending_result.execute_task
|
16
|
+
print '.'
|
17
|
+
$stdout.flush
|
18
|
+
sleep 0.01
|
19
|
+
end
|
20
|
+
result = pending_result.execute_pending
|
21
|
+
puts
|
22
|
+
p result.each.first
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'duckdb'
|
2
|
+
|
3
|
+
DuckDB::Result.use_chunk_each = true
|
4
|
+
DuckDB::Database.open do |db|
|
5
|
+
db.connect do |con|
|
6
|
+
con.query('SET threads=1')
|
7
|
+
con.query('CREATE TABLE tbl as SELECT range a, mod(range, 10) b FROM range(10000)')
|
8
|
+
con.query('CREATE TABLE tbl2 as SELECT range a, mod(range, 10) b FROM range(10000)')
|
9
|
+
# con.query('SET ENABLE_PROGRESS_BAR=true')
|
10
|
+
# con.query('SET ENABLE_PROGRESS_BAR_PRINT=false')
|
11
|
+
pending_result = con.async_query_stream('SELECT * FROM tbl where b = (SELECT min(b) FROM tbl2)')
|
12
|
+
|
13
|
+
# con.interrupt
|
14
|
+
while pending_result.state == :not_ready
|
15
|
+
pending_result.execute_task
|
16
|
+
print '.'
|
17
|
+
$stdout.flush
|
18
|
+
sleep 0.01
|
19
|
+
end
|
20
|
+
result = pending_result.execute_pending
|
21
|
+
puts
|
22
|
+
p result.each.first
|
23
|
+
end
|
24
|
+
end
|
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.9.1
|
4
|
+
version: 0.9.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masaki Suketa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,6 +75,7 @@ extensions:
|
|
75
75
|
- ext/duckdb/extconf.rb
|
76
76
|
extra_rdoc_files: []
|
77
77
|
files:
|
78
|
+
- ".gitattributes"
|
78
79
|
- ".github/FUNDING.yml"
|
79
80
|
- ".github/workflows/test_on_macos.yml"
|
80
81
|
- ".github/workflows/test_on_ubuntu.yml"
|
@@ -88,6 +89,7 @@ files:
|
|
88
89
|
- LICENSE
|
89
90
|
- README.md
|
90
91
|
- Rakefile
|
92
|
+
- benchmark/async_query.rb
|
91
93
|
- benchmark/converter_hugeint_ips.rb
|
92
94
|
- benchmark/get_converter_module_ips.rb
|
93
95
|
- benchmark/to_bigdecimal_ips.rb
|
@@ -138,6 +140,8 @@ files:
|
|
138
140
|
- lib/duckdb/prepared_statement.rb
|
139
141
|
- lib/duckdb/result.rb
|
140
142
|
- lib/duckdb/version.rb
|
143
|
+
- sample/async_query.rb
|
144
|
+
- sample/async_query_stream.rb
|
141
145
|
homepage: https://github.com/suketa/ruby-duckdb
|
142
146
|
licenses:
|
143
147
|
- MIT
|