duckdb 0.2.6.0 → 0.2.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96e1030a16d014daaab4b84c0c15cde0d023fcb0fb761bee97056127f3530533
4
- data.tar.gz: 2010828495199a8959b2246c0de6262de273387daaa3b3b9a8ebbca6e2fda47c
3
+ metadata.gz: 1e40641b43de4613a5417e6f06fb50e23277394f4ba54aadc524afa319e15dbb
4
+ data.tar.gz: a5c578bb6fd9dee33ca0ab5af5d853e623fefec7fc9b74a43b4d6432cdec6fb5
5
5
  SHA512:
6
- metadata.gz: da434b1e0f179cf6392beb998be0eba637cd782a74a4ea4474752b1c900afe1cbf43a5816cb7ff37c8b6e34226a0a2bcc4e4e89e54c28697e5ec39695775f31f
7
- data.tar.gz: be2f05c2b472db0e548da9acd69aebd41ff0685fdcf925970af36d489882539a88fb51c49a791edd1e4f34daf9aac16311e15ce6771e9f504b987e1d29e1aa93
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (0.2.6.0)
4
+ duckdb (0.2.6.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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::ASCII_8BIT)
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
+ ```
@@ -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 = (int64_t)NUM2ULL(val);
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 duckdb_prepared_statement_bind_boolean(VALUE self, VALUE vidx, VALUE val)
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, "bind_boolean", duckdb_prepared_statement_bind_boolean, 2);
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
@@ -4,6 +4,7 @@ require 'duckdb/database'
4
4
  require 'duckdb/connection'
5
5
  require 'duckdb/result'
6
6
  require 'duckdb/prepared_statement'
7
+ require 'duckdb/appender'
7
8
 
8
9
  # DuckDB provides Ruby interface of DuckDB.
9
10
  module DuckDB
@@ -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
@@ -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
- bind_int64(i, value)
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
- bind_boolean(i, value)
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
@@ -1,5 +1,5 @@
1
1
  module DuckDB
2
2
  # The version string of ruby-duckdb.
3
3
  # Currently, ruby-duckdb is NOT semantic versioning.
4
- VERSION = '0.2.6.0'.freeze
4
+ VERSION = '0.2.6.1'.freeze
5
5
  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.2.6.0
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-05-22 00:00:00.000000000 Z
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.3.0.dev
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: []