duckdb 1.1.3.0 → 1.2.0.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/make_documents.yml +34 -0
- 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/.gitignore +1 -0
- data/.rdoc_options +22 -0
- data/CHANGELOG.md +49 -0
- data/Dockerfile +20 -9
- data/Gemfile.lock +23 -11
- data/README.md +17 -3
- data/duckdb.gemspec +1 -0
- data/ext/duckdb/appender.c +113 -78
- data/ext/duckdb/blob.c +3 -0
- data/ext/duckdb/column.c +33 -3
- data/ext/duckdb/config.c +3 -0
- data/ext/duckdb/connection.c +6 -0
- data/ext/duckdb/database.c +6 -0
- data/ext/duckdb/duckdb.c +1 -0
- data/ext/duckdb/error.c +3 -0
- data/ext/duckdb/extconf.rb +0 -3
- data/ext/duckdb/extracted_statements.c +3 -0
- data/ext/duckdb/logical_type.c +187 -0
- data/ext/duckdb/logical_type.h +13 -0
- data/ext/duckdb/pending_result.c +5 -0
- data/ext/duckdb/prepared_statement.c +46 -8
- data/ext/duckdb/result.c +16 -44
- data/ext/duckdb/ruby-duckdb.h +2 -0
- data/lib/duckdb/appender.rb +211 -48
- data/lib/duckdb/column.rb +0 -2
- data/lib/duckdb/connection.rb +1 -12
- data/lib/duckdb/database.rb +1 -6
- data/lib/duckdb/interval.rb +12 -10
- data/lib/duckdb/library_version.rb +2 -0
- data/lib/duckdb/logical_type.rb +22 -0
- data/lib/duckdb/pending_result.rb +1 -1
- data/lib/duckdb/result.rb +16 -16
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +1 -0
- metadata +9 -6
data/lib/duckdb/appender.rb
CHANGED
@@ -13,15 +13,216 @@ module DuckDB
|
|
13
13
|
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
14
14
|
# appender = con.appender('users')
|
15
15
|
# appender.append_row(1, 'Alice')
|
16
|
-
#
|
17
16
|
class Appender
|
18
17
|
include DuckDB::Converter
|
19
18
|
|
19
|
+
# :stopdoc:
|
20
20
|
RANGE_INT16 = -32_768..32_767
|
21
21
|
RANGE_INT32 = -2_147_483_648..2_147_483_647
|
22
22
|
RANGE_INT64 = -9_223_372_036_854_775_808..9_223_372_036_854_775_807
|
23
|
+
private_constant :RANGE_INT16, :RANGE_INT32, :RANGE_INT64
|
24
|
+
# :startdoc:
|
25
|
+
|
26
|
+
# :call-seq:
|
27
|
+
# appender.begin_row -> self
|
28
|
+
# A nop method, provided for backwards compatibility reasons.
|
29
|
+
# Does nothing. Only `end_row` is required.
|
30
|
+
def begin_row
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# call-seq:
|
35
|
+
# appender.end_row -> self
|
36
|
+
#
|
37
|
+
# Finish the current row of appends. After end_row is called, the next row can be appended.
|
38
|
+
# require 'duckdb'
|
39
|
+
# db = DuckDB::Database.open
|
40
|
+
# con = db.connect
|
41
|
+
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
42
|
+
# appender = con.appender('users')
|
43
|
+
# appender
|
44
|
+
# .append_int32(1)
|
45
|
+
# .append_varchar('Alice')
|
46
|
+
# .end_row
|
47
|
+
def end_row
|
48
|
+
return self if _end_row
|
49
|
+
|
50
|
+
raise_appender_error('failed to end_row')
|
51
|
+
end
|
52
|
+
|
53
|
+
# :call-seq:
|
54
|
+
# appender.flush -> self
|
55
|
+
#
|
56
|
+
# Flushes the appender to the table, forcing the cache of the appender to be cleared.
|
57
|
+
# If flushing the data triggers a constraint violation or any other error, then all
|
58
|
+
# data is invalidated, and this method raises DuckDB::Error.
|
59
|
+
#
|
60
|
+
# require 'duckdb'
|
61
|
+
# db = DuckDB::Database.open
|
62
|
+
# con = db.connect
|
63
|
+
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
64
|
+
# appender = con.appender('users')
|
65
|
+
# appender
|
66
|
+
# .append_int32(1)
|
67
|
+
# .append_varchar('Alice')
|
68
|
+
# .end_row
|
69
|
+
# .flush
|
70
|
+
def flush
|
71
|
+
return self if _flush
|
72
|
+
|
73
|
+
raise_appender_error('failed to flush')
|
74
|
+
end
|
75
|
+
|
76
|
+
# :call-seq:
|
77
|
+
# appender.close -> self
|
78
|
+
#
|
79
|
+
# Closes the appender by flushing all intermediate states and closing it for further appends.
|
80
|
+
# If flushing the data triggers a constraint violation or any other error, then all data is
|
81
|
+
# invalidated, and this method raises DuckDB::Error.
|
82
|
+
#
|
83
|
+
# require 'duckdb'
|
84
|
+
# db = DuckDB::Database.open
|
85
|
+
# con = db.connect
|
86
|
+
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
87
|
+
# appender = con.appender('users')
|
88
|
+
# appender
|
89
|
+
# .append_int32(1)
|
90
|
+
# .append_varchar('Alice')
|
91
|
+
# .end_row
|
92
|
+
# .close
|
93
|
+
def close
|
94
|
+
return self if _close
|
95
|
+
|
96
|
+
raise_appender_error('failed to close')
|
97
|
+
end
|
98
|
+
|
99
|
+
# call-seq:
|
100
|
+
# appender.append_bool(val) -> self
|
101
|
+
#
|
102
|
+
# Appends a boolean value to the current row in the appender.
|
103
|
+
#
|
104
|
+
# require 'duckdb'
|
105
|
+
# db = DuckDB::Database.open
|
106
|
+
# con = db.connect
|
107
|
+
# con.query('CREATE TABLE users (id INTEGER, active BOOLEAN)')
|
108
|
+
# appender = con.appender('users')
|
109
|
+
# appender
|
110
|
+
# .append_int32(1)
|
111
|
+
# .append_bool(true)
|
112
|
+
# .end_row
|
113
|
+
# .flush
|
114
|
+
def append_bool(value)
|
115
|
+
return self if _append_bool(value)
|
116
|
+
|
117
|
+
raise_appender_error('failed to append_bool')
|
118
|
+
end
|
119
|
+
|
120
|
+
# call-seq:
|
121
|
+
# appender.append_int8(val) -> self
|
122
|
+
#
|
123
|
+
# Appends an int8(TINYINT) value to the current row in the appender.
|
124
|
+
#
|
125
|
+
# require 'duckdb'
|
126
|
+
# db = DuckDB::Database.open
|
127
|
+
# con = db.connect
|
128
|
+
# con.query('CREATE TABLE users (id INTEGER, age TINYINT)')
|
129
|
+
# appender = con.appender('users')
|
130
|
+
# appender
|
131
|
+
# .append_int32(1)
|
132
|
+
# .append_int8(20)
|
133
|
+
# .end_row
|
134
|
+
# .flush
|
135
|
+
#
|
136
|
+
def append_int8(value)
|
137
|
+
return self if _append_int8(value)
|
138
|
+
|
139
|
+
raise_appender_error('failed to append_int8')
|
140
|
+
end
|
23
141
|
|
142
|
+
# call-seq:
|
143
|
+
# appender.append_int16(val) -> self
|
24
144
|
#
|
145
|
+
# Appends an int16(SMALLINT) value to the current row in the appender.
|
146
|
+
#
|
147
|
+
# require 'duckdb'
|
148
|
+
# db = DuckDB::Database.open
|
149
|
+
# con = db.connect
|
150
|
+
# con.query('CREATE TABLE users (id INTEGER, age SMALLINT)')
|
151
|
+
# appender = con.appender('users')
|
152
|
+
# appender
|
153
|
+
# .append_int32(1)
|
154
|
+
# .append_int16(20)
|
155
|
+
# .end_row
|
156
|
+
# .flush
|
157
|
+
def append_int16(value)
|
158
|
+
return self if _append_int16(value)
|
159
|
+
|
160
|
+
raise_appender_error('failed to append_int16')
|
161
|
+
end
|
162
|
+
|
163
|
+
# call-seq:
|
164
|
+
# appender.append_int32(val) -> self
|
165
|
+
#
|
166
|
+
# Appends an int32(INTEGER) value to the current row in the appender.
|
167
|
+
#
|
168
|
+
# require 'duckdb'
|
169
|
+
# db = DuckDB::Database.open
|
170
|
+
# con = db.connect
|
171
|
+
# con.query('CREATE TABLE users (id INTEGER, age INTEGER)')
|
172
|
+
# appender = con.appender('users')
|
173
|
+
# appender
|
174
|
+
# .append_int32(1)
|
175
|
+
# .append_int32(20)
|
176
|
+
# .end_row
|
177
|
+
# .flush
|
178
|
+
def append_int32(value)
|
179
|
+
return self if _append_int32(value)
|
180
|
+
|
181
|
+
raise_appender_error('failed to append_int32')
|
182
|
+
end
|
183
|
+
|
184
|
+
# call-seq:
|
185
|
+
# appender.append_int64(val) -> self
|
186
|
+
#
|
187
|
+
# Appends an int64(BIGINT) value to the current row in the appender.
|
188
|
+
#
|
189
|
+
# require 'duckdb'
|
190
|
+
# db = DuckDB::Database.open
|
191
|
+
# con = db.connect
|
192
|
+
# con.query('CREATE TABLE users (id INTEGER, age BIGINT)')
|
193
|
+
# appender = con.appender('users')
|
194
|
+
# appender
|
195
|
+
# .append_int32(1)
|
196
|
+
# .append_int64(20)
|
197
|
+
# .end_row
|
198
|
+
# .flush
|
199
|
+
def append_int64(value)
|
200
|
+
return self if _append_int64(value)
|
201
|
+
|
202
|
+
raise_appender_error('failed to append_int64')
|
203
|
+
end
|
204
|
+
|
205
|
+
# call-seq:
|
206
|
+
# appender.append_uint8(val) -> self
|
207
|
+
#
|
208
|
+
# Appends an uint8 value to the current row in the appender.
|
209
|
+
#
|
210
|
+
# require 'duckdb'
|
211
|
+
# db = DuckDB::Database.open
|
212
|
+
# con = db.connect
|
213
|
+
# con.query('CREATE TABLE users (id INTEGER, age UTINYINT)')
|
214
|
+
# appender = con.appender('users')
|
215
|
+
# appender
|
216
|
+
# .append_int32(1)
|
217
|
+
# .append_uint8(20)
|
218
|
+
# .end_row
|
219
|
+
# .flush
|
220
|
+
def append_uint8(value)
|
221
|
+
return self if _append_uint8(value)
|
222
|
+
|
223
|
+
raise_appender_error('failed to append_uint8')
|
224
|
+
end
|
225
|
+
|
25
226
|
# appends huge int value.
|
26
227
|
#
|
27
228
|
# require 'duckdb'
|
@@ -30,16 +231,13 @@ module DuckDB
|
|
30
231
|
# con.query('CREATE TABLE numbers (num HUGEINT)')
|
31
232
|
# appender = con.appender('numbers')
|
32
233
|
# appender
|
33
|
-
# .begin_row
|
34
234
|
# .append_hugeint(-170_141_183_460_469_231_731_687_303_715_884_105_727)
|
35
235
|
# .end_row
|
36
|
-
#
|
37
236
|
def append_hugeint(value)
|
38
237
|
lower, upper = integer_to_hugeint(value)
|
39
238
|
_append_hugeint(lower, upper)
|
40
239
|
end
|
41
240
|
|
42
|
-
#
|
43
241
|
# appends unsigned huge int value.
|
44
242
|
#
|
45
243
|
# require 'duckdb'
|
@@ -48,16 +246,13 @@ module DuckDB
|
|
48
246
|
# con.query('CREATE TABLE numbers (num UHUGEINT)')
|
49
247
|
# appender = con.appender('numbers')
|
50
248
|
# appender
|
51
|
-
# .begin_row
|
52
249
|
# .append_hugeint(340_282_366_920_938_463_463_374_607_431_768_211_455)
|
53
250
|
# .end_row
|
54
|
-
#
|
55
251
|
def append_uhugeint(value)
|
56
252
|
lower, upper = integer_to_hugeint(value)
|
57
253
|
_append_uhugeint(lower, upper)
|
58
254
|
end
|
59
255
|
|
60
|
-
#
|
61
256
|
# appends date value.
|
62
257
|
#
|
63
258
|
# require 'duckdb'
|
@@ -65,21 +260,18 @@ module DuckDB
|
|
65
260
|
# con = db.connect
|
66
261
|
# con.query('CREATE TABLE dates (date_value DATE)')
|
67
262
|
# appender = con.appender('dates')
|
68
|
-
# appender.begin_row
|
69
263
|
# appender.append_date(Date.today)
|
70
264
|
# # or
|
71
265
|
# # appender.append_date(Time.now)
|
72
266
|
# # appender.append_date('2021-10-10')
|
73
267
|
# appender.end_row
|
74
268
|
# appender.flush
|
75
|
-
#
|
76
269
|
def append_date(value)
|
77
|
-
date =
|
270
|
+
date = _parse_date(value)
|
78
271
|
|
79
272
|
_append_date(date.year, date.month, date.day)
|
80
273
|
end
|
81
274
|
|
82
|
-
#
|
83
275
|
# appends time value.
|
84
276
|
#
|
85
277
|
# require 'duckdb'
|
@@ -87,20 +279,17 @@ module DuckDB
|
|
87
279
|
# con = db.connect
|
88
280
|
# con.query('CREATE TABLE times (time_value TIME)')
|
89
281
|
# appender = con.appender('times')
|
90
|
-
# appender.begin_row
|
91
282
|
# appender.append_time(Time.now)
|
92
283
|
# # or
|
93
284
|
# # appender.append_time('01:01:01')
|
94
285
|
# appender.end_row
|
95
286
|
# appender.flush
|
96
|
-
#
|
97
287
|
def append_time(value)
|
98
288
|
time = _parse_time(value)
|
99
289
|
|
100
290
|
_append_time(time.hour, time.min, time.sec, time.usec)
|
101
291
|
end
|
102
292
|
|
103
|
-
#
|
104
293
|
# appends timestamp value.
|
105
294
|
#
|
106
295
|
# require 'duckdb'
|
@@ -108,21 +297,18 @@ module DuckDB
|
|
108
297
|
# con = db.connect
|
109
298
|
# con.query('CREATE TABLE timestamps (timestamp_value TIMESTAMP)')
|
110
299
|
# appender = con.appender('timestamps')
|
111
|
-
# appender.begin_row
|
112
300
|
# appender.append_time(Time.now)
|
113
301
|
# # or
|
114
302
|
# # appender.append_time(Date.today)
|
115
303
|
# # appender.append_time('2021-08-01 01:01:01')
|
116
304
|
# appender.end_row
|
117
305
|
# appender.flush
|
118
|
-
#
|
119
306
|
def append_timestamp(value)
|
120
307
|
time = to_time(value)
|
121
308
|
|
122
309
|
_append_timestamp(time.year, time.month, time.day, time.hour, time.min, time.sec, time.nsec / 1000)
|
123
310
|
end
|
124
311
|
|
125
|
-
#
|
126
312
|
# appends interval.
|
127
313
|
# The argument must be ISO8601 duration format.
|
128
314
|
# WARNING: This method is expremental.
|
@@ -133,17 +319,14 @@ module DuckDB
|
|
133
319
|
# con.query('CREATE TABLE intervals (interval_value INTERVAL)')
|
134
320
|
# appender = con.appender('intervals')
|
135
321
|
# appender
|
136
|
-
# .begin_row
|
137
322
|
# .append_interval('P1Y2D') # => append 1 year 2 days interval.
|
138
323
|
# .end_row
|
139
324
|
# .flush
|
140
|
-
#
|
141
325
|
def append_interval(value)
|
142
326
|
value = Interval.to_interval(value)
|
143
327
|
_append_interval(value.interval_months, value.interval_days, value.interval_micros)
|
144
328
|
end
|
145
329
|
|
146
|
-
#
|
147
330
|
# appends value.
|
148
331
|
#
|
149
332
|
# require 'duckdb'
|
@@ -151,11 +334,9 @@ module DuckDB
|
|
151
334
|
# con = db.connect
|
152
335
|
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
|
153
336
|
# appender = con.appender('users')
|
154
|
-
# appender.begin_row
|
155
337
|
# appender.append(1)
|
156
338
|
# appender.append('Alice')
|
157
339
|
# appender.end_row
|
158
|
-
#
|
159
340
|
def append(value)
|
160
341
|
case value
|
161
342
|
when NilClass
|
@@ -188,20 +369,16 @@ module DuckDB
|
|
188
369
|
end
|
189
370
|
end
|
190
371
|
|
191
|
-
#
|
192
372
|
# append a row.
|
193
373
|
#
|
194
374
|
# appender.append_row(1, 'Alice')
|
195
375
|
#
|
196
376
|
# is same as:
|
197
377
|
#
|
198
|
-
# appender.
|
199
|
-
# appender.append(1)
|
378
|
+
# appender.append(2)
|
200
379
|
# appender.append('Alice')
|
201
380
|
# appender.end_row
|
202
|
-
#
|
203
381
|
def append_row(*args)
|
204
|
-
begin_row
|
205
382
|
args.each do |arg|
|
206
383
|
append(arg)
|
207
384
|
end
|
@@ -210,35 +387,21 @@ module DuckDB
|
|
210
387
|
|
211
388
|
private
|
212
389
|
|
213
|
-
def
|
214
|
-
|
390
|
+
def raise_appender_error(default_message) # :nodoc:
|
391
|
+
message = error_message
|
392
|
+
raise DuckDB::Error, message || default_message
|
215
393
|
end
|
216
394
|
|
217
|
-
def
|
218
|
-
|
219
|
-
when Date, Time
|
220
|
-
value
|
221
|
-
else
|
222
|
-
begin
|
223
|
-
Date.parse(value)
|
224
|
-
rescue StandardError
|
225
|
-
raise(ArgumentError, "Cannot parse argument `#{value}` to Date.")
|
226
|
-
end
|
227
|
-
end
|
395
|
+
def blob?(value) # :nodoc:
|
396
|
+
value.instance_of?(DuckDB::Blob) || value.encoding == Encoding::BINARY
|
228
397
|
end
|
229
398
|
|
230
|
-
def to_time(value)
|
399
|
+
def to_time(value) # :nodoc:
|
231
400
|
case value
|
232
|
-
when Time
|
233
|
-
value
|
234
401
|
when Date
|
235
402
|
value.to_time
|
236
403
|
else
|
237
|
-
|
238
|
-
Time.parse(value)
|
239
|
-
rescue StandardError
|
240
|
-
raise(ArgumentError, "Cannot parse argument `#{value}` to Time or Date.")
|
241
|
-
end
|
404
|
+
_parse_time(value)
|
242
405
|
end
|
243
406
|
end
|
244
407
|
end
|
data/lib/duckdb/column.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module DuckDB
|
4
4
|
class Column
|
5
|
-
#
|
6
5
|
# returns column type symbol
|
7
6
|
# `:unknown` means that the column type is unknown/unsupported by ruby-duckdb.
|
8
7
|
# `:invalid` means that the column type is invalid in duckdb.
|
@@ -15,7 +14,6 @@ module DuckDB
|
|
15
14
|
# users = con.query('SELECT * FROM users')
|
16
15
|
# columns = users.columns
|
17
16
|
# columns.first.type #=> :integer
|
18
|
-
#
|
19
17
|
def type
|
20
18
|
type_id = _type
|
21
19
|
DuckDB::Converter::IntToSym.type_to_sym(type_id)
|
data/lib/duckdb/connection.rb
CHANGED
@@ -8,7 +8,6 @@ module DuckDB
|
|
8
8
|
# con = db.connect
|
9
9
|
# con.query(sql)
|
10
10
|
class Connection
|
11
|
-
#
|
12
11
|
# executes sql with args.
|
13
12
|
# The first argument sql must be SQL string.
|
14
13
|
# The rest arguments are parameters of SQL string.
|
@@ -24,7 +23,6 @@ module DuckDB
|
|
24
23
|
#
|
25
24
|
# sql = 'SELECT * FROM users WHERE name = $name AND email = $email'
|
26
25
|
# dave = con.query(sql, name: 'Dave', email: 'dave@example.com')
|
27
|
-
#
|
28
26
|
def query(sql, *args, **kwargs)
|
29
27
|
return query_multi_sql(sql) if args.empty? && kwargs.empty?
|
30
28
|
|
@@ -39,13 +37,13 @@ module DuckDB
|
|
39
37
|
result = nil
|
40
38
|
stmts.each do |stmt|
|
41
39
|
result = stmt.execute
|
40
|
+
stmt.destroy
|
42
41
|
end
|
43
42
|
result
|
44
43
|
ensure
|
45
44
|
stmts&.destroy
|
46
45
|
end
|
47
46
|
|
48
|
-
#
|
49
47
|
# executes sql with args asynchronously.
|
50
48
|
# The first argument sql must be SQL string.
|
51
49
|
# The rest arguments are parameters of SQL string.
|
@@ -60,7 +58,6 @@ module DuckDB
|
|
60
58
|
# pending_result.execute_task while pending_result.state == :not_ready
|
61
59
|
# result = pending_result.execute_pending
|
62
60
|
# result.each.first
|
63
|
-
#
|
64
61
|
def async_query(sql, *args, **kwargs)
|
65
62
|
prepare(sql) do |stmt|
|
66
63
|
stmt.bind_args(*args, **kwargs)
|
@@ -68,7 +65,6 @@ module DuckDB
|
|
68
65
|
end
|
69
66
|
end
|
70
67
|
|
71
|
-
#
|
72
68
|
# executes sql with args asynchronously and provides streaming result.
|
73
69
|
# The first argument sql must be SQL string.
|
74
70
|
# The rest arguments are parameters of SQL string.
|
@@ -84,7 +80,6 @@ module DuckDB
|
|
84
80
|
# pending_result.execute_task while pending_result.state == :not_ready
|
85
81
|
# result = pending_result.execute_pending
|
86
82
|
# result.each.first
|
87
|
-
#
|
88
83
|
def async_query_stream(sql, *args, **kwargs)
|
89
84
|
prepare(sql) do |stmt|
|
90
85
|
stmt.bind_args(*args, **kwargs)
|
@@ -92,10 +87,8 @@ module DuckDB
|
|
92
87
|
end
|
93
88
|
end
|
94
89
|
|
95
|
-
#
|
96
90
|
# connects DuckDB database
|
97
91
|
# The first argument is DuckDB::Database object
|
98
|
-
#
|
99
92
|
def connect(db)
|
100
93
|
conn = _connect(db)
|
101
94
|
return conn unless block_given?
|
@@ -107,7 +100,6 @@ module DuckDB
|
|
107
100
|
end
|
108
101
|
end
|
109
102
|
|
110
|
-
#
|
111
103
|
# returns PreparedStatement object.
|
112
104
|
# The first argument is SQL string.
|
113
105
|
# If block is given, the block is executed with PreparedStatement object
|
@@ -127,17 +119,14 @@ module DuckDB
|
|
127
119
|
# stmt.bind_args(name: 'Dave', email: 'dave@example.com')
|
128
120
|
# stmt.execute
|
129
121
|
# end
|
130
|
-
#
|
131
122
|
def prepared_statement(str, &)
|
132
123
|
return PreparedStatement.new(self, str) unless block_given?
|
133
124
|
|
134
125
|
PreparedStatement.prepare(self, str, &)
|
135
126
|
end
|
136
127
|
|
137
|
-
#
|
138
128
|
# returns Appender object.
|
139
129
|
# The first argument is table name
|
140
|
-
#
|
141
130
|
def appender(table)
|
142
131
|
appender = create_appender(table)
|
143
132
|
|
data/lib/duckdb/database.rb
CHANGED
@@ -20,13 +20,11 @@ module DuckDB
|
|
20
20
|
# result.each do |row|
|
21
21
|
# p row
|
22
22
|
# end
|
23
|
-
#
|
24
23
|
class Database
|
25
24
|
private_class_method :_open
|
26
25
|
private_class_method :_open_ext
|
27
26
|
|
28
27
|
class << self
|
29
|
-
##
|
30
28
|
# Opens database.
|
31
29
|
# The first argument is DuckDB database file path to open.
|
32
30
|
# If there is no argument, the method opens DuckDB database in memory.
|
@@ -40,7 +38,6 @@ module DuckDB
|
|
40
38
|
# con = db.connect
|
41
39
|
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
42
40
|
# end
|
43
|
-
#
|
44
41
|
def open(dbpath = nil, config = nil)
|
45
42
|
db = _db_open(dbpath, config)
|
46
43
|
return db unless block_given?
|
@@ -54,7 +51,7 @@ module DuckDB
|
|
54
51
|
|
55
52
|
private
|
56
53
|
|
57
|
-
def _db_open(dbpath, config)
|
54
|
+
def _db_open(dbpath, config) # :nodoc:
|
58
55
|
if config
|
59
56
|
_open_ext(dbpath, config)
|
60
57
|
else
|
@@ -63,7 +60,6 @@ module DuckDB
|
|
63
60
|
end
|
64
61
|
end
|
65
62
|
|
66
|
-
##
|
67
63
|
# connects database.
|
68
64
|
#
|
69
65
|
# The method yields block and disconnects the database if block given
|
@@ -75,7 +71,6 @@ module DuckDB
|
|
75
71
|
# db.connect do |con|
|
76
72
|
# con.query('CREATE TABLE users (id INTEGER, name VARCHAR(30))')
|
77
73
|
# end
|
78
|
-
#
|
79
74
|
def connect
|
80
75
|
conn = _connect
|
81
76
|
return conn unless block_given?
|
data/lib/duckdb/interval.rb
CHANGED
@@ -24,11 +24,11 @@ module DuckDB
|
|
24
24
|
# con.query('CREATE TABLE intervals (interval_value INTERVAL)')
|
25
25
|
# appender = con.appender('intervals')
|
26
26
|
# appender
|
27
|
-
# .begin_row
|
28
27
|
# .append_interval(interval)
|
29
28
|
# .end_row
|
30
29
|
# .flush
|
31
30
|
class Interval
|
31
|
+
# :stopdoc:
|
32
32
|
ISO8601_REGEXP = Regexp.compile(
|
33
33
|
'(?<negativ>-{0,1})P
|
34
34
|
(?<year>-{0,1}\d+Y){0,1}
|
@@ -40,6 +40,8 @@ module DuckDB
|
|
40
40
|
((?<sec>-{0,1}\d+)\.{0,1}(?<usec>\d*)S){0,1}',
|
41
41
|
Regexp::EXTENDED
|
42
42
|
)
|
43
|
+
private_constant :ISO8601_REGEXP
|
44
|
+
# :startdoc:
|
43
45
|
|
44
46
|
class << self
|
45
47
|
# parses the ISO8601 format string and return the Interval object.
|
@@ -93,7 +95,7 @@ module DuckDB
|
|
93
95
|
|
94
96
|
private
|
95
97
|
|
96
|
-
def matched_to_i(matched)
|
98
|
+
def matched_to_i(matched) # :nodoc:
|
97
99
|
sign = to_sign(matched)
|
98
100
|
sec = to_sec(matched)
|
99
101
|
usec = to_usec(matched)
|
@@ -104,35 +106,35 @@ module DuckDB
|
|
104
106
|
sign.positive? ? value : value.map { |v| v * sign }
|
105
107
|
end
|
106
108
|
|
107
|
-
def to_sign(matched)
|
109
|
+
def to_sign(matched) # :nodoc:
|
108
110
|
matched[:negativ] == '-' ? -1 : 1
|
109
111
|
end
|
110
112
|
|
111
|
-
def to_year(matched)
|
113
|
+
def to_year(matched) # :nodoc:
|
112
114
|
matched[:year].to_i
|
113
115
|
end
|
114
116
|
|
115
|
-
def to_month(matched)
|
117
|
+
def to_month(matched) # :nodoc:
|
116
118
|
matched[:month].to_i
|
117
119
|
end
|
118
120
|
|
119
|
-
def to_day(matched)
|
121
|
+
def to_day(matched) # :nodoc:
|
120
122
|
matched[:day].to_i
|
121
123
|
end
|
122
124
|
|
123
|
-
def to_hour(matched)
|
125
|
+
def to_hour(matched) # :nodoc:
|
124
126
|
matched[:hour].to_i
|
125
127
|
end
|
126
128
|
|
127
|
-
def to_min(matched)
|
129
|
+
def to_min(matched) # :nodoc:
|
128
130
|
matched[:min].to_i
|
129
131
|
end
|
130
132
|
|
131
|
-
def to_sec(matched)
|
133
|
+
def to_sec(matched) # :nodoc:
|
132
134
|
matched[:sec].to_i
|
133
135
|
end
|
134
136
|
|
135
|
-
def to_usec(matched)
|
137
|
+
def to_usec(matched) # :nodoc:
|
136
138
|
matched[:usec].to_s.ljust(6, '0')[0, 6].to_i
|
137
139
|
end
|
138
140
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DuckDB
|
4
|
+
class LogicalType
|
5
|
+
# returns logical type's type symbol
|
6
|
+
# `:unknown` means that the logical type's type is unknown/unsupported by ruby-duckdb.
|
7
|
+
# `:invalid` means that the logical type's type is invalid in duckdb.
|
8
|
+
#
|
9
|
+
# require 'duckdb'
|
10
|
+
# db = DuckDB::Database.open
|
11
|
+
# con = db.connect
|
12
|
+
# con.query('CREATE TABLE climates (id INTEGER, temperature DECIMAIL)')
|
13
|
+
#
|
14
|
+
# users = con.query('SELECT * FROM climates')
|
15
|
+
# columns = users.columns
|
16
|
+
# columns.second.logical_type.type #=> :decimal
|
17
|
+
def type
|
18
|
+
type_id = _type
|
19
|
+
DuckDB::Converter::IntToSym.type_to_sym(type_id)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -19,7 +19,7 @@ module DuckDB
|
|
19
19
|
# end
|
20
20
|
# result = pending_result.execute_pending
|
21
21
|
class PendingResult
|
22
|
-
STATES = %i[ready not_ready error no_tasks].freeze
|
22
|
+
STATES = %i[ready not_ready error no_tasks].freeze # :nodoc:
|
23
23
|
|
24
24
|
# returns the state of the pending result.
|
25
25
|
# the result can be :ready, :not_ready, :error, :no_tasks.
|