duckdb 0.2.6.0 → 0.2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +1 -1
- data/README.md +67 -1
- data/ext/duckdb/appender.c +3 -3
- data/ext/duckdb/prepared_statement.c +17 -2
- data/ext/duckdb/result.c +3 -0
- data/lib/duckdb.rb +1 -0
- data/lib/duckdb/appender.rb +102 -0
- data/lib/duckdb/connection.rb +21 -0
- data/lib/duckdb/prepared_statement.rb +20 -2
- data/lib/duckdb/version.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e40641b43de4613a5417e6f06fb50e23277394f4ba54aadc524afa319e15dbb
|
4
|
+
data.tar.gz: a5c578bb6fd9dee33ca0ab5af5d853e623fefec7fc9b74a43b4d6432cdec6fb5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2db7f176dc767856e43a2f8e4991c0bd6229f4174e2c1e91595436f36320f4f2b2eb1db52186644641b0ed45e38798a2bf76688e398abe27d4c3b81eda780939
|
7
|
+
data.tar.gz: 0343b460f0f62393ecd6e550ce468fa28c0098ce236a87968ad2bc8eb2f4764e87448c7df80f328e39b1f07da1acef6e5a931dfafe91af222dc201ef41812f36
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# ChangeLog
|
2
2
|
|
3
|
+
# 0.2.6.1
|
4
|
+
|
5
|
+
- add DuckDB::PreparedStatement#bind_int8
|
6
|
+
- DuckDB::Connection#appender accepts block.
|
7
|
+
- add DuckDB::Appender#append_row.
|
8
|
+
- support HUGEINT type.
|
9
|
+
- add DuckDB::Appender#append.
|
10
|
+
- rename PreparedStatement#bind_boolean to PreparedStatement#bind_bool.
|
11
|
+
- add DuckDB::Connection#appender.
|
12
|
+
|
3
13
|
# 0.2.6.0
|
4
14
|
|
5
15
|
- change version policy
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -68,7 +68,7 @@ end
|
|
68
68
|
### using BLOB column
|
69
69
|
|
70
70
|
BLOB is available with DuckDB v0.2.5 or later.
|
71
|
-
Use `DuckDB::Blob.new` or use sting#force_encoding(Encoding::
|
71
|
+
Use `DuckDB::Blob.new` or use sting#force_encoding(Encoding::BINARY)
|
72
72
|
|
73
73
|
```
|
74
74
|
require 'duckdb'
|
@@ -87,3 +87,69 @@ DuckDB::Database.open do |db|
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
```
|
90
|
+
|
91
|
+
### Appender
|
92
|
+
|
93
|
+
Appender class provides Ruby interface of [DuckDB Appender](https://duckdb.org/docs/data/appender)
|
94
|
+
|
95
|
+
```
|
96
|
+
require 'duckdb'
|
97
|
+
require 'benchmark'
|
98
|
+
|
99
|
+
def insert
|
100
|
+
DuckDB::Database.open do |db|
|
101
|
+
db.connect do |con|
|
102
|
+
con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
103
|
+
10000.times do
|
104
|
+
con.query("INSERT into users VALUES(1, 'Alice')")
|
105
|
+
end
|
106
|
+
# r = con.query('SELECT count(*) from users')
|
107
|
+
# p r.each.first
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def prepare
|
113
|
+
DuckDB::Database.open do |db|
|
114
|
+
db.connect do |con|
|
115
|
+
con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
116
|
+
stmt = con.prepared_statement('INSERT INTO users VALUES($1, $2)')
|
117
|
+
10000.times do
|
118
|
+
stmt.bind(1, 1)
|
119
|
+
stmt.bind(2, 'Alice')
|
120
|
+
stmt.execute
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def append
|
127
|
+
DuckDB::Database.open do |db|
|
128
|
+
db.connect do |con|
|
129
|
+
con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
130
|
+
appender = con.appender('users')
|
131
|
+
10000.times do
|
132
|
+
appender.begin_row
|
133
|
+
appender.append(1)
|
134
|
+
appender.append('Alice')
|
135
|
+
appender.end_row
|
136
|
+
end
|
137
|
+
appender.flush
|
138
|
+
# r = con.query('SELECT count(*) from users')
|
139
|
+
# p r.each.first
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
Benchmark.bm(8) do |x|
|
145
|
+
x.report('insert') { insert }
|
146
|
+
x.report('prepare') { prepare }
|
147
|
+
x.report('append') { append }
|
148
|
+
end
|
149
|
+
|
150
|
+
# =>
|
151
|
+
# user system total real
|
152
|
+
# insert 0.637439 0.000000 0.637439 ( 0.637486 )
|
153
|
+
# prepare 0.230457 0.000000 0.230457 ( 0.230460 )
|
154
|
+
# append 0.012666 0.000000 0.012666 ( 0.012670 )
|
155
|
+
```
|
data/ext/duckdb/appender.c
CHANGED
@@ -112,7 +112,7 @@ static VALUE appender_append_int8(VALUE self, VALUE val) {
|
|
112
112
|
|
113
113
|
static VALUE appender_append_int16(VALUE self, VALUE val) {
|
114
114
|
rubyDuckDBAppender *ctx;
|
115
|
-
int16_t i16val = NUM2INT(val);
|
115
|
+
int16_t i16val = (int16_t)NUM2INT(val);
|
116
116
|
|
117
117
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
118
118
|
|
@@ -136,7 +136,7 @@ static VALUE appender_append_int32(VALUE self, VALUE val) {
|
|
136
136
|
|
137
137
|
static VALUE appender_append_int64(VALUE self, VALUE val) {
|
138
138
|
rubyDuckDBAppender *ctx;
|
139
|
-
int64_t i64val = NUM2LL(val);
|
139
|
+
int64_t i64val = (int64_t)NUM2LL(val);
|
140
140
|
|
141
141
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
142
142
|
|
@@ -184,7 +184,7 @@ static VALUE appender_append_uint32(VALUE self, VALUE val) {
|
|
184
184
|
|
185
185
|
static VALUE appender_append_uint64(VALUE self, VALUE val) {
|
186
186
|
rubyDuckDBAppender *ctx;
|
187
|
-
uint64_t ui64val = (
|
187
|
+
uint64_t ui64val = (uint64_t)NUM2ULL(val);
|
188
188
|
|
189
189
|
Data_Get_Struct(self, rubyDuckDBAppender, ctx);
|
190
190
|
|
@@ -70,7 +70,7 @@ static idx_t check_index(VALUE vidx)
|
|
70
70
|
return idx;
|
71
71
|
}
|
72
72
|
|
73
|
-
static VALUE
|
73
|
+
static VALUE duckdb_prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val)
|
74
74
|
{
|
75
75
|
rubyDuckDBPreparedStatement *ctx;
|
76
76
|
idx_t idx = check_index(vidx);
|
@@ -86,6 +86,20 @@ static VALUE duckdb_prepared_statement_bind_boolean(VALUE self, VALUE vidx, VALU
|
|
86
86
|
return self;
|
87
87
|
}
|
88
88
|
|
89
|
+
static VALUE duckdb_prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val)
|
90
|
+
{
|
91
|
+
rubyDuckDBPreparedStatement *ctx;
|
92
|
+
idx_t idx = check_index(vidx);
|
93
|
+
int8_t i8val = (int8_t)NUM2INT(val);
|
94
|
+
|
95
|
+
Data_Get_Struct(self, rubyDuckDBPreparedStatement, ctx);
|
96
|
+
|
97
|
+
if (duckdb_bind_int8(ctx->prepared_statement, idx, i8val) == DuckDBError) {
|
98
|
+
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
99
|
+
}
|
100
|
+
return self;
|
101
|
+
}
|
102
|
+
|
89
103
|
static VALUE duckdb_prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val)
|
90
104
|
{
|
91
105
|
rubyDuckDBPreparedStatement *ctx;
|
@@ -203,7 +217,8 @@ void init_duckdb_prepared_statement(void)
|
|
203
217
|
rb_define_method(cDuckDBPreparedStatement, "initialize", duckdb_prepared_statement_initialize, 2);
|
204
218
|
rb_define_method(cDuckDBPreparedStatement, "execute", duckdb_prepared_statement_execute, 0);
|
205
219
|
rb_define_method(cDuckDBPreparedStatement, "nparams", duckdb_prepared_statement_nparams, 0);
|
206
|
-
rb_define_method(cDuckDBPreparedStatement, "
|
220
|
+
rb_define_method(cDuckDBPreparedStatement, "bind_bool", duckdb_prepared_statement_bind_bool, 2);
|
221
|
+
rb_define_method(cDuckDBPreparedStatement, "bind_int8", duckdb_prepared_statement_bind_int8, 2);
|
207
222
|
rb_define_method(cDuckDBPreparedStatement, "bind_int16", duckdb_prepared_statement_bind_int16, 2);
|
208
223
|
rb_define_method(cDuckDBPreparedStatement, "bind_int32", duckdb_prepared_statement_bind_int32, 2);
|
209
224
|
rb_define_method(cDuckDBPreparedStatement, "bind_int64", duckdb_prepared_statement_bind_int64, 2);
|
data/ext/duckdb/result.c
CHANGED
@@ -88,6 +88,9 @@ static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx)
|
|
88
88
|
p = duckdb_value_varchar(result, col_idx, row_idx);
|
89
89
|
obj = rb_str_new2(p);
|
90
90
|
free(p);
|
91
|
+
if (result->columns[col_idx].type == DUCKDB_TYPE_HUGEINT) {
|
92
|
+
obj = rb_funcall(obj, rb_intern("to_i"), 0);
|
93
|
+
}
|
91
94
|
}
|
92
95
|
return obj;
|
93
96
|
}
|
data/lib/duckdb.rb
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module DuckDB
|
4
|
+
if defined?(DuckDB::Appender)
|
5
|
+
# The DuckDB::Appender encapsulates DuckDB Appender.
|
6
|
+
#
|
7
|
+
# require 'duckdb'
|
8
|
+
# db = DuckDB::Database.open
|
9
|
+
# con = db.connect
|
10
|
+
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
11
|
+
# appender = con.appender('users')
|
12
|
+
# appender.append_row(1, 'Alice')
|
13
|
+
#
|
14
|
+
class Appender
|
15
|
+
RANGE_INT16 = (-32_768..32_767).freeze
|
16
|
+
RANGE_INT32 = (-2_147_483_648..2_147_483_647).freeze
|
17
|
+
RANGE_INT64 = (-9_223_372_036_854_775_808..9_223_372_036_854_775_807).freeze
|
18
|
+
|
19
|
+
def append_hugeint(value)
|
20
|
+
case value
|
21
|
+
when Integer
|
22
|
+
append_varchar(value.to_s)
|
23
|
+
else
|
24
|
+
rb_raise(ArgumentError, "2nd argument `#{value}` must be Integer.")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# appends value.
|
30
|
+
#
|
31
|
+
# require 'duckdb'
|
32
|
+
# db = DuckDB::Database.open
|
33
|
+
# con = db.connect
|
34
|
+
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
35
|
+
# appender = con.appender('users')
|
36
|
+
# appender.begin_row
|
37
|
+
# appender.append(1)
|
38
|
+
# appender.append('Alice')
|
39
|
+
# appender.end_row
|
40
|
+
#
|
41
|
+
def append(value)
|
42
|
+
case value
|
43
|
+
when NilClass
|
44
|
+
append_null
|
45
|
+
when Float
|
46
|
+
append_double(value)
|
47
|
+
when Integer
|
48
|
+
case value
|
49
|
+
when RANGE_INT16
|
50
|
+
append_int16(value)
|
51
|
+
when RANGE_INT32
|
52
|
+
append_int32(value)
|
53
|
+
when RANGE_INT64
|
54
|
+
append_int64(value)
|
55
|
+
else
|
56
|
+
append_hugeint(value)
|
57
|
+
end
|
58
|
+
when String
|
59
|
+
if defined?(DuckDB::Blob)
|
60
|
+
blob?(value) ? append_blob(value) : append_varchar(value)
|
61
|
+
else
|
62
|
+
append_varchar(value)
|
63
|
+
end
|
64
|
+
when TrueClass, FalseClass
|
65
|
+
append_bool(value)
|
66
|
+
when Time
|
67
|
+
append_varchar(value.strftime('%Y-%m-%d %H:%M:%S.%N'))
|
68
|
+
when Date
|
69
|
+
append_varchar(value.strftime('%Y-%m-%d'))
|
70
|
+
else
|
71
|
+
rb_raise(DuckDB::Error, "not supported type #{value} (value.class)")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# append a row.
|
77
|
+
#
|
78
|
+
# appender.append_row(1, 'Alice')
|
79
|
+
#
|
80
|
+
# is same as:
|
81
|
+
#
|
82
|
+
# appender.begin_row
|
83
|
+
# appender.append(1)
|
84
|
+
# appender.append('Alice')
|
85
|
+
# appender.end_row
|
86
|
+
#
|
87
|
+
def append_row(*args)
|
88
|
+
begin_row
|
89
|
+
args.each do |arg|
|
90
|
+
append(arg)
|
91
|
+
end
|
92
|
+
end_row
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def blob?(value)
|
98
|
+
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/duckdb/connection.rb
CHANGED
@@ -52,6 +52,27 @@ module DuckDB
|
|
52
52
|
PreparedStatement.new(self, str)
|
53
53
|
end
|
54
54
|
|
55
|
+
#
|
56
|
+
# returns Appender object.
|
57
|
+
# The first argument is table name
|
58
|
+
#
|
59
|
+
def appender(table)
|
60
|
+
appender = create_appender(table)
|
61
|
+
|
62
|
+
return appender unless block_given?
|
63
|
+
|
64
|
+
yield appender
|
65
|
+
appender.flush
|
66
|
+
appender.close
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def create_appender(table)
|
72
|
+
t1, t2 = table.split('.')
|
73
|
+
t2 ? Appender.new(self, t1, t2) : Appender.new(self, t2, t1)
|
74
|
+
end
|
75
|
+
|
55
76
|
alias execute query
|
56
77
|
alias open connect
|
57
78
|
alias close disconnect
|
@@ -13,6 +13,19 @@ module DuckDB
|
|
13
13
|
# stmt.execute
|
14
14
|
class PreparedStatement
|
15
15
|
|
16
|
+
RANGE_INT16 = -32768..32767
|
17
|
+
RANGE_INT32 = -2147483648..2147483647
|
18
|
+
RANGE_INT64 = -9223372036854775808..9223372036854775807
|
19
|
+
|
20
|
+
def bind_hugeint(i, value)
|
21
|
+
case value
|
22
|
+
when Integer
|
23
|
+
bind_varchar(i, value.to_s)
|
24
|
+
else
|
25
|
+
rb_raise(ArgumentError, "2nd argument `#{value}` must be Integer.")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
16
29
|
# binds i-th parameter with SQL prepared statement.
|
17
30
|
# The first argument is index of parameter. The index of first parameter is
|
18
31
|
# 1 not 0.
|
@@ -31,7 +44,12 @@ module DuckDB
|
|
31
44
|
when Float
|
32
45
|
bind_double(i, value)
|
33
46
|
when Integer
|
34
|
-
|
47
|
+
case value
|
48
|
+
when RANGE_INT64
|
49
|
+
bind_int64(i, value)
|
50
|
+
else
|
51
|
+
bind_varchar(i, value.to_s)
|
52
|
+
end
|
35
53
|
when String
|
36
54
|
if defined?(DuckDB::Blob)
|
37
55
|
blob?(value) ? bind_blob(i, value) : bind_varchar(i, value)
|
@@ -39,7 +57,7 @@ module DuckDB
|
|
39
57
|
bind_varchar(i, value)
|
40
58
|
end
|
41
59
|
when TrueClass, FalseClass
|
42
|
-
|
60
|
+
bind_bool(i, value)
|
43
61
|
when Time
|
44
62
|
bind_varchar(i, value.strftime('%Y-%m-%d %H:%M:%S.%N'))
|
45
63
|
when Date
|
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.6.
|
4
|
+
version: 0.2.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masaki Suketa
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- ext/duckdb/result.h
|
107
107
|
- ext/duckdb/ruby-duckdb.h
|
108
108
|
- lib/duckdb.rb
|
109
|
+
- lib/duckdb/appender.rb
|
109
110
|
- lib/duckdb/connection.rb
|
110
111
|
- lib/duckdb/database.rb
|
111
112
|
- lib/duckdb/prepared_statement.rb
|
@@ -118,7 +119,7 @@ metadata:
|
|
118
119
|
homepage_uri: https://github.com/suketa/ruby-duckdb
|
119
120
|
source_code_uri: https://github.com/suketa/ruby-duckdb
|
120
121
|
changelog_uri: https://github.com/suketa/ruby-duckdb/blob/master/CHANGELOG.md
|
121
|
-
post_install_message:
|
122
|
+
post_install_message:
|
122
123
|
rdoc_options: []
|
123
124
|
require_paths:
|
124
125
|
- lib
|
@@ -133,8 +134,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
134
|
- !ruby/object:Gem::Version
|
134
135
|
version: '0'
|
135
136
|
requirements: []
|
136
|
-
rubygems_version: 3.
|
137
|
-
signing_key:
|
137
|
+
rubygems_version: 3.2.15
|
138
|
+
signing_key:
|
138
139
|
specification_version: 4
|
139
140
|
summary: This module is Ruby binding for DuckDB database engine.
|
140
141
|
test_files: []
|