duckdb 0.9.1.1 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitattributes +1 -0
- data/.github/workflows/test_on_macos.yml +6 -6
- data/.github/workflows/test_on_ubuntu.yml +6 -6
- data/.github/workflows/test_on_windows.yml +4 -4
- data/CHANGELOG.md +11 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +5 -5
- data/README.md +17 -1
- data/benchmark/async_query.rb +90 -0
- data/ext/duckdb/appender.c +5 -5
- data/ext/duckdb/appender.h +1 -1
- data/ext/duckdb/blob.c +1 -1
- data/ext/duckdb/blob.h +1 -4
- data/ext/duckdb/column.c +2 -2
- data/ext/duckdb/column.h +2 -2
- data/ext/duckdb/config.c +1 -1
- data/ext/duckdb/config.h +1 -1
- data/ext/duckdb/connection.c +66 -6
- data/ext/duckdb/connection.h +2 -2
- data/ext/duckdb/converter.h +1 -1
- data/ext/duckdb/conveter.c +1 -1
- data/ext/duckdb/database.c +3 -3
- data/ext/duckdb/database.h +2 -2
- data/ext/duckdb/duckdb.c +11 -11
- data/ext/duckdb/error.c +1 -1
- data/ext/duckdb/error.h +1 -1
- data/ext/duckdb/extconf.rb +46 -13
- data/ext/duckdb/pending_result.c +45 -6
- data/ext/duckdb/pending_result.h +1 -1
- data/ext/duckdb/prepared_statement.c +7 -7
- data/ext/duckdb/prepared_statement.h +1 -1
- data/ext/duckdb/result.c +112 -70
- data/ext/duckdb/result.h +2 -2
- data/ext/duckdb/ruby-duckdb.h +1 -0
- data/ext/duckdb/util.c +4 -4
- data/ext/duckdb/util.h +4 -4
- data/lib/duckdb/appender.rb +1 -10
- data/lib/duckdb/connection.rb +50 -8
- data/lib/duckdb/converter.rb +27 -1
- data/lib/duckdb/prepared_statement.rb +42 -40
- data/lib/duckdb/result.rb +8 -2
- data/lib/duckdb/version.rb +1 -1
- data/sample/async_query.rb +24 -0
- data/sample/async_query_stream.rb +24 -0
- metadata +6 -2
data/ext/duckdb/extconf.rb
CHANGED
@@ -1,31 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'mkmf'
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
DUCKDB_REQUIRED_VERSION = '0.8.0'
|
6
|
+
|
7
|
+
def check_duckdb_header(header, version)
|
8
|
+
found = find_header(
|
9
|
+
header,
|
10
|
+
'/opt/homebrew/include',
|
11
|
+
'/opt/homebrew/opt/duckdb/include',
|
12
|
+
'/opt/local/include'
|
13
|
+
)
|
14
|
+
return if found
|
15
|
+
|
16
|
+
msg = "#{header} is not found. Install #{header} of duckdb >= #{version}."
|
17
|
+
print_message(msg)
|
18
|
+
raise msg
|
7
19
|
end
|
8
20
|
|
9
|
-
def check_duckdb_library(func, version)
|
10
|
-
|
21
|
+
def check_duckdb_library(library, func, version)
|
22
|
+
found = find_library(
|
23
|
+
library,
|
24
|
+
func,
|
25
|
+
'/opt/homebrew/lib',
|
26
|
+
'/opt/homebrew/opt/duckdb/lib',
|
27
|
+
'/opt/local/lib'
|
28
|
+
)
|
29
|
+
return if found
|
11
30
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
puts msg
|
16
|
-
puts '*' * 80
|
17
|
-
puts ''
|
31
|
+
library_name = duckdb_library_name(library)
|
32
|
+
msg = "#{library_name} is not found. Install #{library_name} of duckdb >= #{version}."
|
33
|
+
print_message(msg)
|
18
34
|
raise msg
|
19
35
|
end
|
20
36
|
|
37
|
+
def duckdb_library_name(library)
|
38
|
+
"lib#{library}.(so|dylib|dll)"
|
39
|
+
end
|
40
|
+
|
41
|
+
def print_message(msg)
|
42
|
+
print <<~END_OF_MESSAGE
|
43
|
+
|
44
|
+
#{'*' * 80}
|
45
|
+
#{msg}
|
46
|
+
#{'*' * 80}
|
47
|
+
|
48
|
+
END_OF_MESSAGE
|
49
|
+
end
|
50
|
+
|
21
51
|
dir_config('duckdb')
|
22
52
|
|
53
|
+
check_duckdb_header('duckdb.h', DUCKDB_REQUIRED_VERSION)
|
54
|
+
|
23
55
|
# check duckdb >= 0.8.0
|
24
|
-
check_duckdb_library('
|
56
|
+
check_duckdb_library('duckdb', 'duckdb_string_is_inlined', DUCKDB_REQUIRED_VERSION)
|
25
57
|
|
26
58
|
# check duckdb >= 0.9.0
|
27
59
|
have_func('duckdb_bind_parameter_index', 'duckdb.h')
|
28
60
|
|
61
|
+
# duckdb_parameter_name is not found on Windows.
|
29
62
|
have_func('duckdb_parameter_name', 'duckdb.h')
|
30
63
|
|
31
64
|
create_makefile('duckdb/duckdb_native')
|
data/ext/duckdb/pending_result.c
CHANGED
@@ -5,7 +5,7 @@ static VALUE cDuckDBPendingResult;
|
|
5
5
|
static void deallocate(void *ctx);
|
6
6
|
static VALUE allocate(VALUE klass);
|
7
7
|
static size_t memsize(const void *p);
|
8
|
-
static VALUE duckdb_pending_result_initialize(VALUE
|
8
|
+
static VALUE duckdb_pending_result_initialize(int argc, VALUE *args, VALUE self);
|
9
9
|
static VALUE duckdb_pending_result_execute_task(VALUE self);
|
10
10
|
static VALUE duckdb_pending_result_execute_pending(VALUE self);
|
11
11
|
|
@@ -38,16 +38,43 @@ static size_t memsize(const void *p) {
|
|
38
38
|
return sizeof(rubyDuckDBPendingResult);
|
39
39
|
}
|
40
40
|
|
41
|
-
static VALUE duckdb_pending_result_initialize(VALUE
|
41
|
+
static VALUE duckdb_pending_result_initialize(int argc, VALUE *argv, VALUE self) {
|
42
|
+
VALUE oDuckDBPreparedStatement;
|
43
|
+
VALUE streaming_p = Qfalse;
|
44
|
+
duckdb_state state;
|
45
|
+
|
46
|
+
rb_scan_args(argc, argv, "11", &oDuckDBPreparedStatement, &streaming_p);
|
47
|
+
|
48
|
+
if (rb_obj_is_kind_of(oDuckDBPreparedStatement, cDuckDBPreparedStatement) != Qtrue) {
|
49
|
+
rb_raise(rb_eTypeError, "1st argument must be DuckDB::PreparedStatement");
|
50
|
+
}
|
51
|
+
|
42
52
|
rubyDuckDBPendingResult *ctx = get_struct_pending_result(self);
|
43
53
|
rubyDuckDBPreparedStatement *stmt = get_struct_prepared_statement(oDuckDBPreparedStatement);
|
44
54
|
|
45
|
-
if (
|
55
|
+
if (!NIL_P(streaming_p) && streaming_p == Qtrue) {
|
56
|
+
state = duckdb_pending_prepared_streaming(stmt->prepared_statement, &(ctx->pending_result));
|
57
|
+
} else {
|
58
|
+
state = duckdb_pending_prepared(stmt->prepared_statement, &(ctx->pending_result));
|
59
|
+
}
|
60
|
+
|
61
|
+
if (state == DuckDBError) {
|
46
62
|
rb_raise(eDuckDBError, "%s", duckdb_pending_error(ctx->pending_result));
|
47
63
|
}
|
48
64
|
return self;
|
49
65
|
}
|
50
66
|
|
67
|
+
/*
|
68
|
+
* call-seq:
|
69
|
+
* pending_result.execute_task -> nil
|
70
|
+
*
|
71
|
+
* Executes the task in the pending result.
|
72
|
+
*
|
73
|
+
* db = DuckDB::Database.open
|
74
|
+
* conn = db.connect
|
75
|
+
* pending_result = conn.async_query("slow query")
|
76
|
+
* pending_result.execute_task
|
77
|
+
*/
|
51
78
|
static VALUE duckdb_pending_result_execute_task(VALUE self) {
|
52
79
|
rubyDuckDBPendingResult *ctx = get_struct_pending_result(self);
|
53
80
|
ctx->state = duckdb_pending_execute_task(ctx->pending_result);
|
@@ -61,10 +88,22 @@ static VALUE duckdb_pending_result_execution_finished_p(VALUE self) {
|
|
61
88
|
}
|
62
89
|
#endif
|
63
90
|
|
91
|
+
/*
|
92
|
+
* call-seq:
|
93
|
+
* pending_result.execute_pending -> DuckDB::Result
|
94
|
+
*
|
95
|
+
* Get DuckDB::Result object after query execution finished.
|
96
|
+
*
|
97
|
+
* db = DuckDB::Database.open
|
98
|
+
* conn = db.connect
|
99
|
+
* pending_result = conn.async_query("slow query")
|
100
|
+
* pending_result.execute_task while pending_result.state != :ready
|
101
|
+
* result = pending_result.execute_pending # => DuckDB::Result
|
102
|
+
*/
|
64
103
|
static VALUE duckdb_pending_result_execute_pending(VALUE self) {
|
65
104
|
rubyDuckDBPendingResult *ctx;
|
66
105
|
rubyDuckDBResult *ctxr;
|
67
|
-
VALUE result =
|
106
|
+
VALUE result = rbduckdb_create_result();
|
68
107
|
|
69
108
|
TypedData_Get_Struct(self, rubyDuckDBPendingResult, &pending_result_data_type, ctx);
|
70
109
|
ctxr = get_struct_result(result);
|
@@ -85,11 +124,11 @@ rubyDuckDBPendingResult *get_struct_pending_result(VALUE obj) {
|
|
85
124
|
return ctx;
|
86
125
|
}
|
87
126
|
|
88
|
-
void
|
127
|
+
void rbduckdb_init_duckdb_pending_result(void) {
|
89
128
|
cDuckDBPendingResult = rb_define_class_under(mDuckDB, "PendingResult", rb_cObject);
|
90
129
|
rb_define_alloc_func(cDuckDBPendingResult, allocate);
|
91
130
|
|
92
|
-
rb_define_method(cDuckDBPendingResult, "initialize", duckdb_pending_result_initialize, 1);
|
131
|
+
rb_define_method(cDuckDBPendingResult, "initialize", duckdb_pending_result_initialize, -1);
|
93
132
|
rb_define_method(cDuckDBPendingResult, "execute_task", duckdb_pending_result_execute_task, 0);
|
94
133
|
rb_define_method(cDuckDBPendingResult, "execute_pending", duckdb_pending_result_execute_pending, 0);
|
95
134
|
|
data/ext/duckdb/pending_result.h
CHANGED
@@ -9,5 +9,5 @@ struct _rubyDuckDBPendingResult {
|
|
9
9
|
typedef struct _rubyDuckDBPendingResult rubyDuckDBPendingResult;
|
10
10
|
|
11
11
|
rubyDuckDBPendingResult *get_struct_pending_result(VALUE obj);
|
12
|
-
void
|
12
|
+
void rbduckdb_init_duckdb_pending_result(void);
|
13
13
|
#endif
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#include "ruby-duckdb.h"
|
2
2
|
|
3
|
-
|
3
|
+
VALUE cDuckDBPreparedStatement;
|
4
4
|
|
5
5
|
static void deallocate(void *ctx);
|
6
6
|
static VALUE allocate(VALUE klass);
|
@@ -83,7 +83,7 @@ static VALUE duckdb_prepared_statement_nparams(VALUE self) {
|
|
83
83
|
static VALUE duckdb_prepared_statement_execute(VALUE self) {
|
84
84
|
rubyDuckDBPreparedStatement *ctx;
|
85
85
|
rubyDuckDBResult *ctxr;
|
86
|
-
VALUE result =
|
86
|
+
VALUE result = rbduckdb_create_result();
|
87
87
|
|
88
88
|
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
89
89
|
ctxr = get_struct_result(result);
|
@@ -268,7 +268,7 @@ static VALUE duckdb_prepared_statement__bind_date(VALUE self, VALUE vidx, VALUE
|
|
268
268
|
duckdb_date dt;
|
269
269
|
idx_t idx = check_index(vidx);
|
270
270
|
|
271
|
-
dt =
|
271
|
+
dt = rbduckdb_to_duckdb_date_from_value(year, month, day);
|
272
272
|
|
273
273
|
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
274
274
|
|
@@ -285,7 +285,7 @@ static VALUE duckdb_prepared_statement__bind_time(VALUE self, VALUE vidx, VALUE
|
|
285
285
|
|
286
286
|
idx_t idx = check_index(vidx);
|
287
287
|
|
288
|
-
time =
|
288
|
+
time = rbduckdb_to_duckdb_time_from_value(hour, min, sec, micros);
|
289
289
|
|
290
290
|
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
291
291
|
|
@@ -301,7 +301,7 @@ static VALUE duckdb_prepared_statement__bind_timestamp(VALUE self, VALUE vidx, V
|
|
301
301
|
rubyDuckDBPreparedStatement *ctx;
|
302
302
|
idx_t idx = check_index(vidx);
|
303
303
|
|
304
|
-
timestamp =
|
304
|
+
timestamp = rbduckdb_to_duckdb_timestamp_from_value(year, month, day, hour, min, sec, micros);
|
305
305
|
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
306
306
|
|
307
307
|
if (duckdb_bind_timestamp(ctx->prepared_statement, idx, timestamp) == DuckDBError) {
|
@@ -317,7 +317,7 @@ static VALUE duckdb_prepared_statement__bind_interval(VALUE self, VALUE vidx, VA
|
|
317
317
|
|
318
318
|
TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
|
319
319
|
|
320
|
-
|
320
|
+
rbduckdb_to_duckdb_interval_from_value(&interval, months, days, micros);
|
321
321
|
|
322
322
|
if (duckdb_bind_interval(ctx->prepared_statement, idx, interval) == DuckDBError) {
|
323
323
|
rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
|
@@ -347,7 +347,7 @@ rubyDuckDBPreparedStatement *get_struct_prepared_statement(VALUE self) {
|
|
347
347
|
return ctx;
|
348
348
|
}
|
349
349
|
|
350
|
-
void
|
350
|
+
void rbduckdb_init_duckdb_prepared_statement(void) {
|
351
351
|
cDuckDBPreparedStatement = rb_define_class_under(mDuckDB, "PreparedStatement", rb_cObject);
|
352
352
|
|
353
353
|
rb_define_alloc_func(cDuckDBPreparedStatement, allocate);
|
@@ -9,6 +9,6 @@ struct _rubyDuckDBPreparedStatement {
|
|
9
9
|
typedef struct _rubyDuckDBPreparedStatement rubyDuckDBPreparedStatement;
|
10
10
|
|
11
11
|
rubyDuckDBPreparedStatement *get_struct_prepared_statement(VALUE self);
|
12
|
-
void
|
12
|
+
void rbduckdb_init_duckdb_prepared_statement(void);
|
13
13
|
|
14
14
|
#endif
|
data/ext/duckdb/result.c
CHANGED
@@ -19,6 +19,11 @@ static VALUE duckdb_result_column_count(VALUE oDuckDBResult);
|
|
19
19
|
static VALUE duckdb_result_row_count(VALUE oDuckDBResult);
|
20
20
|
static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult);
|
21
21
|
static VALUE duckdb_result_columns(VALUE oDuckDBResult);
|
22
|
+
static VALUE duckdb_result_streaming_p(VALUE oDuckDBResult);
|
23
|
+
static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult);
|
24
|
+
|
25
|
+
static VALUE duckdb_result__chunk_stream(VALUE oDuckDBResult);
|
26
|
+
static void yield_rows(duckdb_data_chunk chunk, idx_t col_count);
|
22
27
|
static VALUE duckdb_result__column_type(VALUE oDuckDBResult, VALUE col_idx);
|
23
28
|
static VALUE duckdb_result__is_null(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx);
|
24
29
|
static VALUE duckdb_result__to_boolean(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx);
|
@@ -50,7 +55,6 @@ static VALUE vector_map(duckdb_logical_type ty, duckdb_vector vector, idx_t row_
|
|
50
55
|
static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx);
|
51
56
|
static VALUE vector_uuid(void* vector_data, idx_t row_idx);
|
52
57
|
static VALUE vector_value(duckdb_vector vector, idx_t row_idx);
|
53
|
-
static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult);
|
54
58
|
|
55
59
|
static const rb_data_type_t result_data_type = {
|
56
60
|
"DuckDB/Result",
|
@@ -229,12 +233,85 @@ static VALUE duckdb_result_columns(VALUE oDuckDBResult) {
|
|
229
233
|
|
230
234
|
VALUE ary = rb_ary_new2(column_count);
|
231
235
|
for(col_idx = 0; col_idx < column_count; col_idx++) {
|
232
|
-
VALUE column =
|
236
|
+
VALUE column = rbduckdb_create_column(oDuckDBResult, col_idx);
|
233
237
|
rb_ary_store(ary, col_idx, column);
|
234
238
|
}
|
235
239
|
return ary;
|
236
240
|
}
|
237
241
|
|
242
|
+
/*
|
243
|
+
* call-seq:
|
244
|
+
* result.streaming? -> Boolean
|
245
|
+
*
|
246
|
+
* Returns true if the result is streaming, otherwise false.
|
247
|
+
*
|
248
|
+
*/
|
249
|
+
static VALUE duckdb_result_streaming_p(VALUE oDuckDBResult) {
|
250
|
+
rubyDuckDBResult *ctx;
|
251
|
+
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
252
|
+
return duckdb_result_is_streaming(ctx->result) ? Qtrue : Qfalse;
|
253
|
+
}
|
254
|
+
|
255
|
+
static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult) {
|
256
|
+
rubyDuckDBResult *ctx;
|
257
|
+
idx_t col_count;
|
258
|
+
idx_t chunk_count;
|
259
|
+
idx_t chunk_idx;
|
260
|
+
duckdb_data_chunk chunk;
|
261
|
+
|
262
|
+
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
263
|
+
|
264
|
+
col_count = duckdb_column_count(&(ctx->result));
|
265
|
+
chunk_count = duckdb_result_chunk_count(ctx->result);
|
266
|
+
|
267
|
+
RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
|
268
|
+
|
269
|
+
for (chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) {
|
270
|
+
chunk = duckdb_result_get_chunk(ctx->result, chunk_idx);
|
271
|
+
yield_rows(chunk, col_count);
|
272
|
+
duckdb_destroy_data_chunk(&chunk);
|
273
|
+
}
|
274
|
+
return Qnil;
|
275
|
+
}
|
276
|
+
|
277
|
+
static VALUE duckdb_result__chunk_stream(VALUE oDuckDBResult) {
|
278
|
+
rubyDuckDBResult *ctx;
|
279
|
+
duckdb_data_chunk chunk;
|
280
|
+
idx_t col_count;
|
281
|
+
|
282
|
+
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
283
|
+
|
284
|
+
RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
|
285
|
+
|
286
|
+
col_count = duckdb_column_count(&(ctx->result));
|
287
|
+
|
288
|
+
while((chunk = duckdb_stream_fetch_chunk(ctx->result)) != NULL) {
|
289
|
+
yield_rows(chunk, col_count);
|
290
|
+
duckdb_destroy_data_chunk(&chunk);
|
291
|
+
}
|
292
|
+
return Qnil;
|
293
|
+
}
|
294
|
+
|
295
|
+
static void yield_rows(duckdb_data_chunk chunk, idx_t col_count) {
|
296
|
+
idx_t row_count;
|
297
|
+
idx_t row_idx;
|
298
|
+
idx_t col_idx;
|
299
|
+
duckdb_vector vector;
|
300
|
+
VALUE row;
|
301
|
+
VALUE val;
|
302
|
+
|
303
|
+
row_count = duckdb_data_chunk_get_size(chunk);
|
304
|
+
for (row_idx = 0; row_idx < row_count; row_idx++) {
|
305
|
+
row = rb_ary_new2(col_count);
|
306
|
+
for (col_idx = 0; col_idx < col_count; col_idx++) {
|
307
|
+
vector = duckdb_data_chunk_get_vector(chunk, col_idx);
|
308
|
+
val = vector_value(vector, row_idx);
|
309
|
+
rb_ary_store(row, col_idx, val);
|
310
|
+
}
|
311
|
+
rb_yield(row);
|
312
|
+
}
|
313
|
+
}
|
314
|
+
|
238
315
|
static VALUE duckdb_result__column_type(VALUE oDuckDBResult, VALUE col_idx) {
|
239
316
|
rubyDuckDBResult *ctx;
|
240
317
|
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
@@ -397,7 +474,7 @@ static VALUE duckdb_result__enum_dictionary_value(VALUE oDuckDBResult, VALUE col
|
|
397
474
|
return value;
|
398
475
|
}
|
399
476
|
|
400
|
-
VALUE
|
477
|
+
VALUE rbduckdb_create_result(void) {
|
401
478
|
return allocate(cDuckDBResult);
|
402
479
|
}
|
403
480
|
|
@@ -405,32 +482,32 @@ static VALUE vector_date(void *vector_data, idx_t row_idx) {
|
|
405
482
|
duckdb_date_struct date = duckdb_from_date(((duckdb_date *) vector_data)[row_idx]);
|
406
483
|
|
407
484
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_date"), 3,
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
485
|
+
INT2FIX(date.year),
|
486
|
+
INT2FIX(date.month),
|
487
|
+
INT2FIX(date.day)
|
488
|
+
);
|
412
489
|
}
|
413
490
|
|
414
491
|
static VALUE vector_timestamp(void* vector_data, idx_t row_idx) {
|
415
492
|
duckdb_timestamp_struct data = duckdb_from_timestamp(((duckdb_timestamp *)vector_data)[row_idx]);
|
416
493
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_time"), 7,
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
494
|
+
INT2FIX(data.date.year),
|
495
|
+
INT2FIX(data.date.month),
|
496
|
+
INT2FIX(data.date.day),
|
497
|
+
INT2FIX(data.time.hour),
|
498
|
+
INT2FIX(data.time.min),
|
499
|
+
INT2FIX(data.time.sec),
|
500
|
+
INT2NUM(data.time.micros)
|
501
|
+
);
|
425
502
|
}
|
426
503
|
|
427
504
|
static VALUE vector_interval(void* vector_data, idx_t row_idx) {
|
428
505
|
duckdb_interval data = ((duckdb_interval *)vector_data)[row_idx];
|
429
506
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_interval_from_vector"), 3,
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
507
|
+
INT2NUM(data.months),
|
508
|
+
INT2NUM(data.days),
|
509
|
+
LL2NUM(data.micros)
|
510
|
+
);
|
434
511
|
}
|
435
512
|
|
436
513
|
static VALUE vector_blob(void* vector_data, idx_t row_idx) {
|
@@ -454,9 +531,9 @@ static VALUE vector_varchar(void* vector_data, idx_t row_idx) {
|
|
454
531
|
static VALUE vector_hugeint(void* vector_data, idx_t row_idx) {
|
455
532
|
duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
|
456
533
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_hugeint_from_vector"), 2,
|
457
|
-
|
458
|
-
|
459
|
-
|
534
|
+
ULL2NUM(hugeint.lower),
|
535
|
+
LL2NUM(hugeint.upper)
|
536
|
+
);
|
460
537
|
}
|
461
538
|
|
462
539
|
static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
|
@@ -477,11 +554,11 @@ static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row
|
|
477
554
|
}
|
478
555
|
|
479
556
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_decimal_from_vector"), 4,
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
557
|
+
INT2FIX(width),
|
558
|
+
INT2FIX(scale),
|
559
|
+
ULL2NUM(value.lower),
|
560
|
+
LL2NUM(value.upper)
|
561
|
+
);
|
485
562
|
}
|
486
563
|
|
487
564
|
static VALUE vector_enum(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
|
@@ -577,9 +654,9 @@ static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t r
|
|
577
654
|
static VALUE vector_uuid(void* vector_data, idx_t row_idx) {
|
578
655
|
duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
|
579
656
|
return rb_funcall(mDuckDBConverter, rb_intern("_to_uuid_from_vector"), 2,
|
580
|
-
|
581
|
-
|
582
|
-
|
657
|
+
ULL2NUM(hugeint.lower),
|
658
|
+
LL2NUM(hugeint.upper)
|
659
|
+
);
|
583
660
|
}
|
584
661
|
|
585
662
|
static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
@@ -617,7 +694,7 @@ static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
|
617
694
|
case DUCKDB_TYPE_BIGINT:
|
618
695
|
obj = LL2NUM(((int64_t *) vector_data)[row_idx]);
|
619
696
|
break;
|
620
|
-
|
697
|
+
case DUCKDB_TYPE_UTINYINT:
|
621
698
|
obj = INT2FIX(((uint8_t *) vector_data)[row_idx]);
|
622
699
|
break;
|
623
700
|
case DUCKDB_TYPE_USMALLINT:
|
@@ -680,44 +757,7 @@ static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
|
680
757
|
return obj;
|
681
758
|
}
|
682
759
|
|
683
|
-
|
684
|
-
rubyDuckDBResult *ctx;
|
685
|
-
VALUE row;
|
686
|
-
idx_t col_count;
|
687
|
-
idx_t row_count;
|
688
|
-
idx_t chunk_count;
|
689
|
-
idx_t col_idx;
|
690
|
-
idx_t row_idx;
|
691
|
-
idx_t chunk_idx;
|
692
|
-
duckdb_data_chunk chunk;
|
693
|
-
duckdb_vector vector;
|
694
|
-
VALUE val;
|
695
|
-
|
696
|
-
TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
|
697
|
-
|
698
|
-
col_count = duckdb_column_count(&(ctx->result));
|
699
|
-
chunk_count = duckdb_result_chunk_count(ctx->result);
|
700
|
-
|
701
|
-
RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
|
702
|
-
|
703
|
-
for (chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) {
|
704
|
-
chunk = duckdb_result_get_chunk(ctx->result, chunk_idx);
|
705
|
-
row_count = duckdb_data_chunk_get_size(chunk);
|
706
|
-
for (row_idx = 0; row_idx < row_count; row_idx++) {
|
707
|
-
row = rb_ary_new2(col_count);
|
708
|
-
for (col_idx = 0; col_idx < col_count; col_idx++) {
|
709
|
-
vector = duckdb_data_chunk_get_vector(chunk, col_idx);
|
710
|
-
val = vector_value(vector, row_idx);
|
711
|
-
rb_ary_store(row, col_idx, val);
|
712
|
-
}
|
713
|
-
rb_yield(row);
|
714
|
-
}
|
715
|
-
duckdb_destroy_data_chunk(&chunk);
|
716
|
-
}
|
717
|
-
return Qnil;
|
718
|
-
}
|
719
|
-
|
720
|
-
void init_duckdb_result(void) {
|
760
|
+
void rbduckdb_init_duckdb_result(void) {
|
721
761
|
cDuckDBResult = rb_define_class_under(mDuckDB, "Result", rb_cObject);
|
722
762
|
rb_define_alloc_func(cDuckDBResult, allocate);
|
723
763
|
|
@@ -725,6 +765,9 @@ void init_duckdb_result(void) {
|
|
725
765
|
rb_define_method(cDuckDBResult, "row_count", duckdb_result_row_count, 0);
|
726
766
|
rb_define_method(cDuckDBResult, "rows_changed", duckdb_result_rows_changed, 0);
|
727
767
|
rb_define_method(cDuckDBResult, "columns", duckdb_result_columns, 0);
|
768
|
+
rb_define_method(cDuckDBResult, "streaming?", duckdb_result_streaming_p, 0);
|
769
|
+
rb_define_method(cDuckDBResult, "chunk_each", duckdb_result_chunk_each, 0);
|
770
|
+
rb_define_private_method(cDuckDBResult, "_chunk_stream", duckdb_result__chunk_stream, 0);
|
728
771
|
rb_define_private_method(cDuckDBResult, "_column_type", duckdb_result__column_type, 1);
|
729
772
|
rb_define_private_method(cDuckDBResult, "_null?", duckdb_result__is_null, 2);
|
730
773
|
rb_define_private_method(cDuckDBResult, "_to_boolean", duckdb_result__to_boolean, 2);
|
@@ -742,5 +785,4 @@ void init_duckdb_result(void) {
|
|
742
785
|
rb_define_private_method(cDuckDBResult, "_enum_internal_type", duckdb_result__enum_internal_type, 1);
|
743
786
|
rb_define_private_method(cDuckDBResult, "_enum_dictionary_size", duckdb_result__enum_dictionary_size, 1);
|
744
787
|
rb_define_private_method(cDuckDBResult, "_enum_dictionary_value", duckdb_result__enum_dictionary_value, 2);
|
745
|
-
rb_define_method(cDuckDBResult, "chunk_each", duckdb_result_chunk_each, 0);
|
746
788
|
}
|
data/ext/duckdb/result.h
CHANGED
@@ -8,8 +8,8 @@ struct _rubyDuckDBResult {
|
|
8
8
|
typedef struct _rubyDuckDBResult rubyDuckDBResult;
|
9
9
|
|
10
10
|
rubyDuckDBResult *get_struct_result(VALUE obj);
|
11
|
-
void
|
12
|
-
VALUE
|
11
|
+
void rbduckdb_init_duckdb_result(void);
|
12
|
+
VALUE rbduckdb_create_result(void);
|
13
13
|
|
14
14
|
#endif
|
15
15
|
|
data/ext/duckdb/ruby-duckdb.h
CHANGED
data/ext/duckdb/util.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#include "ruby-duckdb.h"
|
2
2
|
|
3
|
-
duckdb_date
|
3
|
+
duckdb_date rbduckdb_to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day) {
|
4
4
|
duckdb_date_struct dt_struct;
|
5
5
|
|
6
6
|
dt_struct.year = NUM2INT(year);
|
@@ -10,7 +10,7 @@ duckdb_date to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day) {
|
|
10
10
|
return duckdb_to_date(dt_struct);
|
11
11
|
}
|
12
12
|
|
13
|
-
duckdb_time
|
13
|
+
duckdb_time rbduckdb_to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
14
14
|
duckdb_time_struct time_st;
|
15
15
|
|
16
16
|
time_st.hour = NUM2INT(hour);
|
@@ -21,7 +21,7 @@ duckdb_time to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE mi
|
|
21
21
|
return duckdb_to_time(time_st);
|
22
22
|
}
|
23
23
|
|
24
|
-
duckdb_timestamp
|
24
|
+
duckdb_timestamp rbduckdb_to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros) {
|
25
25
|
duckdb_timestamp_struct timestamp_st;
|
26
26
|
|
27
27
|
timestamp_st.date.year = NUM2INT(year);
|
@@ -35,7 +35,7 @@ duckdb_timestamp to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE d
|
|
35
35
|
return duckdb_to_timestamp(timestamp_st);
|
36
36
|
}
|
37
37
|
|
38
|
-
void
|
38
|
+
void rbduckdb_to_duckdb_interval_from_value(duckdb_interval* interval, VALUE months, VALUE days, VALUE micros) {
|
39
39
|
interval->months = NUM2INT(months);
|
40
40
|
interval->days = NUM2INT(days);
|
41
41
|
interval->micros = NUM2LL(micros);
|
data/ext/duckdb/util.h
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#ifndef RUBY_DUCKDB_UTIL_H
|
2
2
|
#define RUBY_DUCKDB_UTIL_H
|
3
3
|
|
4
|
-
duckdb_date
|
5
|
-
duckdb_time
|
6
|
-
duckdb_timestamp
|
7
|
-
void
|
4
|
+
duckdb_date rbduckdb_to_duckdb_date_from_value(VALUE year, VALUE month, VALUE day);
|
5
|
+
duckdb_time rbduckdb_to_duckdb_time_from_value(VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
6
|
+
duckdb_timestamp rbduckdb_to_duckdb_timestamp_from_value(VALUE year, VALUE month, VALUE day, VALUE hour, VALUE min, VALUE sec, VALUE micros);
|
7
|
+
void rbduckdb_to_duckdb_interval_from_value(duckdb_interval* interval, VALUE months, VALUE days, VALUE micros);
|
8
8
|
|
9
9
|
#endif
|
data/lib/duckdb/appender.rb
CHANGED
@@ -86,16 +86,7 @@ module DuckDB
|
|
86
86
|
# appender.flush
|
87
87
|
#
|
88
88
|
def append_time(value)
|
89
|
-
time =
|
90
|
-
when Time
|
91
|
-
value
|
92
|
-
else
|
93
|
-
begin
|
94
|
-
Time.parse(value)
|
95
|
-
rescue
|
96
|
-
raise(ArgumentError, "Cannot parse argument `#{value}` to Time.")
|
97
|
-
end
|
98
|
-
end
|
89
|
+
time = _parse_time(value)
|
99
90
|
|
100
91
|
_append_time(time.hour, time.min, time.sec, time.usec)
|
101
92
|
end
|