duckdb 0.9.2.3 → 0.10.1.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 +2 -2
- data/.github/workflows/test_on_ubuntu.yml +2 -2
- data/.github/workflows/test_on_windows.yml +2 -2
- data/CHANGELOG.md +29 -10
- data/Dockerfile +1 -1
- data/Gemfile.lock +7 -7
- data/README.md +35 -22
- data/benchmark/to_intern_ips.rb +73 -0
- data/ext/duckdb/connection.c +8 -0
- data/ext/duckdb/extconf.rb +5 -5
- data/ext/duckdb/result.c +42 -14
- data/ext/duckdb/ruby-duckdb.h +4 -0
- data/lib/duckdb/column.rb +3 -0
- data/lib/duckdb/converter.rb +14 -3
- data/lib/duckdb/result.rb +26 -13
- data/lib/duckdb/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b2100acff5462ba1ae39b45795b53969911ff7e567007875098cebc536b6b3a1
|
|
4
|
+
data.tar.gz: c99f55d6e6b9d535f75ed6759daaddb0ef39dc49ee1861cc1a1b7c18a914ea6d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 112837a9b6df91ff4db6ebd489c1ad04fbacac7eea0d778d3c82ecc21ef1c0772cbca42123a99f39a170585fbbaf0cba5f904809cac2dd71a8e7fe2b474fe71b
|
|
7
|
+
data.tar.gz: b6b2b47cff49a552e51d53988f03f73dd2163ec06877114a019bbaf155c2519417465e3fe208a15cdaf4953df6749661786f2ca627fb42488fbae7f466b77e97
|
|
@@ -15,8 +15,8 @@ jobs:
|
|
|
15
15
|
runs-on: macos-latest
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
ruby: ['3.0.6', '3.1.4', '3.2.
|
|
19
|
-
duckdb: ['0.9.2', '0.
|
|
18
|
+
ruby: ['3.0.6', '3.1.4', '3.2.3', '3.3.0', 'head']
|
|
19
|
+
duckdb: ['0.9.2', '0.10.0', '0.10.1']
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
22
|
- uses: actions/checkout@v3
|
|
@@ -15,8 +15,8 @@ jobs:
|
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
ruby: ['3.0.6', '3.1.4', '3.2.
|
|
19
|
-
duckdb: ['0.9.2', '0.
|
|
18
|
+
ruby: ['3.0.6', '3.1.4', '3.2.3', '3.3.0', 'head']
|
|
19
|
+
duckdb: ['0.9.2', '0.10.0', '0.10.1']
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
22
|
- uses: actions/checkout@v3
|
|
@@ -15,8 +15,8 @@ jobs:
|
|
|
15
15
|
runs-on: windows-latest
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
ruby: ['3.0.6', '3.1.4', '3.2.2', 'ucrt', 'mingw', 'mswin', 'head']
|
|
19
|
-
duckdb: ['0.9.2', '0.
|
|
18
|
+
ruby: ['3.0.6', '3.1.4', '3.2.2', '3.3.0', 'ucrt', 'mingw', 'mswin', 'head']
|
|
19
|
+
duckdb: ['0.9.2', '0.10.0', '0.10.1']
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
22
|
- uses: actions/checkout@v3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,30 +1,49 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
# 0.10.1.0 - 2024-03-22
|
|
8
|
+
- drop duckdb v0.8.x.
|
|
9
|
+
- fix column type failures with duckdb v0.10.1.
|
|
10
|
+
|
|
11
|
+
# 0.10.0.0 - 2024-02-18
|
|
12
|
+
- bump to duckdb v0.10.0.
|
|
13
|
+
- fix building error with duckdb v0.10.0.
|
|
14
|
+
- bundle update to bump nokogiri from 1.16.0 to 1.16.2.
|
|
15
|
+
- fix Decimal type conversion.
|
|
16
|
+
|
|
17
|
+
## Breaking changes
|
|
18
|
+
|
|
19
|
+
- `DuckDB::Connection#query_progress` returns `DuckDB::QueryProgress` object only when duckdb library version is 0.10.0 or later.
|
|
20
|
+
- The available methods are `DuckDB::QueryProgress#percentage`, `DuckDB::QueryProgress#rows_processed`, `DuckDB::QueryProgress#total_rows_to_process`.
|
|
21
|
+
|
|
22
|
+
# 0.9.2.3 - 2023-12-29
|
|
4
23
|
- fix bigdecimal warning with Ruby 3.3.0.
|
|
5
24
|
|
|
6
|
-
# 0.9.2.2
|
|
25
|
+
# 0.9.2.2 - 2023-12-26
|
|
7
26
|
- bump Ruby to 3.3.0 on CI.
|
|
8
27
|
|
|
9
28
|
## Breaking changes
|
|
10
29
|
- drop Ruby 2.7.
|
|
11
30
|
|
|
12
|
-
# 0.9.2.1
|
|
31
|
+
# 0.9.2.1 - 2023-12-24
|
|
13
32
|
- support Time column in `DuckDB#Result#chunk_each`.
|
|
14
33
|
- add `DuckDB::Interval#eql?`.
|
|
15
34
|
|
|
16
|
-
# 0.9.2
|
|
35
|
+
# 0.9.2 - 2023-11-26
|
|
17
36
|
- add `DuckDB::Connection#async_query_stream`.
|
|
18
37
|
- `DuckDB::PendingResult` accepts second argument. If the second argument is
|
|
19
38
|
true, `PendingResult#execute_pending` returns streaming `DuckDB::Result` object.
|
|
20
39
|
- add `DuckDB::PreparedStatement#pending_prepared_stream`
|
|
21
40
|
- add `DuckDB::Result#streaming?`.
|
|
22
41
|
|
|
23
|
-
# 0.9.1.2
|
|
42
|
+
# 0.9.1.2 - 2023-11-05
|
|
24
43
|
- add `DuckDB::Connection#interrupt`, `DuckDB::Connection#query_progress`.
|
|
25
44
|
- add `DuckDB::Connection#async_query`, alias method `async_execute`.
|
|
26
45
|
|
|
27
|
-
# 0.9.1.1
|
|
46
|
+
# 0.9.1.1 - 2023-10-29
|
|
28
47
|
- change default branch to main from master.
|
|
29
48
|
- add `DuckDB::PendingResult` class.
|
|
30
49
|
- add `DuckDB::PendingResult#state`.
|
|
@@ -35,15 +54,15 @@
|
|
|
35
54
|
## Breaking Changes
|
|
36
55
|
- drop duckdb v0.7.x.
|
|
37
56
|
|
|
38
|
-
# 0.9.1
|
|
57
|
+
# 0.9.1 - 2023-10-14
|
|
39
58
|
- add `DuckDB::PreparedStatement#parameter_name`.
|
|
40
59
|
- bump duckdb to 0.9.1.
|
|
41
60
|
|
|
42
|
-
# 0.9.0.1
|
|
61
|
+
# 0.9.0.1 - 2023-10-08
|
|
43
62
|
- add `DuckDB::PreparedStatement#bind_parameter_index`.
|
|
44
63
|
- `DuckDB::Connection#query` accepts SQL with named bind parameters.
|
|
45
64
|
|
|
46
|
-
# 0.9.0
|
|
65
|
+
# 0.9.0 - 2023-09-30
|
|
47
66
|
- bump duckdb to 0.9.0.
|
|
48
67
|
|
|
49
68
|
## Breaking Changes
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
duckdb (0.
|
|
4
|
+
duckdb (0.10.1.0)
|
|
5
5
|
bigdecimal (>= 3.1.4)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
10
|
benchmark-ips (2.13.0)
|
|
11
|
-
bigdecimal (3.1.
|
|
11
|
+
bigdecimal (3.1.7)
|
|
12
12
|
mini_portile2 (2.8.5)
|
|
13
|
-
minitest (5.
|
|
14
|
-
nokogiri (1.16.
|
|
13
|
+
minitest (5.22.3)
|
|
14
|
+
nokogiri (1.16.3)
|
|
15
15
|
mini_portile2 (~> 2.8.2)
|
|
16
16
|
racc (~> 1.4)
|
|
17
|
-
nokogiri (1.16.
|
|
17
|
+
nokogiri (1.16.3-x86_64-linux)
|
|
18
18
|
racc (~> 1.4)
|
|
19
19
|
racc (1.7.3)
|
|
20
20
|
rake (13.1.0)
|
|
21
|
-
rake-compiler (1.2.
|
|
21
|
+
rake-compiler (1.2.7)
|
|
22
22
|
rake
|
|
23
23
|
ruby_memcheck (2.3.0)
|
|
24
24
|
nokogiri
|
|
25
|
-
stackprof (0.2.
|
|
25
|
+
stackprof (0.2.26)
|
|
26
26
|
|
|
27
27
|
PLATFORMS
|
|
28
28
|
ruby
|
data/README.md
CHANGED
|
@@ -7,32 +7,34 @@
|
|
|
7
7
|
|
|
8
8
|
## Description
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This gem `duckdb` is Ruby client for the [DuckDB](https://www.duckdb.org) database engine.
|
|
11
11
|
|
|
12
12
|
## Requirement
|
|
13
13
|
|
|
14
|
-
You must have [DuckDB](
|
|
14
|
+
You must have [DuckDB](https://www.duckdb.org) engine installed in order to use this gem.
|
|
15
15
|
|
|
16
16
|
## Pre-requisite setup (Linux):
|
|
17
|
-
1. Head over to the [DuckDB](https://duckdb.org/) webpage
|
|
17
|
+
1. Head over to the [DuckDB](https://duckdb.org/) webpage.
|
|
18
18
|
|
|
19
|
-
2. Download the latest C++ package release for DuckDB
|
|
19
|
+
2. Download the latest C++ package release for DuckDB.
|
|
20
20
|
|
|
21
21
|
3. Move the files to their respective location:
|
|
22
|
-
- Extract the `duckdb.h` and `duckdb.hpp` file to `/usr/local/include
|
|
23
|
-
- Extract the `libduckdb.so` file to `/usr/local/lib
|
|
22
|
+
- Extract the `duckdb.h` and `duckdb.hpp` file to `/usr/local/include`.
|
|
23
|
+
- Extract the `libduckdb.so` file to `/usr/local/lib`.
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
26
|
unzip libduckdb-linux-amd64.zip -d libduckdb
|
|
27
27
|
sudo mv libduckdb/duckdb.* /usr/local/include/
|
|
28
28
|
sudo mv libduckdb/libduckdb.so /usr/local/lib
|
|
29
29
|
```
|
|
30
|
+
|
|
30
31
|
4. To create the necessary link, run `ldconfig` as root:
|
|
31
32
|
|
|
32
33
|
```sh
|
|
33
34
|
sudo ldconfig /usr/local/lib # adding a --verbose flag is optional - but this will let you know if the libduckdb.so library has been linked
|
|
34
35
|
```
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
## Pre-requisite setup (macOS):
|
|
36
38
|
|
|
37
39
|
Using `brew install` is recommended.
|
|
38
40
|
|
|
@@ -40,14 +42,22 @@ Using `brew install` is recommended.
|
|
|
40
42
|
brew install duckdb
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
##
|
|
45
|
+
## Pre-requisite setup (Windows):
|
|
46
|
+
|
|
47
|
+
Using [Ruby + Devkit](https://rubyinstaller.org/downloads/) is recommended.
|
|
48
|
+
|
|
49
|
+
1. Download libduckdb-windows-amd64.zip from [DuckDB](https://github.com/duckdb/duckdb/releases) and extranct it.
|
|
50
|
+
2. Copy `duckdb.dll` into `C:\Windows\System32`
|
|
51
|
+
|
|
52
|
+
## How to install
|
|
44
53
|
|
|
45
54
|
```sh
|
|
46
55
|
gem install duckdb
|
|
47
56
|
```
|
|
48
|
-
> this will work fine with the above pre-requisite setup.
|
|
49
57
|
|
|
50
|
-
|
|
58
|
+
After you've run the above pre-requisite setup, this should work fine.
|
|
59
|
+
|
|
60
|
+
If it doesn't, you may have to specify the location of the C header and library files:
|
|
51
61
|
|
|
52
62
|
```sh
|
|
53
63
|
gem install duckdb -- --with-duckdb-include=/duckdb_header_directory --with-duckdb-lib=/duckdb_library_directory
|
|
@@ -69,7 +79,7 @@ con.query("INSERT into users VALUES(3, 'Cathy')")
|
|
|
69
79
|
|
|
70
80
|
result = con.query('SELECT * from users')
|
|
71
81
|
result.each do |row|
|
|
72
|
-
|
|
82
|
+
puts row
|
|
73
83
|
end
|
|
74
84
|
```
|
|
75
85
|
|
|
@@ -88,13 +98,13 @@ DuckDB::Database.open do |db|
|
|
|
88
98
|
|
|
89
99
|
result = con.query('SELECT * from users')
|
|
90
100
|
result.each do |row|
|
|
91
|
-
|
|
101
|
+
puts row
|
|
92
102
|
end
|
|
93
103
|
end
|
|
94
104
|
end
|
|
95
105
|
```
|
|
96
106
|
|
|
97
|
-
###
|
|
107
|
+
### Using bind variables
|
|
98
108
|
|
|
99
109
|
You can use bind variables.
|
|
100
110
|
|
|
@@ -104,12 +114,12 @@ con.query('SELECT * FROM users WHERE name = ? AND email = ?', 'Alice', 'alice@ex
|
|
|
104
114
|
con.query('SELECT * FROM users WHERE name = $name AND email = $email', name: 'Alice', email: 'alice@example.com')
|
|
105
115
|
```
|
|
106
116
|
|
|
107
|
-
###
|
|
117
|
+
### Using async query
|
|
108
118
|
|
|
109
119
|
You can use async query.
|
|
110
120
|
|
|
111
121
|
```ruby
|
|
112
|
-
DuckDB::Result.use_chunk_each = true
|
|
122
|
+
DuckDB::Result.use_chunk_each = true
|
|
113
123
|
...
|
|
114
124
|
|
|
115
125
|
pending_result = con.async_query_stream('SLOW QUERY')
|
|
@@ -121,9 +131,9 @@ result.each.first
|
|
|
121
131
|
|
|
122
132
|
Here is [the benchmark](./benchmark/async_query.rb).
|
|
123
133
|
|
|
124
|
-
###
|
|
134
|
+
### Using BLOB column
|
|
125
135
|
|
|
126
|
-
Use `DuckDB::Blob.new` or use
|
|
136
|
+
Use `DuckDB::Blob.new` or use string#force_encoding(Encoding::BINARY)
|
|
127
137
|
|
|
128
138
|
```ruby
|
|
129
139
|
require 'duckdb'
|
|
@@ -134,12 +144,12 @@ DuckDB::Database.open do |db|
|
|
|
134
144
|
stmt = DuckDB::PreparedStatement.new(con, 'INSERT INTO blob_table VALUES ($1)')
|
|
135
145
|
|
|
136
146
|
stmt.bind(1, DuckDB::Blob.new("\0\1\2\3\4\5"))
|
|
137
|
-
#
|
|
147
|
+
# or
|
|
138
148
|
# stmt.bind(1, "\0\1\2\3\4\5".force_encoding(Encoding::BINARY))
|
|
139
149
|
stmt.execute
|
|
140
150
|
|
|
141
151
|
result = con.query('SELECT binary_data FROM blob_table')
|
|
142
|
-
|
|
152
|
+
puts result.first.first
|
|
143
153
|
end
|
|
144
154
|
end
|
|
145
155
|
```
|
|
@@ -212,14 +222,17 @@ Config class provides Ruby interface of [DuckDB configuration](https://duckdb.or
|
|
|
212
222
|
|
|
213
223
|
```ruby
|
|
214
224
|
require 'duckdb'
|
|
225
|
+
|
|
215
226
|
config = DuckDB::Config.new
|
|
216
227
|
config['default_order'] = 'DESC'
|
|
228
|
+
|
|
217
229
|
db = DuckDB::Database.open(nil, config)
|
|
230
|
+
|
|
218
231
|
con = db.connect
|
|
219
232
|
con.query('CREATE TABLE numbers (number INTEGER)')
|
|
220
233
|
con.query('INSERT INTO numbers VALUES (2), (1), (4), (3)')
|
|
221
234
|
|
|
222
|
-
# number is ordered by descending
|
|
223
|
-
|
|
224
|
-
|
|
235
|
+
# number is ordered by descending
|
|
236
|
+
res = con.query('SELECT number FROM numbers ORDER BY number')
|
|
237
|
+
res.first.first # => 4
|
|
225
238
|
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'duckdb'
|
|
5
|
+
require 'benchmark/ips'
|
|
6
|
+
|
|
7
|
+
DuckDB::Result.use_chunk_each = true
|
|
8
|
+
db = DuckDB::Database.open
|
|
9
|
+
con = db.connect
|
|
10
|
+
con.query(<<~SQL
|
|
11
|
+
CREATE TABLE t (
|
|
12
|
+
date_value DATE,
|
|
13
|
+
time_value TIME,
|
|
14
|
+
timestamp_value TIMESTAMP,
|
|
15
|
+
interval_value INTERVAL,
|
|
16
|
+
hugeint_value HUGEINT,
|
|
17
|
+
uuid_value UUID,
|
|
18
|
+
decimal_value DECIMAL(4, 2)
|
|
19
|
+
)
|
|
20
|
+
SQL
|
|
21
|
+
)
|
|
22
|
+
con.query(<<~SQL
|
|
23
|
+
INSERT INTO t VALUES
|
|
24
|
+
(
|
|
25
|
+
'2019-01-01',
|
|
26
|
+
'12:00:00',
|
|
27
|
+
'2019-01-01 12:00:00',
|
|
28
|
+
'1 day',
|
|
29
|
+
12345678901234567890,
|
|
30
|
+
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
|
|
31
|
+
0.12
|
|
32
|
+
),
|
|
33
|
+
(
|
|
34
|
+
'2019-01-01',
|
|
35
|
+
'12:00:00',
|
|
36
|
+
'2019-01-01 12:00:00',
|
|
37
|
+
'1 day',
|
|
38
|
+
12345678901234567890,
|
|
39
|
+
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
|
|
40
|
+
0.12
|
|
41
|
+
),
|
|
42
|
+
(
|
|
43
|
+
'2019-01-01',
|
|
44
|
+
'12:00:00',
|
|
45
|
+
'2019-01-01 12:00:00',
|
|
46
|
+
'1 day',
|
|
47
|
+
12345678901234567890,
|
|
48
|
+
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
|
|
49
|
+
2.12
|
|
50
|
+
)
|
|
51
|
+
SQL
|
|
52
|
+
)
|
|
53
|
+
result = con.query('SELECT * FROM t')
|
|
54
|
+
|
|
55
|
+
Benchmark.ips do |x|
|
|
56
|
+
x.report('_to_date') { result.each.to_a }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
__END__
|
|
60
|
+
```
|
|
61
|
+
## before
|
|
62
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
|
|
63
|
+
Warming up --------------------------------------
|
|
64
|
+
_to_date 30.790k i/100ms
|
|
65
|
+
Calculating -------------------------------------
|
|
66
|
+
_to_date 365.254k (± 0.2%) i/s - 1.847M in 5.057875s
|
|
67
|
+
|
|
68
|
+
## after
|
|
69
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
|
|
70
|
+
Warming up --------------------------------------
|
|
71
|
+
_to_date 36.047k i/100ms
|
|
72
|
+
Calculating -------------------------------------
|
|
73
|
+
_to_date 383.760k (± 3.3%) i/s - 1.947M in 5.077849s
|
data/ext/duckdb/connection.c
CHANGED
|
@@ -111,12 +111,20 @@ static VALUE duckdb_connection_interrupt(VALUE self) {
|
|
|
111
111
|
*/
|
|
112
112
|
static VALUE duckdb_connection_query_progress(VALUE self) {
|
|
113
113
|
rubyDuckDBConnection *ctx;
|
|
114
|
+
#ifdef HAVE_DUCKDB_H_GE_V0_10_0
|
|
115
|
+
duckdb_query_progress_type progress;
|
|
116
|
+
#else
|
|
114
117
|
double progress;
|
|
118
|
+
#endif
|
|
115
119
|
|
|
116
120
|
TypedData_Get_Struct(self, rubyDuckDBConnection, &connection_data_type, ctx);
|
|
117
121
|
progress = duckdb_query_progress(ctx->con);
|
|
118
122
|
|
|
123
|
+
#ifdef HAVE_DUCKDB_H_GE_V0_10_0
|
|
124
|
+
return rb_funcall(mDuckDBConverter, rb_intern("_to_query_progress"), 3, DBL2NUM(progress.percentage), ULL2NUM(progress.rows_processed), ULL2NUM(progress.total_rows_to_process));
|
|
125
|
+
#else
|
|
119
126
|
return DBL2NUM(progress);
|
|
127
|
+
#endif
|
|
120
128
|
}
|
|
121
129
|
#endif
|
|
122
130
|
|
data/ext/duckdb/extconf.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'mkmf'
|
|
4
4
|
|
|
5
|
-
DUCKDB_REQUIRED_VERSION = '0.
|
|
5
|
+
DUCKDB_REQUIRED_VERSION = '0.9.0'
|
|
6
6
|
|
|
7
7
|
def check_duckdb_header(header, version)
|
|
8
8
|
found = find_header(
|
|
@@ -52,11 +52,11 @@ dir_config('duckdb')
|
|
|
52
52
|
|
|
53
53
|
check_duckdb_header('duckdb.h', DUCKDB_REQUIRED_VERSION)
|
|
54
54
|
|
|
55
|
-
# check duckdb >= 0.8.0
|
|
56
|
-
check_duckdb_library('duckdb', 'duckdb_string_is_inlined', DUCKDB_REQUIRED_VERSION)
|
|
57
|
-
|
|
58
55
|
# check duckdb >= 0.9.0
|
|
59
|
-
|
|
56
|
+
check_duckdb_library('duckdb', 'duckdb_bind_parameter_index', DUCKDB_REQUIRED_VERSION)
|
|
57
|
+
|
|
58
|
+
# check duckdb >= 0.10.0
|
|
59
|
+
have_func('duckdb_appender_column_count', 'duckdb.h')
|
|
60
60
|
|
|
61
61
|
# duckdb_parameter_name is not found on Windows.
|
|
62
62
|
have_func('duckdb_parameter_name', 'duckdb.h')
|
data/ext/duckdb/result.c
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
#include "ruby-duckdb.h"
|
|
2
2
|
|
|
3
3
|
static VALUE cDuckDBResult;
|
|
4
|
+
static ID id__to_date;
|
|
5
|
+
static ID id__to_time;
|
|
6
|
+
static ID id__to_time_from_duckdb_time;
|
|
7
|
+
static ID id__to_interval_from_vector;
|
|
8
|
+
static ID id__to_hugeint_from_vector;
|
|
9
|
+
static ID id__to_decimal_from_hugeint;
|
|
10
|
+
static ID id__to_uuid_from_vector;
|
|
4
11
|
|
|
5
12
|
static void deallocate(void *ctx);
|
|
6
13
|
static VALUE allocate(VALUE klass);
|
|
@@ -482,7 +489,7 @@ VALUE rbduckdb_create_result(void) {
|
|
|
482
489
|
static VALUE vector_date(void *vector_data, idx_t row_idx) {
|
|
483
490
|
duckdb_date_struct date = duckdb_from_date(((duckdb_date *) vector_data)[row_idx]);
|
|
484
491
|
|
|
485
|
-
return rb_funcall(mDuckDBConverter,
|
|
492
|
+
return rb_funcall(mDuckDBConverter, id__to_date, 3,
|
|
486
493
|
INT2FIX(date.year),
|
|
487
494
|
INT2FIX(date.month),
|
|
488
495
|
INT2FIX(date.day)
|
|
@@ -491,7 +498,7 @@ static VALUE vector_date(void *vector_data, idx_t row_idx) {
|
|
|
491
498
|
|
|
492
499
|
static VALUE vector_timestamp(void* vector_data, idx_t row_idx) {
|
|
493
500
|
duckdb_timestamp_struct data = duckdb_from_timestamp(((duckdb_timestamp *)vector_data)[row_idx]);
|
|
494
|
-
return rb_funcall(mDuckDBConverter,
|
|
501
|
+
return rb_funcall(mDuckDBConverter, id__to_time, 7,
|
|
495
502
|
INT2FIX(data.date.year),
|
|
496
503
|
INT2FIX(data.date.month),
|
|
497
504
|
INT2FIX(data.date.day),
|
|
@@ -504,7 +511,7 @@ static VALUE vector_timestamp(void* vector_data, idx_t row_idx) {
|
|
|
504
511
|
|
|
505
512
|
static VALUE vector_time(void* vector_data, idx_t row_idx) {
|
|
506
513
|
duckdb_time_struct data = duckdb_from_time(((duckdb_time *)vector_data)[row_idx]);
|
|
507
|
-
return rb_funcall(mDuckDBConverter,
|
|
514
|
+
return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_time, 4,
|
|
508
515
|
INT2FIX(data.hour),
|
|
509
516
|
INT2FIX(data.min),
|
|
510
517
|
INT2FIX(data.sec),
|
|
@@ -515,7 +522,7 @@ static VALUE vector_time(void* vector_data, idx_t row_idx) {
|
|
|
515
522
|
|
|
516
523
|
static VALUE vector_interval(void* vector_data, idx_t row_idx) {
|
|
517
524
|
duckdb_interval data = ((duckdb_interval *)vector_data)[row_idx];
|
|
518
|
-
return rb_funcall(mDuckDBConverter,
|
|
525
|
+
return rb_funcall(mDuckDBConverter, id__to_interval_from_vector, 3,
|
|
519
526
|
INT2NUM(data.months),
|
|
520
527
|
INT2NUM(data.days),
|
|
521
528
|
LL2NUM(data.micros)
|
|
@@ -542,34 +549,47 @@ static VALUE vector_varchar(void* vector_data, idx_t row_idx) {
|
|
|
542
549
|
|
|
543
550
|
static VALUE vector_hugeint(void* vector_data, idx_t row_idx) {
|
|
544
551
|
duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
|
|
545
|
-
return rb_funcall(mDuckDBConverter,
|
|
552
|
+
return rb_funcall(mDuckDBConverter, id__to_hugeint_from_vector, 2,
|
|
546
553
|
ULL2NUM(hugeint.lower),
|
|
547
554
|
LL2NUM(hugeint.upper)
|
|
548
555
|
);
|
|
549
556
|
}
|
|
550
557
|
|
|
551
558
|
static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
|
|
552
|
-
|
|
553
|
-
|
|
559
|
+
VALUE width = INT2FIX(duckdb_decimal_width(ty));
|
|
560
|
+
VALUE scale = INT2FIX(duckdb_decimal_scale(ty));
|
|
554
561
|
duckdb_type type = duckdb_decimal_internal_type(ty);
|
|
555
562
|
duckdb_hugeint value;
|
|
563
|
+
VALUE upper = Qnil;
|
|
564
|
+
VALUE lower = Qnil;
|
|
556
565
|
|
|
557
566
|
value.upper = 0;
|
|
558
567
|
value.lower = 0;
|
|
559
568
|
|
|
560
|
-
switch(
|
|
569
|
+
switch(type) {
|
|
561
570
|
case DUCKDB_TYPE_HUGEINT:
|
|
562
571
|
value = ((duckdb_hugeint *) vector_data)[row_idx];
|
|
572
|
+
upper = LL2NUM(value.upper);
|
|
573
|
+
lower = ULL2NUM(value.lower);
|
|
574
|
+
break;
|
|
575
|
+
case DUCKDB_TYPE_SMALLINT:
|
|
576
|
+
upper = INT2FIX(((int16_t *) vector_data)[row_idx]);
|
|
577
|
+
break;
|
|
578
|
+
case DUCKDB_TYPE_INTEGER:
|
|
579
|
+
upper = INT2NUM(((int32_t *) vector_data)[row_idx]);
|
|
580
|
+
break;
|
|
581
|
+
case DUCKDB_TYPE_BIGINT:
|
|
582
|
+
upper = LL2NUM(((int64_t *) vector_data)[row_idx]);
|
|
563
583
|
break;
|
|
564
584
|
default:
|
|
565
585
|
rb_warn("Unknown decimal internal type %d", type);
|
|
566
586
|
}
|
|
567
587
|
|
|
568
|
-
return rb_funcall(mDuckDBConverter,
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
588
|
+
return rb_funcall(mDuckDBConverter, id__to_decimal_from_hugeint, 4,
|
|
589
|
+
width,
|
|
590
|
+
scale,
|
|
591
|
+
upper,
|
|
592
|
+
lower
|
|
573
593
|
);
|
|
574
594
|
}
|
|
575
595
|
|
|
@@ -665,7 +685,7 @@ static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t r
|
|
|
665
685
|
|
|
666
686
|
static VALUE vector_uuid(void* vector_data, idx_t row_idx) {
|
|
667
687
|
duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
|
|
668
|
-
return rb_funcall(mDuckDBConverter,
|
|
688
|
+
return rb_funcall(mDuckDBConverter, id__to_uuid_from_vector, 2,
|
|
669
689
|
ULL2NUM(hugeint.lower),
|
|
670
690
|
LL2NUM(hugeint.upper)
|
|
671
691
|
);
|
|
@@ -774,6 +794,14 @@ static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
|
|
774
794
|
|
|
775
795
|
void rbduckdb_init_duckdb_result(void) {
|
|
776
796
|
cDuckDBResult = rb_define_class_under(mDuckDB, "Result", rb_cObject);
|
|
797
|
+
id__to_date = rb_intern("_to_date");
|
|
798
|
+
id__to_time = rb_intern("_to_time");
|
|
799
|
+
id__to_time_from_duckdb_time = rb_intern("_to_time_from_duckdb_time");
|
|
800
|
+
id__to_interval_from_vector = rb_intern("_to_interval_from_vector");
|
|
801
|
+
id__to_hugeint_from_vector = rb_intern("_to_hugeint_from_vector");
|
|
802
|
+
id__to_decimal_from_hugeint = rb_intern("_to_decimal_from_hugeint");
|
|
803
|
+
id__to_uuid_from_vector = rb_intern("_to_uuid_from_vector");
|
|
804
|
+
|
|
777
805
|
rb_define_alloc_func(cDuckDBResult, allocate);
|
|
778
806
|
|
|
779
807
|
rb_define_method(cDuckDBResult, "column_count", duckdb_result_column_count, 0);
|
data/ext/duckdb/ruby-duckdb.h
CHANGED
data/lib/duckdb/column.rb
CHANGED
data/lib/duckdb/converter.rb
CHANGED
|
@@ -4,6 +4,8 @@ require 'date'
|
|
|
4
4
|
require_relative 'interval'
|
|
5
5
|
|
|
6
6
|
module DuckDB
|
|
7
|
+
QueryProgress = Struct.new(:percentage, :rows_processed, :total_rows_to_process)
|
|
8
|
+
|
|
7
9
|
module Converter
|
|
8
10
|
HALF_HUGEINT_BIT = 64
|
|
9
11
|
HALF_HUGEINT = 1 << HALF_HUGEINT_BIT
|
|
@@ -35,10 +37,15 @@ module DuckDB
|
|
|
35
37
|
(upper << HALF_HUGEINT_BIT) + lower
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
def
|
|
39
|
-
v = _to_hugeint_from_vector(lower, upper)
|
|
40
|
+
def _to_decimal_from_hugeint(width, scale, upper, lower = nil)
|
|
41
|
+
v = lower.nil? ? upper : _to_hugeint_from_vector(lower, upper)
|
|
42
|
+
_to_decimal_from_value(width, scale, v)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def _to_decimal_from_value(_width, scale, value)
|
|
46
|
+
v = value.to_s
|
|
40
47
|
v = v.rjust(scale + 1, '0') if v.length < scale
|
|
41
|
-
v[-scale, 0] = '.'
|
|
48
|
+
v[-scale, 0] = '.' if scale.positive?
|
|
42
49
|
BigDecimal(v)
|
|
43
50
|
end
|
|
44
51
|
|
|
@@ -80,6 +87,10 @@ module DuckDB
|
|
|
80
87
|
end
|
|
81
88
|
end
|
|
82
89
|
|
|
90
|
+
def _to_query_progress(percentage, rows_processed, total_rows_to_process)
|
|
91
|
+
DuckDB::QueryProgress.new(percentage, rows_processed, total_rows_to_process).freeze
|
|
92
|
+
end
|
|
93
|
+
|
|
83
94
|
private
|
|
84
95
|
|
|
85
96
|
def integer_to_hugeint(value)
|
data/lib/duckdb/result.rb
CHANGED
|
@@ -24,18 +24,31 @@ module DuckDB
|
|
|
24
24
|
# end
|
|
25
25
|
class Result
|
|
26
26
|
include Enumerable
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
TO_METHODS = if Gem::Version.new(DuckDB::LIBRARY_VERSION) == Gem::Version.new('0.10.0')
|
|
28
|
+
Hash.new(:_to_string).merge(
|
|
29
|
+
1 => :_to_boolean,
|
|
30
|
+
3 => :_to_smallint,
|
|
31
|
+
4 => :_to_integer,
|
|
32
|
+
5 => :_to_bigint,
|
|
33
|
+
10 => :_to_float,
|
|
34
|
+
11 => :_to_double,
|
|
35
|
+
16 => :_to_hugeint_internal,
|
|
36
|
+
19 => :_to_blob,
|
|
37
|
+
20 => :_to_decimal_internal
|
|
38
|
+
).freeze
|
|
39
|
+
else
|
|
40
|
+
Hash.new(:_to_string).merge(
|
|
41
|
+
1 => :_to_boolean,
|
|
42
|
+
3 => :_to_smallint,
|
|
43
|
+
4 => :_to_integer,
|
|
44
|
+
5 => :_to_bigint,
|
|
45
|
+
10 => :_to_float,
|
|
46
|
+
11 => :_to_double,
|
|
47
|
+
16 => :_to_hugeint_internal,
|
|
48
|
+
18 => :_to_blob,
|
|
49
|
+
19 => :_to_decimal_internal
|
|
50
|
+
).freeze
|
|
51
|
+
end
|
|
39
52
|
|
|
40
53
|
alias column_size column_count
|
|
41
54
|
alias row_size row_count
|
|
@@ -114,7 +127,7 @@ module DuckDB
|
|
|
114
127
|
|
|
115
128
|
def _to_decimal_internal(row, col)
|
|
116
129
|
lower, upper, width, scale = __to_decimal_internal(row, col)
|
|
117
|
-
Converter.
|
|
130
|
+
Converter._to_decimal_from_hugeint(width, scale, upper, lower)
|
|
118
131
|
end
|
|
119
132
|
end
|
|
120
133
|
end
|
data/lib/duckdb/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: duckdb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Masaki Suketa
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-03-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bigdecimal
|
|
@@ -109,6 +109,7 @@ files:
|
|
|
109
109
|
- benchmark/to_bigdecimal_ips.rb
|
|
110
110
|
- benchmark/to_hugeint_ips.rb
|
|
111
111
|
- benchmark/to_hugeint_profile.rb
|
|
112
|
+
- benchmark/to_intern_ips.rb
|
|
112
113
|
- bin/console
|
|
113
114
|
- bin/setup
|
|
114
115
|
- docker-compose.yml
|