duckdb 0.9.1.1 → 0.9.2
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 +6 -6
- data/.github/workflows/test_on_ubuntu.yml +6 -6
- data/.github/workflows/test_on_windows.yml +4 -4
- data/CHANGELOG.md +11 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +5 -5
- data/README.md +17 -1
- data/benchmark/async_query.rb +90 -0
- data/ext/duckdb/appender.c +5 -5
- data/ext/duckdb/appender.h +1 -1
- data/ext/duckdb/blob.c +1 -1
- data/ext/duckdb/blob.h +1 -4
- data/ext/duckdb/column.c +2 -2
- data/ext/duckdb/column.h +2 -2
- data/ext/duckdb/config.c +1 -1
- data/ext/duckdb/config.h +1 -1
- data/ext/duckdb/connection.c +66 -6
- data/ext/duckdb/connection.h +2 -2
- data/ext/duckdb/converter.h +1 -1
- data/ext/duckdb/conveter.c +1 -1
- data/ext/duckdb/database.c +3 -3
- data/ext/duckdb/database.h +2 -2
- data/ext/duckdb/duckdb.c +11 -11
- data/ext/duckdb/error.c +1 -1
- data/ext/duckdb/error.h +1 -1
- data/ext/duckdb/extconf.rb +46 -13
- data/ext/duckdb/pending_result.c +45 -6
- data/ext/duckdb/pending_result.h +1 -1
- data/ext/duckdb/prepared_statement.c +7 -7
- data/ext/duckdb/prepared_statement.h +1 -1
- data/ext/duckdb/result.c +112 -70
- data/ext/duckdb/result.h +2 -2
- data/ext/duckdb/ruby-duckdb.h +1 -0
- data/ext/duckdb/util.c +4 -4
- data/ext/duckdb/util.h +4 -4
- data/lib/duckdb/appender.rb +1 -10
- data/lib/duckdb/connection.rb +50 -8
- data/lib/duckdb/converter.rb +27 -1
- data/lib/duckdb/prepared_statement.rb +42 -40
- 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: afbb8627bfcb9764d6928d64558b55c18b26932b1ad50946cfe777169b6986f9
|
4
|
+
data.tar.gz: b560803df1d4b93d1e1b9f5c56b55f779c34095780592b9cdae51f7d4da2c0ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c16acf784261f874501381aa9c764bc461d56fd35b066bae88c6cf0b4de654a867a6d309641cf0cf39d60854d268ce610fd3997534adcd11f322e7e4cd76401
|
7
|
+
data.tar.gz: 24d26d68b843c27ca306980e0d1acdfed2c6f24bb573cb89ba684879c4d05d43256d2335085e82fb1c352b7cdffcd016f2c2dadf3d924fc747cc4c450b142693
|
data/.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.rb diff=ruby
|
@@ -1,9 +1,9 @@
|
|
1
1
|
name: MacOS
|
2
2
|
|
3
3
|
on:
|
4
|
-
push:
|
5
|
-
|
6
|
-
|
4
|
+
# push:
|
5
|
+
# branches:
|
6
|
+
# - main
|
7
7
|
pull_request:
|
8
8
|
types:
|
9
9
|
- opened
|
@@ -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-preview3', '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
|
@@ -1,9 +1,9 @@
|
|
1
1
|
name: Ubuntu
|
2
2
|
|
3
3
|
on:
|
4
|
-
push:
|
5
|
-
|
6
|
-
|
4
|
+
# push:
|
5
|
+
# branches:
|
6
|
+
# - main
|
7
7
|
pull_request:
|
8
8
|
types:
|
9
9
|
- opened
|
@@ -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-preview3', 'head']
|
19
|
+
duckdb: ['0.9.2', '0.8.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v3
|
@@ -57,7 +57,7 @@ jobs:
|
|
57
57
|
env:
|
58
58
|
DUCKDB_VERSION: ${{ matrix.duckdb }}
|
59
59
|
run: |
|
60
|
-
rake test
|
60
|
+
env RUBYOPT=-W:deprecated rake test
|
61
61
|
|
62
62
|
post-test:
|
63
63
|
name: All tests passed on Ubuntu
|
@@ -1,9 +1,9 @@
|
|
1
1
|
name: Windows
|
2
2
|
|
3
3
|
on:
|
4
|
-
push:
|
5
|
-
|
6
|
-
|
4
|
+
# push:
|
5
|
+
# branches:
|
6
|
+
# - main
|
7
7
|
pull_request:
|
8
8
|
types:
|
9
9
|
- opened
|
@@ -16,7 +16,7 @@ jobs:
|
|
16
16
|
strategy:
|
17
17
|
matrix:
|
18
18
|
ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', 'ucrt', 'mingw', 'mswin', 'head']
|
19
|
-
duckdb: ['0.9.
|
19
|
+
duckdb: ['0.9.2', '0.8.1']
|
20
20
|
|
21
21
|
steps:
|
22
22
|
- uses: actions/checkout@v3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# ChangeLog
|
2
2
|
|
3
|
+
# 0.9.2
|
4
|
+
- add DuckDB::Connection#async_query_stream
|
5
|
+
- DuckDB::PendingResult accepts second argument. If the second argument is
|
6
|
+
true, PendingResult#execute_pending returns streaming DuckDB::Result object.
|
7
|
+
- add DuckDB::PreparedStatement#pending_prepared_stream
|
8
|
+
- add DuckDB::Result#streaming?.
|
9
|
+
|
10
|
+
# 0.9.1.2
|
11
|
+
- add DuckDB::Connection#interrupt, DuckDB::Connection#query_progress
|
12
|
+
- add DuckDB::Connection#async_query, alias method async_execute.
|
13
|
+
|
3
14
|
# 0.9.1.1
|
4
15
|
- change default branch to main from master.
|
5
16
|
- add DuckDB::PendingResult class.
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
duckdb (0.9.
|
4
|
+
duckdb (0.9.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -9,16 +9,16 @@ GEM
|
|
9
9
|
benchmark-ips (2.12.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
|
-
racc (1.7.
|
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.2.
|
21
|
+
ruby_memcheck (2.2.1)
|
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/appender.c
CHANGED
@@ -285,7 +285,7 @@ static VALUE appender__append_date(VALUE self, VALUE year, VALUE month, VALUE da
|
|
285
285
|
rubyDuckDBAppender *ctx;
|
286
286
|
|
287
287
|
TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
|
288
|
-
dt =
|
288
|
+
dt = rbduckdb_to_duckdb_date_from_value(year, month, day);
|
289
289
|
|
290
290
|
if (duckdb_append_date(ctx->appender, dt) == DuckDBError) {
|
291
291
|
rb_raise(eDuckDBError, "failed to append date");
|
@@ -298,7 +298,7 @@ static VALUE appender__append_interval(VALUE self, VALUE months, VALUE days, VAL
|
|
298
298
|
rubyDuckDBAppender *ctx;
|
299
299
|
|
300
300
|
TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
|
301
|
-
|
301
|
+
rbduckdb_to_duckdb_interval_from_value(&interval, months, days, micros);
|
302
302
|
|
303
303
|
if (duckdb_append_interval(ctx->appender, interval) == DuckDBError) {
|
304
304
|
rb_raise(eDuckDBError, "failed to append interval");
|
@@ -311,7 +311,7 @@ static VALUE appender__append_time(VALUE self, VALUE hour, VALUE min, VALUE sec,
|
|
311
311
|
rubyDuckDBAppender *ctx;
|
312
312
|
|
313
313
|
TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
|
314
|
-
time =
|
314
|
+
time = rbduckdb_to_duckdb_time_from_value(hour, min, sec, micros);
|
315
315
|
|
316
316
|
if (duckdb_append_time(ctx->appender, time) == DuckDBError) {
|
317
317
|
rb_raise(eDuckDBError, "failed to append time");
|
@@ -326,7 +326,7 @@ static VALUE appender__append_timestamp(VALUE self, VALUE year, VALUE month, VAL
|
|
326
326
|
|
327
327
|
TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
|
328
328
|
|
329
|
-
timestamp =
|
329
|
+
timestamp = rbduckdb_to_duckdb_timestamp_from_value(year, month, day, hour, min, sec, micros);
|
330
330
|
|
331
331
|
if (duckdb_append_timestamp(ctx->appender, timestamp) == DuckDBError) {
|
332
332
|
rb_raise(eDuckDBError, "failed to append timestamp");
|
@@ -369,7 +369,7 @@ static VALUE appender_close(VALUE self) {
|
|
369
369
|
return self;
|
370
370
|
}
|
371
371
|
|
372
|
-
void
|
372
|
+
void rbduckdb_init_duckdb_appender(void) {
|
373
373
|
cDuckDBAppender = rb_define_class_under(mDuckDB, "Appender", rb_cObject);
|
374
374
|
rb_define_alloc_func(cDuckDBAppender, allocate);
|
375
375
|
rb_define_method(cDuckDBAppender, "initialize", appender_initialize, 3);
|
data/ext/duckdb/appender.h
CHANGED
data/ext/duckdb/blob.c
CHANGED
data/ext/duckdb/blob.h
CHANGED
data/ext/duckdb/column.c
CHANGED
@@ -68,7 +68,7 @@ VALUE duckdb_column_get_name(VALUE oDuckDBColumn) {
|
|
68
68
|
return rb_utf8_str_new_cstr(duckdb_column_name(&(ctxresult->result), ctx->col));
|
69
69
|
}
|
70
70
|
|
71
|
-
VALUE
|
71
|
+
VALUE rbduckdb_create_column(VALUE oDuckDBResult, idx_t col) {
|
72
72
|
VALUE obj;
|
73
73
|
rubyDuckDBColumn *ctx;
|
74
74
|
|
@@ -81,7 +81,7 @@ VALUE create_column(VALUE oDuckDBResult, idx_t col) {
|
|
81
81
|
return obj;
|
82
82
|
}
|
83
83
|
|
84
|
-
void
|
84
|
+
void rbduckdb_init_duckdb_column(void) {
|
85
85
|
cDuckDBColumn = rb_define_class_under(mDuckDB, "Column", rb_cObject);
|
86
86
|
rb_define_alloc_func(cDuckDBColumn, allocate);
|
87
87
|
|
data/ext/duckdb/column.h
CHANGED
@@ -8,7 +8,7 @@ struct _rubyDuckDBColumn {
|
|
8
8
|
|
9
9
|
typedef struct _rubyDuckDBColumn rubyDuckDBColumn;
|
10
10
|
|
11
|
-
void
|
12
|
-
VALUE
|
11
|
+
void rbduckdb_init_duckdb_column(void);
|
12
|
+
VALUE rbduckdb_create_column(VALUE oDuckDBResult, idx_t col);
|
13
13
|
|
14
14
|
#endif
|
data/ext/duckdb/config.c
CHANGED
@@ -79,7 +79,7 @@ static VALUE config_set_config(VALUE self, VALUE key, VALUE value) {
|
|
79
79
|
return self;
|
80
80
|
}
|
81
81
|
|
82
|
-
void
|
82
|
+
void rbduckdb_init_duckdb_config(void) {
|
83
83
|
cDuckDBConfig = rb_define_class_under(mDuckDB, "Config", rb_cObject);
|
84
84
|
rb_define_alloc_func(cDuckDBConfig, allocate);
|
85
85
|
rb_define_singleton_method(cDuckDBConfig, "size", config_s_size, 0);
|
data/ext/duckdb/config.h
CHANGED
data/ext/duckdb/connection.c
CHANGED
@@ -6,6 +6,12 @@ static void deallocate(void *ctx);
|
|
6
6
|
static VALUE allocate(VALUE klass);
|
7
7
|
static size_t memsize(const void *p);
|
8
8
|
static VALUE duckdb_connection_disconnect(VALUE self);
|
9
|
+
|
10
|
+
#ifdef HAVE_DUCKDB_H_GE_V090
|
11
|
+
static VALUE duckdb_connection_interrupt(VALUE self);
|
12
|
+
static VALUE duckdb_connection_query_progress(VALUE self);
|
13
|
+
#endif
|
14
|
+
|
9
15
|
static VALUE duckdb_connection_connect(VALUE self, VALUE oDuckDBDatabase);
|
10
16
|
static VALUE duckdb_connection_query_sql(VALUE self, VALUE str);
|
11
17
|
|
@@ -37,12 +43,12 @@ rubyDuckDBConnection *get_struct_connection(VALUE obj) {
|
|
37
43
|
return ctx;
|
38
44
|
}
|
39
45
|
|
40
|
-
VALUE
|
46
|
+
VALUE rbduckdb_create_connection(VALUE oDuckDBDatabase) {
|
41
47
|
rubyDuckDB *ctxdb;
|
42
48
|
rubyDuckDBConnection *ctxcon;
|
43
49
|
VALUE obj;
|
44
50
|
|
45
|
-
ctxdb =
|
51
|
+
ctxdb = rbduckdb_get_struct_database(oDuckDBDatabase);
|
46
52
|
|
47
53
|
obj = allocate(cDuckDBConnection);
|
48
54
|
TypedData_Get_Struct(obj, rubyDuckDBConnection, &connection_data_type, ctxcon);
|
@@ -51,7 +57,6 @@ VALUE create_connection(VALUE oDuckDBDatabase) {
|
|
51
57
|
rb_raise(eDuckDBError, "connection error");
|
52
58
|
}
|
53
59
|
|
54
|
-
// rb_ivar_set(obj, rb_intern("database"), oDuckDBDatabase);
|
55
60
|
return obj;
|
56
61
|
}
|
57
62
|
|
@@ -64,6 +69,57 @@ static VALUE duckdb_connection_disconnect(VALUE self) {
|
|
64
69
|
return self;
|
65
70
|
}
|
66
71
|
|
72
|
+
#ifdef HAVE_DUCKDB_H_GE_V090
|
73
|
+
/*
|
74
|
+
* call-seq:
|
75
|
+
* connection.interrupt -> nil
|
76
|
+
*
|
77
|
+
* Interrupts the currently running query.
|
78
|
+
*
|
79
|
+
* db = DuckDB::Database.open
|
80
|
+
* conn = db.connect
|
81
|
+
* con.query('SET ENABLE_PROGRESS_BAR=true')
|
82
|
+
* con.query('SET ENABLE_PROGRESS_BAR_PRINT=false')
|
83
|
+
* pending_result = con.async_query('slow query')
|
84
|
+
*
|
85
|
+
* pending_result.execute_task
|
86
|
+
* con.interrupt # => nil
|
87
|
+
*/
|
88
|
+
static VALUE duckdb_connection_interrupt(VALUE self) {
|
89
|
+
rubyDuckDBConnection *ctx;
|
90
|
+
|
91
|
+
TypedData_Get_Struct(self, rubyDuckDBConnection, &connection_data_type, ctx);
|
92
|
+
duckdb_interrupt(ctx->con);
|
93
|
+
|
94
|
+
return Qnil;
|
95
|
+
}
|
96
|
+
|
97
|
+
/*
|
98
|
+
* Returns the progress of the currently running query.
|
99
|
+
*
|
100
|
+
* require 'duckdb'
|
101
|
+
*
|
102
|
+
* db = DuckDB::Database.open
|
103
|
+
* conn = db.connect
|
104
|
+
* con.query('SET ENABLE_PROGRESS_BAR=true')
|
105
|
+
* con.query('SET ENABLE_PROGRESS_BAR_PRINT=false')
|
106
|
+
* con.query_progress # => -1.0
|
107
|
+
* pending_result = con.async_query('slow query')
|
108
|
+
* con.query_progress # => 0.0
|
109
|
+
* pending_result.execute_task
|
110
|
+
* con.query_progress # => Float
|
111
|
+
*/
|
112
|
+
static VALUE duckdb_connection_query_progress(VALUE self) {
|
113
|
+
rubyDuckDBConnection *ctx;
|
114
|
+
double progress;
|
115
|
+
|
116
|
+
TypedData_Get_Struct(self, rubyDuckDBConnection, &connection_data_type, ctx);
|
117
|
+
progress = duckdb_query_progress(ctx->con);
|
118
|
+
|
119
|
+
return DBL2NUM(progress);
|
120
|
+
}
|
121
|
+
#endif
|
122
|
+
|
67
123
|
static VALUE duckdb_connection_connect(VALUE self, VALUE oDuckDBDatabase) {
|
68
124
|
rubyDuckDBConnection *ctx;
|
69
125
|
rubyDuckDB *ctxdb;
|
@@ -71,7 +127,7 @@ static VALUE duckdb_connection_connect(VALUE self, VALUE oDuckDBDatabase) {
|
|
71
127
|
if (!rb_obj_is_kind_of(oDuckDBDatabase, cDuckDBDatabase)) {
|
72
128
|
rb_raise(rb_eTypeError, "The first argument must be DuckDB::Database object.");
|
73
129
|
}
|
74
|
-
ctxdb =
|
130
|
+
ctxdb = rbduckdb_get_struct_database(oDuckDBDatabase);
|
75
131
|
TypedData_Get_Struct(self, rubyDuckDBConnection, &connection_data_type, ctx);
|
76
132
|
|
77
133
|
if (duckdb_connect(ctxdb->db, &(ctx->con)) == DuckDBError) {
|
@@ -85,7 +141,7 @@ static VALUE duckdb_connection_query_sql(VALUE self, VALUE str) {
|
|
85
141
|
rubyDuckDBConnection *ctx;
|
86
142
|
rubyDuckDBResult *ctxr;
|
87
143
|
|
88
|
-
VALUE result =
|
144
|
+
VALUE result = rbduckdb_create_result();
|
89
145
|
|
90
146
|
TypedData_Get_Struct(self, rubyDuckDBConnection, &connection_data_type, ctx);
|
91
147
|
ctxr = get_struct_result(result);
|
@@ -100,11 +156,15 @@ static VALUE duckdb_connection_query_sql(VALUE self, VALUE str) {
|
|
100
156
|
return result;
|
101
157
|
}
|
102
158
|
|
103
|
-
void
|
159
|
+
void rbduckdb_init_duckdb_connection(void) {
|
104
160
|
cDuckDBConnection = rb_define_class_under(mDuckDB, "Connection", rb_cObject);
|
105
161
|
rb_define_alloc_func(cDuckDBConnection, allocate);
|
106
162
|
|
107
163
|
rb_define_method(cDuckDBConnection, "disconnect", duckdb_connection_disconnect, 0);
|
164
|
+
#ifdef HAVE_DUCKDB_H_GE_V090
|
165
|
+
rb_define_method(cDuckDBConnection, "interrupt", duckdb_connection_interrupt, 0);
|
166
|
+
rb_define_method(cDuckDBConnection, "query_progress", duckdb_connection_query_progress, 0);
|
167
|
+
#endif
|
108
168
|
rb_define_private_method(cDuckDBConnection, "_connect", duckdb_connection_connect, 1);
|
109
169
|
rb_define_private_method(cDuckDBConnection, "query_sql", duckdb_connection_query_sql, 1);
|
110
170
|
}
|
data/ext/duckdb/connection.h
CHANGED
@@ -8,7 +8,7 @@ struct _rubyDuckDBConnection {
|
|
8
8
|
typedef struct _rubyDuckDBConnection rubyDuckDBConnection;
|
9
9
|
|
10
10
|
rubyDuckDBConnection *get_struct_connection(VALUE obj);
|
11
|
-
void
|
12
|
-
VALUE
|
11
|
+
void rbduckdb_init_duckdb_connection(void);
|
12
|
+
VALUE rbduckdb_create_connection(VALUE oDuckDBDatabase);
|
13
13
|
|
14
14
|
#endif
|
data/ext/duckdb/converter.h
CHANGED
data/ext/duckdb/conveter.c
CHANGED
data/ext/duckdb/database.c
CHANGED
@@ -37,7 +37,7 @@ static VALUE allocate(VALUE klass) {
|
|
37
37
|
return TypedData_Wrap_Struct(klass, &database_data_type, ctx);
|
38
38
|
}
|
39
39
|
|
40
|
-
rubyDuckDB *
|
40
|
+
rubyDuckDB *rbduckdb_get_struct_database(VALUE obj) {
|
41
41
|
rubyDuckDB *ctx;
|
42
42
|
TypedData_Get_Struct(obj, rubyDuckDB, &database_data_type, ctx);
|
43
43
|
return ctx;
|
@@ -99,7 +99,7 @@ static VALUE duckdb_database_s_open_ext(int argc, VALUE *argv, VALUE cDuckDBData
|
|
99
99
|
}
|
100
100
|
|
101
101
|
static VALUE duckdb_database_connect(VALUE self) {
|
102
|
-
return
|
102
|
+
return rbduckdb_create_connection(self);
|
103
103
|
}
|
104
104
|
|
105
105
|
/*
|
@@ -115,7 +115,7 @@ static VALUE duckdb_database_close(VALUE self) {
|
|
115
115
|
return self;
|
116
116
|
}
|
117
117
|
|
118
|
-
void
|
118
|
+
void rbduckdb_init_duckdb_database(void) {
|
119
119
|
cDuckDBDatabase = rb_define_class_under(mDuckDB, "Database", rb_cObject);
|
120
120
|
rb_define_alloc_func(cDuckDBDatabase, allocate);
|
121
121
|
rb_define_singleton_method(cDuckDBDatabase, "_open", duckdb_database_s_open, -1);
|
data/ext/duckdb/database.h
CHANGED
data/ext/duckdb/duckdb.c
CHANGED
@@ -22,15 +22,15 @@ Init_duckdb_native(void) {
|
|
22
22
|
|
23
23
|
rb_define_singleton_method(mDuckDB, "library_version", duckdb_s_library_version, 0);
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
rbduckdb_init_duckdb_error();
|
26
|
+
rbduckdb_init_duckdb_database();
|
27
|
+
rbduckdb_init_duckdb_connection();
|
28
|
+
rbduckdb_init_duckdb_result();
|
29
|
+
rbduckdb_init_duckdb_column();
|
30
|
+
rbduckdb_init_duckdb_prepared_statement();
|
31
|
+
rbduckdb_init_duckdb_pending_result();
|
32
|
+
rbduckdb_init_duckdb_blob();
|
33
|
+
rbduckdb_init_duckdb_appender();
|
34
|
+
rbduckdb_init_duckdb_config();
|
35
|
+
rbduckdb_init_duckdb_converter();
|
36
36
|
}
|
data/ext/duckdb/error.c
CHANGED