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 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: []