duckdb 1.5.6.1 → 2.0.0.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 +19 -0
- data/README.md +1 -1
- data/ext/duckdb/aggregate_function.c +40 -78
- data/ext/duckdb/appender.c +39 -126
- data/ext/duckdb/arrow_array_stream.c +10 -2
- data/ext/duckdb/connection.c +17 -54
- data/ext/duckdb/conveter.c +39 -76
- data/ext/duckdb/expression.c +1 -4
- data/ext/duckdb/function_executor.c +214 -248
- data/ext/duckdb/function_executor.h +10 -0
- data/ext/duckdb/function_vector.c +26 -0
- data/ext/duckdb/function_vector.h +18 -0
- data/ext/duckdb/logical_type.c +88 -170
- data/ext/duckdb/pending_result.c +53 -14
- data/ext/duckdb/prepared_statement.c +37 -138
- data/ext/duckdb/result.c +160 -162
- data/ext/duckdb/result.h +2 -0
- data/ext/duckdb/scalar_function.c +9 -69
- data/ext/duckdb/table_function.c +33 -82
- data/ext/duckdb/table_function_bind_info.c +2 -12
- data/ext/duckdb/util.c +53 -2
- data/ext/duckdb/value.c +46 -20
- data/ext/duckdb/value.h +1 -0
- data/lib/duckdb/appender.rb +7 -19
- data/lib/duckdb/config.rb +2 -2
- data/lib/duckdb/connection.rb +19 -17
- data/lib/duckdb/database.rb +1 -18
- data/lib/duckdb/interval.rb +2 -28
- data/lib/duckdb/pending_result.rb +7 -0
- data/lib/duckdb/prepared_statement.rb +5 -0
- data/lib/duckdb/result.rb +0 -29
- data/lib/duckdb/scalar_function_set.rb +1 -2
- data/lib/duckdb/table_description.rb +3 -3
- data/lib/duckdb/table_name_parser.rb +6 -36
- data/lib/duckdb/version.rb +1 -1
- data/lib/duckdb.rb +0 -14
- metadata +1 -1
data/ext/duckdb/result.c
CHANGED
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
struct chunk_arg {
|
|
4
4
|
duckdb_data_chunk chunk;
|
|
5
5
|
idx_t col_count;
|
|
6
|
+
duckdb_logical_type *types;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
struct owned_type_arg {
|
|
10
|
+
duckdb_vector vector;
|
|
11
|
+
duckdb_logical_type type;
|
|
12
|
+
idx_t bgn;
|
|
13
|
+
idx_t end;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
struct struct_fields_arg {
|
|
17
|
+
duckdb_logical_type ty;
|
|
18
|
+
duckdb_vector vector;
|
|
19
|
+
idx_t row_idx;
|
|
20
|
+
duckdb_logical_type child_type;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
struct map_entries_arg {
|
|
24
|
+
duckdb_vector key_vector;
|
|
25
|
+
duckdb_vector value_vector;
|
|
26
|
+
duckdb_logical_type key_type;
|
|
27
|
+
duckdb_logical_type value_type;
|
|
28
|
+
idx_t bgn;
|
|
29
|
+
idx_t end;
|
|
6
30
|
};
|
|
7
31
|
|
|
8
32
|
static VALUE cDuckDBResult;
|
|
@@ -14,6 +38,7 @@ static VALUE result_column_count(VALUE oDuckDBResult);
|
|
|
14
38
|
static VALUE result_rows_changed(VALUE oDuckDBResult);
|
|
15
39
|
static VALUE result_columns(VALUE oDuckDBResult);
|
|
16
40
|
static VALUE destroy_data_chunk(VALUE arg);
|
|
41
|
+
static duckdb_logical_type *result_column_types(rubyDuckDBResult *ctx);
|
|
17
42
|
|
|
18
43
|
static VALUE result__chunk_stream(VALUE oDuckDBResult);
|
|
19
44
|
static VALUE result_arrow_c_stream(VALUE oDuckDBResult);
|
|
@@ -22,20 +47,10 @@ static VALUE result__return_type(VALUE oDuckDBResult);
|
|
|
22
47
|
static VALUE result__statement_type(VALUE oDuckDBResult);
|
|
23
48
|
static VALUE result__enum_internal_type(VALUE oDuckDBResult, VALUE col_idx);
|
|
24
49
|
|
|
25
|
-
static VALUE vector_date(void *vector_data, idx_t row_idx);
|
|
26
|
-
static VALUE vector_timestamp(void* vector_data, idx_t row_idx);
|
|
27
|
-
static VALUE vector_time(void* vector_data, idx_t row_idx);
|
|
28
|
-
static VALUE vector_interval(void* vector_data, idx_t row_idx);
|
|
29
50
|
static VALUE vector_blob(void* vector_data, idx_t row_idx);
|
|
30
51
|
static VALUE vector_varchar(void* vector_data, idx_t row_idx);
|
|
31
|
-
static VALUE vector_hugeint(void* vector_data, idx_t row_idx);
|
|
32
|
-
static VALUE vector_uhugeint(void* vector_data, idx_t row_idx);
|
|
33
52
|
static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx);
|
|
34
53
|
|
|
35
|
-
static VALUE vector_timestamp_s(void* vector_data, idx_t row_idx);
|
|
36
|
-
static VALUE vector_timestamp_ms(void* vector_data, idx_t row_idx);
|
|
37
|
-
static VALUE vector_timestamp_ns(void* vector_data, idx_t row_idx);
|
|
38
|
-
static VALUE vector_time_ns(void* vector_data, idx_t row_idx);
|
|
39
54
|
static VALUE vector_enum(duckdb_logical_type ty, void* vector_data, idx_t row_idx);
|
|
40
55
|
static VALUE vector_array(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx);
|
|
41
56
|
static VALUE vector_list(duckdb_logical_type ty, duckdb_vector vector, void* vector_data, idx_t row_idx);
|
|
@@ -46,7 +61,13 @@ static VALUE vector_bit(void* vector_data, idx_t row_idx);
|
|
|
46
61
|
static VALUE vector_time_tz(void* vector_data, idx_t row_idx);
|
|
47
62
|
static VALUE vector_timestamp_tz(void* vector_data, idx_t row_idx);
|
|
48
63
|
static VALUE vector_uuid(void* vector_data, idx_t row_idx);
|
|
49
|
-
static VALUE
|
|
64
|
+
static VALUE convert_values_in_range(VALUE varg);
|
|
65
|
+
static VALUE destroy_owned_type(VALUE varg);
|
|
66
|
+
static VALUE vector_values_with_owned_type(duckdb_vector vector, duckdb_logical_type type, idx_t bgn, idx_t end);
|
|
67
|
+
static VALUE convert_map_entries(VALUE varg);
|
|
68
|
+
static VALUE destroy_map_types(VALUE varg);
|
|
69
|
+
static VALUE convert_struct_fields(VALUE varg);
|
|
70
|
+
static VALUE destroy_struct_child_type(VALUE varg);
|
|
50
71
|
|
|
51
72
|
/*
|
|
52
73
|
* No RUBY_TYPED_FREE_IMMEDIATELY: deallocate can block, and must not run
|
|
@@ -66,6 +87,11 @@ static void deallocate(void *ctx) {
|
|
|
66
87
|
}
|
|
67
88
|
|
|
68
89
|
static VALUE allocate(VALUE klass) {
|
|
90
|
+
/*
|
|
91
|
+
* Use calloc (not xcalloc): rbduckdb_result_unref frees the struct, and it
|
|
92
|
+
* can run from the Arrow stream release callback on a non-Ruby thread
|
|
93
|
+
* where xfree is unsafe.
|
|
94
|
+
*/
|
|
69
95
|
rubyDuckDBResult *ctx = calloc((size_t)1, sizeof(rubyDuckDBResult));
|
|
70
96
|
|
|
71
97
|
if (ctx == NULL) {
|
|
@@ -80,7 +106,13 @@ void rbduckdb_result_ref(rubyDuckDBResult *ctx) {
|
|
|
80
106
|
}
|
|
81
107
|
|
|
82
108
|
void rbduckdb_result_unref(rubyDuckDBResult *ctx) {
|
|
109
|
+
idx_t col_idx;
|
|
110
|
+
|
|
83
111
|
if (RUBY_ATOMIC_FETCH_SUB(ctx->refcount, 1) == 1) {
|
|
112
|
+
for (col_idx = 0; col_idx < ctx->column_types_count; col_idx++) {
|
|
113
|
+
duckdb_destroy_logical_type(&(ctx->column_types[col_idx]));
|
|
114
|
+
}
|
|
115
|
+
free(ctx->column_types);
|
|
84
116
|
duckdb_destroy_result(&(ctx->result));
|
|
85
117
|
free(ctx);
|
|
86
118
|
}
|
|
@@ -176,6 +208,25 @@ static VALUE destroy_data_chunk(VALUE arg) {
|
|
|
176
208
|
return Qnil;
|
|
177
209
|
}
|
|
178
210
|
|
|
211
|
+
static duckdb_logical_type *result_column_types(rubyDuckDBResult *ctx) {
|
|
212
|
+
idx_t col_idx;
|
|
213
|
+
idx_t column_count;
|
|
214
|
+
|
|
215
|
+
if (ctx->column_types == NULL) {
|
|
216
|
+
column_count = duckdb_column_count(&(ctx->result));
|
|
217
|
+
/* Use calloc (not xcalloc): freed by rbduckdb_result_unref (see allocate). */
|
|
218
|
+
ctx->column_types = calloc(column_count + 1, sizeof(duckdb_logical_type));
|
|
219
|
+
if (ctx->column_types == NULL) {
|
|
220
|
+
rb_raise(rb_eNoMemError, "failed to allocate DuckDB::Result column types");
|
|
221
|
+
}
|
|
222
|
+
for (col_idx = 0; col_idx < column_count; col_idx++) {
|
|
223
|
+
ctx->column_types[col_idx] = duckdb_column_logical_type(&(ctx->result), col_idx);
|
|
224
|
+
}
|
|
225
|
+
ctx->column_types_count = column_count;
|
|
226
|
+
}
|
|
227
|
+
return ctx->column_types;
|
|
228
|
+
}
|
|
229
|
+
|
|
179
230
|
/* :nodoc: */
|
|
180
231
|
static VALUE result__chunk_stream(VALUE oDuckDBResult) {
|
|
181
232
|
rubyDuckDBResult *ctx;
|
|
@@ -186,6 +237,7 @@ static VALUE result__chunk_stream(VALUE oDuckDBResult) {
|
|
|
186
237
|
RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
|
|
187
238
|
|
|
188
239
|
arg.col_count = duckdb_column_count(&(ctx->result));
|
|
240
|
+
arg.types = result_column_types(ctx);
|
|
189
241
|
|
|
190
242
|
while((arg.chunk = duckdb_fetch_chunk(ctx->result)) != NULL) {
|
|
191
243
|
rb_ensure(yield_rows, (VALUE)&arg, destroy_data_chunk, (VALUE)&arg);
|
|
@@ -208,7 +260,7 @@ static VALUE yield_rows(VALUE arg) {
|
|
|
208
260
|
row = rb_ary_new2(p->col_count);
|
|
209
261
|
for (col_idx = 0; col_idx < p->col_count; col_idx++) {
|
|
210
262
|
vector = duckdb_data_chunk_get_vector(p->chunk, col_idx);
|
|
211
|
-
val =
|
|
263
|
+
val = rbduckdb_vector_value_at(vector, p->types[col_idx], row_idx);
|
|
212
264
|
rb_ary_store(row, col_idx, val);
|
|
213
265
|
}
|
|
214
266
|
rb_yield(row);
|
|
@@ -249,46 +301,14 @@ VALUE rbduckdb_create_result(void) {
|
|
|
249
301
|
return allocate(cDuckDBResult);
|
|
250
302
|
}
|
|
251
303
|
|
|
252
|
-
static VALUE vector_date(void *vector_data, idx_t row_idx) {
|
|
253
|
-
return rbduckdb_date_to_ruby(((duckdb_date *)vector_data)[row_idx]);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
static VALUE vector_timestamp(void* vector_data, idx_t row_idx) {
|
|
257
|
-
return rbduckdb_timestamp_to_ruby(((duckdb_timestamp *)vector_data)[row_idx]);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
static VALUE vector_time(void* vector_data, idx_t row_idx) {
|
|
261
|
-
return rbduckdb_time_to_ruby(((duckdb_time *)vector_data)[row_idx]);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
static VALUE vector_interval(void* vector_data, idx_t row_idx) {
|
|
265
|
-
return rbduckdb_interval_to_ruby(((duckdb_interval *)vector_data)[row_idx]);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
304
|
static VALUE vector_blob(void* vector_data, idx_t row_idx) {
|
|
269
305
|
duckdb_string_t s = (((duckdb_string_t *)vector_data)[row_idx]);
|
|
270
|
-
|
|
271
|
-
return rb_str_new(s.value.inlined.inlined, s.value.inlined.length);
|
|
272
|
-
} else {
|
|
273
|
-
return rb_str_new(s.value.pointer.ptr, s.value.pointer.length);
|
|
274
|
-
}
|
|
306
|
+
return rb_str_new(duckdb_string_t_data(&s), duckdb_string_t_length(s));
|
|
275
307
|
}
|
|
276
308
|
|
|
277
309
|
static VALUE vector_varchar(void* vector_data, idx_t row_idx) {
|
|
278
310
|
duckdb_string_t s = (((duckdb_string_t *)vector_data)[row_idx]);
|
|
279
|
-
|
|
280
|
-
return rb_utf8_str_new(s.value.inlined.inlined, s.value.inlined.length);
|
|
281
|
-
} else {
|
|
282
|
-
return rb_utf8_str_new(s.value.pointer.ptr, s.value.pointer.length);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
static VALUE vector_hugeint(void* vector_data, idx_t row_idx) {
|
|
287
|
-
return rbduckdb_hugeint_to_ruby(((duckdb_hugeint *)vector_data)[row_idx]);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
static VALUE vector_uhugeint(void* vector_data, idx_t row_idx) {
|
|
291
|
-
return rbduckdb_uhugeint_to_ruby(((duckdb_uhugeint *)vector_data)[row_idx]);
|
|
311
|
+
return rb_utf8_str_new(duckdb_string_t_data(&s), duckdb_string_t_length(s));
|
|
292
312
|
}
|
|
293
313
|
|
|
294
314
|
static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
|
|
@@ -329,26 +349,6 @@ static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row
|
|
|
329
349
|
);
|
|
330
350
|
}
|
|
331
351
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
static VALUE vector_timestamp_s(void* vector_data, idx_t row_idx) {
|
|
335
|
-
return rbduckdb_timestamp_s_to_ruby(((duckdb_timestamp_s *)vector_data)[row_idx]);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
static VALUE vector_timestamp_ms(void* vector_data, idx_t row_idx) {
|
|
340
|
-
return rbduckdb_timestamp_ms_to_ruby(((duckdb_timestamp_ms *)vector_data)[row_idx]);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
static VALUE vector_timestamp_ns(void* vector_data, idx_t row_idx) {
|
|
345
|
-
return rbduckdb_timestamp_ns_to_ruby(((duckdb_timestamp_ns *)vector_data)[row_idx]);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
static VALUE vector_time_ns(void* vector_data, idx_t row_idx) {
|
|
349
|
-
return rbduckdb_time_ns_to_ruby(((duckdb_time_ns *)vector_data)[row_idx]);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
352
|
static VALUE vector_enum(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
|
|
353
353
|
duckdb_type type = duckdb_enum_internal_type(ty);
|
|
354
354
|
uint8_t index;
|
|
@@ -371,23 +371,11 @@ static VALUE vector_enum(duckdb_logical_type ty, void* vector_data, idx_t row_id
|
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
static VALUE vector_array(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx) {
|
|
374
|
-
VALUE ary = Qnil;
|
|
375
|
-
VALUE value = Qnil;
|
|
376
|
-
|
|
377
|
-
duckdb_logical_type child_logical_type = duckdb_array_type_child_type(ty);
|
|
378
374
|
idx_t size = duckdb_array_type_array_size(ty);
|
|
379
375
|
idx_t bgn = row_idx * size;
|
|
380
|
-
|
|
381
|
-
duckdb_vector child = duckdb_array_vector_get_child(vector);
|
|
382
|
-
|
|
383
|
-
ary = rb_ary_new2(size);
|
|
384
|
-
for (idx_t i = bgn; i < end; ++i) {
|
|
385
|
-
value = rbduckdb_vector_value_at(child, child_logical_type, i);
|
|
386
|
-
rb_ary_store(ary, i - bgn, value);
|
|
387
|
-
}
|
|
376
|
+
duckdb_vector child = duckdb_array_vector_get_child(vector);
|
|
388
377
|
|
|
389
|
-
|
|
390
|
-
return ary;
|
|
378
|
+
return vector_values_with_owned_type(child, duckdb_array_type_child_type(ty), bgn, bgn + size);
|
|
391
379
|
}
|
|
392
380
|
|
|
393
381
|
VALUE rbduckdb_vector_value_at(duckdb_vector vector, duckdb_logical_type element_type, idx_t index) {
|
|
@@ -442,22 +430,22 @@ VALUE rbduckdb_vector_value_at(duckdb_vector vector, duckdb_logical_type element
|
|
|
442
430
|
obj = DBL2NUM((((double *) vector_data)[index]));
|
|
443
431
|
break;
|
|
444
432
|
case DUCKDB_TYPE_TIMESTAMP:
|
|
445
|
-
obj =
|
|
433
|
+
obj = rbduckdb_timestamp_to_ruby(((duckdb_timestamp *)vector_data)[index]);
|
|
446
434
|
break;
|
|
447
435
|
case DUCKDB_TYPE_DATE:
|
|
448
|
-
obj =
|
|
436
|
+
obj = rbduckdb_date_to_ruby(((duckdb_date *)vector_data)[index]);
|
|
449
437
|
break;
|
|
450
438
|
case DUCKDB_TYPE_TIME:
|
|
451
|
-
obj =
|
|
439
|
+
obj = rbduckdb_time_to_ruby(((duckdb_time *)vector_data)[index]);
|
|
452
440
|
break;
|
|
453
441
|
case DUCKDB_TYPE_INTERVAL:
|
|
454
|
-
obj =
|
|
442
|
+
obj = rbduckdb_interval_to_ruby(((duckdb_interval *)vector_data)[index]);
|
|
455
443
|
break;
|
|
456
444
|
case DUCKDB_TYPE_HUGEINT:
|
|
457
|
-
obj =
|
|
445
|
+
obj = rbduckdb_hugeint_to_ruby(((duckdb_hugeint *)vector_data)[index]);
|
|
458
446
|
break;
|
|
459
447
|
case DUCKDB_TYPE_UHUGEINT:
|
|
460
|
-
obj =
|
|
448
|
+
obj = rbduckdb_uhugeint_to_ruby(((duckdb_uhugeint *)vector_data)[index]);
|
|
461
449
|
break;
|
|
462
450
|
case DUCKDB_TYPE_VARCHAR:
|
|
463
451
|
obj = vector_varchar(vector_data, index);
|
|
@@ -469,16 +457,16 @@ VALUE rbduckdb_vector_value_at(duckdb_vector vector, duckdb_logical_type element
|
|
|
469
457
|
obj = vector_decimal(element_type, vector_data, index);
|
|
470
458
|
break;
|
|
471
459
|
case DUCKDB_TYPE_TIMESTAMP_S:
|
|
472
|
-
obj =
|
|
460
|
+
obj = rbduckdb_timestamp_s_to_ruby(((duckdb_timestamp_s *)vector_data)[index]);
|
|
473
461
|
break;
|
|
474
462
|
case DUCKDB_TYPE_TIMESTAMP_MS:
|
|
475
|
-
obj =
|
|
463
|
+
obj = rbduckdb_timestamp_ms_to_ruby(((duckdb_timestamp_ms *)vector_data)[index]);
|
|
476
464
|
break;
|
|
477
465
|
case DUCKDB_TYPE_TIMESTAMP_NS:
|
|
478
|
-
obj =
|
|
466
|
+
obj = rbduckdb_timestamp_ns_to_ruby(((duckdb_timestamp_ns *)vector_data)[index]);
|
|
479
467
|
break;
|
|
480
468
|
case DUCKDB_TYPE_TIME_NS:
|
|
481
|
-
obj =
|
|
469
|
+
obj = rbduckdb_time_ns_to_ruby(((duckdb_time_ns *)vector_data)[index]);
|
|
482
470
|
break;
|
|
483
471
|
case DUCKDB_TYPE_ENUM:
|
|
484
472
|
obj = vector_enum(element_type, vector_data, index);
|
|
@@ -519,93 +507,121 @@ VALUE rbduckdb_vector_value_at(duckdb_vector vector, duckdb_logical_type element
|
|
|
519
507
|
}
|
|
520
508
|
|
|
521
509
|
static VALUE vector_list(duckdb_logical_type ty, duckdb_vector vector, void * vector_data, idx_t row_idx) {
|
|
522
|
-
VALUE ary = Qnil;
|
|
523
|
-
VALUE value = Qnil;
|
|
524
|
-
idx_t i;
|
|
525
|
-
|
|
526
|
-
duckdb_logical_type child_logical_type = duckdb_list_type_child_type(ty);
|
|
527
|
-
|
|
528
510
|
duckdb_list_entry list_entry = ((duckdb_list_entry *)vector_data)[row_idx];
|
|
529
511
|
idx_t bgn = list_entry.offset;
|
|
530
|
-
idx_t end = bgn + list_entry.length;
|
|
531
|
-
ary = rb_ary_new2(list_entry.length);
|
|
532
|
-
|
|
533
512
|
duckdb_vector child = duckdb_list_vector_get_child(vector);
|
|
534
513
|
|
|
535
|
-
|
|
536
|
-
value = rbduckdb_vector_value_at(child, child_logical_type, i);
|
|
537
|
-
rb_ary_store(ary, i - bgn, value);
|
|
538
|
-
}
|
|
539
|
-
duckdb_destroy_logical_type(&child_logical_type);
|
|
540
|
-
return ary;
|
|
514
|
+
return vector_values_with_owned_type(child, duckdb_list_type_child_type(ty), bgn, bgn + list_entry.length);
|
|
541
515
|
}
|
|
542
516
|
|
|
543
517
|
static VALUE vector_map(duckdb_logical_type ty, duckdb_vector vector, void* vector_data, idx_t row_idx) {
|
|
544
|
-
|
|
545
|
-
VALUE key = Qnil;
|
|
546
|
-
VALUE value = Qnil;
|
|
547
|
-
|
|
548
|
-
duckdb_logical_type key_logical_type = duckdb_map_type_key_type(ty);
|
|
549
|
-
duckdb_logical_type value_logical_type = duckdb_map_type_value_type(ty);
|
|
550
|
-
|
|
518
|
+
struct map_entries_arg arg;
|
|
551
519
|
duckdb_list_entry list_entry = ((duckdb_list_entry *)vector_data)[row_idx];
|
|
520
|
+
duckdb_vector child = duckdb_list_vector_get_child(vector);
|
|
552
521
|
|
|
553
|
-
|
|
554
|
-
|
|
522
|
+
arg.key_vector = duckdb_struct_vector_get_child(child, 0);
|
|
523
|
+
arg.value_vector = duckdb_struct_vector_get_child(child, 1);
|
|
524
|
+
arg.key_type = duckdb_map_type_key_type(ty);
|
|
525
|
+
arg.value_type = duckdb_map_type_value_type(ty);
|
|
526
|
+
arg.bgn = list_entry.offset;
|
|
527
|
+
arg.end = list_entry.offset + list_entry.length;
|
|
555
528
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
duckdb_vector value_vector = duckdb_struct_vector_get_child(child, 1);
|
|
529
|
+
return rb_ensure(convert_map_entries, (VALUE)&arg, destroy_map_types, (VALUE)&arg);
|
|
530
|
+
}
|
|
559
531
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
532
|
+
static VALUE convert_map_entries(VALUE varg) {
|
|
533
|
+
struct map_entries_arg *arg = (struct map_entries_arg *)varg;
|
|
534
|
+
VALUE hash = rb_hash_new();
|
|
535
|
+
VALUE key;
|
|
536
|
+
VALUE value;
|
|
537
|
+
|
|
538
|
+
for (idx_t i = arg->bgn; i < arg->end; ++i) {
|
|
539
|
+
key = rbduckdb_vector_value_at(arg->key_vector, arg->key_type, i);
|
|
540
|
+
value = rbduckdb_vector_value_at(arg->value_vector, arg->value_type, i);
|
|
563
541
|
rb_hash_aset(hash, key, value);
|
|
564
542
|
}
|
|
565
|
-
|
|
566
|
-
duckdb_destroy_logical_type(&key_logical_type);
|
|
567
|
-
duckdb_destroy_logical_type(&value_logical_type);
|
|
568
543
|
return hash;
|
|
569
544
|
}
|
|
570
545
|
|
|
546
|
+
static VALUE destroy_map_types(VALUE varg) {
|
|
547
|
+
struct map_entries_arg *arg = (struct map_entries_arg *)varg;
|
|
548
|
+
|
|
549
|
+
duckdb_destroy_logical_type(&(arg->key_type));
|
|
550
|
+
duckdb_destroy_logical_type(&(arg->value_type));
|
|
551
|
+
return Qnil;
|
|
552
|
+
}
|
|
553
|
+
|
|
571
554
|
static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx) {
|
|
555
|
+
struct struct_fields_arg arg = {ty, vector, row_idx, NULL};
|
|
556
|
+
|
|
557
|
+
return rb_ensure(convert_struct_fields, (VALUE)&arg, destroy_struct_child_type, (VALUE)&arg);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
static VALUE convert_struct_fields(VALUE varg) {
|
|
561
|
+
struct struct_fields_arg *arg = (struct struct_fields_arg *)varg;
|
|
572
562
|
VALUE hash = rb_hash_new();
|
|
573
563
|
VALUE value = Qnil;
|
|
574
564
|
VALUE key = Qnil;
|
|
575
565
|
duckdb_vector child;
|
|
576
|
-
duckdb_logical_type child_type;
|
|
577
566
|
char *p;
|
|
578
567
|
|
|
579
|
-
idx_t child_count = duckdb_struct_type_child_count(ty);
|
|
568
|
+
idx_t child_count = duckdb_struct_type_child_count(arg->ty);
|
|
580
569
|
|
|
581
570
|
for (idx_t i = 0; i < child_count; ++i) {
|
|
582
|
-
p = duckdb_struct_type_child_name(ty, i);
|
|
571
|
+
p = duckdb_struct_type_child_name(arg->ty, i);
|
|
583
572
|
if (p) {
|
|
584
573
|
key = ID2SYM(rb_intern_const(p));
|
|
585
|
-
child = duckdb_struct_vector_get_child(vector, i);
|
|
586
|
-
child_type = duckdb_struct_type_child_type(ty, i);
|
|
587
|
-
value = rbduckdb_vector_value_at(child, child_type, row_idx);
|
|
588
|
-
rb_hash_aset(hash, key, value);
|
|
589
|
-
duckdb_destroy_logical_type(&child_type);
|
|
590
574
|
duckdb_free(p);
|
|
575
|
+
child = duckdb_struct_vector_get_child(arg->vector, i);
|
|
576
|
+
arg->child_type = duckdb_struct_type_child_type(arg->ty, i);
|
|
577
|
+
value = rbduckdb_vector_value_at(child, arg->child_type, arg->row_idx);
|
|
578
|
+
duckdb_destroy_logical_type(&(arg->child_type));
|
|
579
|
+
rb_hash_aset(hash, key, value);
|
|
591
580
|
}
|
|
592
581
|
}
|
|
593
582
|
|
|
594
583
|
return hash;
|
|
595
584
|
}
|
|
596
585
|
|
|
586
|
+
static VALUE destroy_struct_child_type(VALUE varg) {
|
|
587
|
+
struct struct_fields_arg *arg = (struct struct_fields_arg *)varg;
|
|
588
|
+
|
|
589
|
+
duckdb_destroy_logical_type(&(arg->child_type));
|
|
590
|
+
return Qnil;
|
|
591
|
+
}
|
|
592
|
+
|
|
597
593
|
static VALUE vector_union(duckdb_logical_type ty, duckdb_vector vector, void* vector_data, idx_t row_idx){
|
|
598
|
-
VALUE value = Qnil;
|
|
599
594
|
duckdb_vector type_vector = duckdb_struct_vector_get_child(vector, 0);
|
|
600
595
|
void *data = duckdb_vector_get_data(type_vector);
|
|
601
596
|
uint8_t index = ((int8_t *)data)[row_idx];
|
|
602
597
|
|
|
603
|
-
|
|
598
|
+
duckdb_vector member_vector = duckdb_struct_vector_get_child(vector, index + 1);
|
|
599
|
+
VALUE values = vector_values_with_owned_type(member_vector, duckdb_union_type_member_type(ty, index), row_idx, row_idx + 1);
|
|
604
600
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
601
|
+
return rb_ary_entry(values, 0);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
static VALUE convert_values_in_range(VALUE varg) {
|
|
605
|
+
struct owned_type_arg *arg = (struct owned_type_arg *)varg;
|
|
606
|
+
VALUE ary = rb_ary_new2(arg->end - arg->bgn);
|
|
607
|
+
|
|
608
|
+
for (idx_t i = arg->bgn; i < arg->end; ++i) {
|
|
609
|
+
rb_ary_store(ary, i - arg->bgn, rbduckdb_vector_value_at(arg->vector, arg->type, i));
|
|
610
|
+
}
|
|
611
|
+
return ary;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
static VALUE destroy_owned_type(VALUE varg) {
|
|
615
|
+
struct owned_type_arg *arg = (struct owned_type_arg *)varg;
|
|
616
|
+
|
|
617
|
+
duckdb_destroy_logical_type(&(arg->type));
|
|
618
|
+
return Qnil;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
static VALUE vector_values_with_owned_type(duckdb_vector vector, duckdb_logical_type type, idx_t bgn, idx_t end) {
|
|
622
|
+
struct owned_type_arg arg = {vector, type, bgn, end};
|
|
623
|
+
|
|
624
|
+
return rb_ensure(convert_values_in_range, (VALUE)&arg, destroy_owned_type, (VALUE)&arg);
|
|
609
625
|
}
|
|
610
626
|
|
|
611
627
|
static VALUE str_concat_byte(VALUE str, unsigned char byte, int offset) {
|
|
@@ -625,7 +641,7 @@ static VALUE str_concat_byte(VALUE str, unsigned char byte, int offset) {
|
|
|
625
641
|
return rb_str_cat(str, p, 8 - offset);
|
|
626
642
|
}
|
|
627
643
|
|
|
628
|
-
static VALUE bytes_to_string(char *bytes, uint32_t length, int offset) {
|
|
644
|
+
static VALUE bytes_to_string(const char *bytes, uint32_t length, int offset) {
|
|
629
645
|
VALUE str = rb_str_new_literal("");
|
|
630
646
|
str = str_concat_byte(str, bytes[0], offset);
|
|
631
647
|
for (uint32_t i = 1; i < length; i++) {
|
|
@@ -636,22 +652,16 @@ static VALUE bytes_to_string(char *bytes, uint32_t length, int offset) {
|
|
|
636
652
|
|
|
637
653
|
static VALUE vector_bit(void* vector_data, idx_t row_idx) {
|
|
638
654
|
duckdb_string_t s = (((duckdb_string_t *)vector_data)[row_idx]);
|
|
639
|
-
char *p;
|
|
655
|
+
const char *p = duckdb_string_t_data(&s);
|
|
656
|
+
uint32_t length = duckdb_string_t_length(s);
|
|
640
657
|
int offset;
|
|
641
|
-
uint32_t length;
|
|
642
658
|
VALUE str = Qnil;
|
|
643
659
|
|
|
644
|
-
if(
|
|
645
|
-
|
|
646
|
-
p = &s.value.inlined.inlined[1];
|
|
647
|
-
offset = s.value.inlined.inlined[0];
|
|
648
|
-
str = bytes_to_string(p, length, offset);
|
|
649
|
-
} else {
|
|
650
|
-
length = s.value.pointer.length - 1;
|
|
651
|
-
p = &s.value.pointer.ptr[1];
|
|
652
|
-
offset = s.value.pointer.ptr[0];
|
|
653
|
-
str = bytes_to_string(p, length, offset);
|
|
660
|
+
if (length < 2 || (unsigned char)p[0] > 7) {
|
|
661
|
+
rb_raise(eDuckDBError, "invalid BIT value");
|
|
654
662
|
}
|
|
663
|
+
offset = (unsigned char)p[0];
|
|
664
|
+
str = bytes_to_string(p + 1, length - 1, offset);
|
|
655
665
|
return str;
|
|
656
666
|
}
|
|
657
667
|
|
|
@@ -697,18 +707,6 @@ static VALUE result_arrow_c_stream(VALUE oDuckDBResult) {
|
|
|
697
707
|
return stream;
|
|
698
708
|
}
|
|
699
709
|
|
|
700
|
-
static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
|
|
701
|
-
duckdb_logical_type ty;
|
|
702
|
-
VALUE obj = Qnil;
|
|
703
|
-
|
|
704
|
-
ty = duckdb_vector_get_column_type(vector);
|
|
705
|
-
|
|
706
|
-
obj = rbduckdb_vector_value_at(vector, ty, row_idx);
|
|
707
|
-
|
|
708
|
-
duckdb_destroy_logical_type(&ty);
|
|
709
|
-
return obj;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
710
|
void rbduckdb_init_result(void) {
|
|
713
711
|
#if 0
|
|
714
712
|
VALUE mDuckDB = rb_define_module("DuckDB");
|
data/ext/duckdb/result.h
CHANGED
|
@@ -18,11 +18,6 @@ static VALUE scalar_function__set_bind(VALUE self);
|
|
|
18
18
|
static void scalar_function_callback(duckdb_function_info info, duckdb_data_chunk input, duckdb_vector output);
|
|
19
19
|
static void scalar_function_bind_callback(duckdb_bind_info info);
|
|
20
20
|
#ifdef HAVE_DUCKDB_H_GE_V1_5_0
|
|
21
|
-
/*
|
|
22
|
-
* Thread detection functions (available since Ruby 2.3).
|
|
23
|
-
* Used to skip the proxy on Ruby threads.
|
|
24
|
-
*/
|
|
25
|
-
extern int ruby_native_thread_p(void);
|
|
26
21
|
static void scalar_function_init_callback(duckdb_init_info info);
|
|
27
22
|
#endif
|
|
28
23
|
|
|
@@ -251,15 +246,8 @@ static VALUE process_rows(VALUE varg) {
|
|
|
251
246
|
* a GC, and the earlier columns' objects must stay reachable. */
|
|
252
247
|
VALUE args = rb_ary_new_capa((long)arg->col_count);
|
|
253
248
|
|
|
254
|
-
/* Allocate arrays to hold input vectors and their types */
|
|
255
|
-
arg->input_vectors = ALLOC_N(duckdb_vector, arg->col_count);
|
|
256
|
-
arg->input_types = ALLOC_N(duckdb_logical_type, arg->col_count);
|
|
257
|
-
|
|
258
249
|
/* Get all input vectors and their types */
|
|
259
|
-
|
|
260
|
-
arg->input_vectors[j] = duckdb_data_chunk_get_vector(arg->input, j);
|
|
261
|
-
arg->input_types[j] = duckdb_vector_get_column_type(arg->input_vectors[j]);
|
|
262
|
-
}
|
|
250
|
+
rbduckdb_input_columns_load(arg->input, arg->col_count, &arg->input_vectors, &arg->input_types);
|
|
263
251
|
|
|
264
252
|
/* Process each row */
|
|
265
253
|
for (i = 0; i < arg->row_count; i++) {
|
|
@@ -282,24 +270,10 @@ static VALUE process_rows(VALUE varg) {
|
|
|
282
270
|
|
|
283
271
|
static VALUE cleanup_callback(VALUE varg) {
|
|
284
272
|
struct callback_arg *arg = (struct callback_arg *)varg;
|
|
285
|
-
idx_t j;
|
|
286
273
|
|
|
287
|
-
|
|
288
|
-
if (arg->input_types != NULL) {
|
|
289
|
-
for (j = 0; j < arg->col_count; j++) {
|
|
290
|
-
duckdb_destroy_logical_type(&arg->input_types[j]);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
274
|
+
rbduckdb_input_columns_free(arg->input_vectors, arg->input_types, arg->col_count);
|
|
293
275
|
duckdb_destroy_logical_type(&arg->output_type);
|
|
294
276
|
|
|
295
|
-
/* Free allocated memory */
|
|
296
|
-
if (arg->input_types != NULL) {
|
|
297
|
-
xfree(arg->input_types);
|
|
298
|
-
}
|
|
299
|
-
if (arg->input_vectors != NULL) {
|
|
300
|
-
xfree(arg->input_vectors);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
277
|
return Qnil;
|
|
304
278
|
}
|
|
305
279
|
|
|
@@ -307,50 +281,16 @@ static VALUE cleanup_callback(VALUE varg) {
|
|
|
307
281
|
/*
|
|
308
282
|
* Per-worker init for the execute path (DuckDB >= 1.5.0).
|
|
309
283
|
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* instead of the shared global executor, so workers run callbacks concurrently.
|
|
315
|
-
* DuckDB invokes rbduckdb_worker_proxy_destroy when the state is freed.
|
|
284
|
+
* Runs once on each worker thread that will execute the callback. Creates the
|
|
285
|
+
* worker's proxy and stores it as per-worker state, so the execute callback
|
|
286
|
+
* dispatches through it rather than the shared global executor. DuckDB calls
|
|
287
|
+
* rbduckdb_worker_proxy_destroy when the state is freed.
|
|
316
288
|
*/
|
|
317
|
-
struct create_proxy_callback_arg {
|
|
318
|
-
struct worker_proxy *proxy;
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
static VALUE create_proxy_callback(VALUE varg) {
|
|
322
|
-
struct create_proxy_callback_arg *arg = (struct create_proxy_callback_arg *)varg;
|
|
323
|
-
arg->proxy = rbduckdb_worker_proxy_create();
|
|
324
|
-
return Qnil;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/*
|
|
328
|
-
* rbduckdb_worker_proxy_create may raise (NoMemError, Thread.new failure),
|
|
329
|
-
* and the executor runs callbacks unprotected — a raise would longjmp past
|
|
330
|
-
* its done-signaling and block the waiting DuckDB worker forever. Swallow
|
|
331
|
-
* the exception instead: the proxy stays NULL, init sets no state, and the
|
|
332
|
-
* execute callback falls back to the global executor.
|
|
333
|
-
*/
|
|
334
|
-
static void create_proxy_callback_protected(void *user_data) {
|
|
335
|
-
int exception_state;
|
|
336
|
-
|
|
337
|
-
rb_protect(create_proxy_callback, (VALUE)user_data, &exception_state);
|
|
338
|
-
if (exception_state) {
|
|
339
|
-
rb_set_errinfo(Qnil);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
289
|
static void scalar_function_init_callback(duckdb_init_info info) {
|
|
344
|
-
struct
|
|
345
|
-
|
|
346
|
-
/* A Ruby calling thread runs the callback inline (Case 1/2); no proxy needed. */
|
|
347
|
-
if (ruby_native_thread_p()) return;
|
|
348
|
-
|
|
349
|
-
arg.proxy = NULL;
|
|
350
|
-
rbduckdb_function_executor_dispatch(create_proxy_callback_protected, &arg);
|
|
290
|
+
struct worker_proxy *proxy = rbduckdb_worker_proxy_create_for_current_thread();
|
|
351
291
|
|
|
352
|
-
if (
|
|
353
|
-
duckdb_scalar_function_init_set_state(info,
|
|
292
|
+
if (proxy != NULL) {
|
|
293
|
+
duckdb_scalar_function_init_set_state(info, proxy, rbduckdb_worker_proxy_destroy);
|
|
354
294
|
}
|
|
355
295
|
}
|
|
356
296
|
#endif
|