duckdb 0.8.0 → 0.8.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: 8e8040d795ad975b4472fe439aa2cfb403ad5f24f9c602bca7dbdf6103c37b65
4
- data.tar.gz: 82cd61d78fec67f62be8ad0280305b224ae605ffd2ea453855168dcaa77f4d32
3
+ metadata.gz: dab5e8d5f3beafce29f2d545b736b34b3502f2f31120d1d7d0714fdb83512457
4
+ data.tar.gz: a73a7438ec5762af143b8590923b0fd3c54ec99926aa48b485346e943fe66916
5
5
  SHA512:
6
- metadata.gz: b54b53aa6ec96ef9e8607bea7f96b8ef9fc7c4e2189675e575eeabdfaa2d608320c02ac86dc8ca7453cd9d314ceb943241a0a858689c85b8221374ff5dc6e00e
7
- data.tar.gz: 86936495132694846dd8931998c9f716d405571dd34842f6f8563ad531f2e0b8fb678f4477cff9ec33a1c0d3affc615884a4dd8063909f57cb8e4a1da2a0434f
6
+ metadata.gz: de0988a48ae0e9652d8411ce52265835e6d63c30f53c181cc25066d7fbae26ff9a54290e014c66aa44f6a3f87b9e5da7fa3acee6f0051c1b886cb6ea5e68d4bb
7
+ data.tar.gz: 0edd9bfe15f0e47da50e860732acecc897a9cbba716218da5de80188be7bf43df5f1300d3419e501532a7d26cc42a1c79d76835cb3a1a956e7b06d7842b40c20
@@ -15,8 +15,8 @@ jobs:
15
15
  runs-on: macos-latest
16
16
  strategy:
17
17
  matrix:
18
- ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', 'head']
19
- duckdb: ['0.7.1', '0.8.0']
18
+ ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-preview1', 'head']
19
+ duckdb: ['0.7.1', '0.8.1']
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v3
@@ -15,8 +15,8 @@ jobs:
15
15
  runs-on: ubuntu-latest
16
16
  strategy:
17
17
  matrix:
18
- ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', 'head']
19
- duckdb: ['0.7.1', '0.8.0']
18
+ ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', '3.3.0-preview1', 'head']
19
+ duckdb: ['0.7.1', '0.8.1']
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v3
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  matrix:
18
18
  ruby: ['2.7.8', '3.0.6', '3.1.4', '3.2.2', 'ucrt', 'mingw', 'mswin', 'head']
19
- duckdb: ['0.7.1', '0.8.0']
19
+ duckdb: ['0.7.1', '0.8.1']
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # ChangeLog
2
2
 
3
+ # 0.8.1
4
+ - bump duckdb to 0.8.1
5
+ - add `DuckDB::Result#chunk_each`, `DuckDB::Result.use_chunk_each=`, `DuckDB::Result#use_chunk_each?`
6
+ The current behavior of `DuckDB::Result#each` is same as older version.
7
+ But `DuckDB::Result#each` behavior will be changed like as `DuckDB::Result#chunk_each` in near future release.
8
+ And there are some breaking changes.
9
+ Write `DuckdDB::Result.use_chunk_each = true` if you want to try new behavior.
10
+ ```
11
+ DuckDB::Result.use_chunk_each = true
12
+
13
+ result = con.query('SELECT ....')
14
+ result.each do |record| # <= each method behavior is same as DuckDB::Result#chunk_each
15
+ ...
16
+ end
17
+ ```
18
+ Thanks to @stephenprater.
19
+ - support enum type in DuckDB::Result#chunk_each.
20
+ - support uuid type in DuckDB::Result#chunk_each.
21
+
22
+ ## Breaking Change
23
+
24
+ - DuckDB::Config.set_config does not raise exception when invalid key specified.
25
+ Instead, DuckDB::Database.open raises DuckDB::Error with invalid key configuration.
26
+
3
27
  # 0.8.0
4
28
  - bump duckdb to 0.8.0
5
29
  - add DuckDB::Result#_to_decimal_internal
data/Dockerfile CHANGED
@@ -1,7 +1,7 @@
1
- ARG RUBY_VERSION=3.2.1
1
+ ARG RUBY_VERSION=3.2.2
2
2
  FROM ruby:${RUBY_VERSION}
3
3
 
4
- ARG DUCKDB_VERSION=0.7.1
4
+ ARG DUCKDB_VERSION=0.8.0
5
5
 
6
6
  RUN apt update -qq && \
7
7
  apt install -y build-essential curl git wget
data/Gemfile.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (0.8.0)
4
+ duckdb (0.8.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  benchmark-ips (2.12.0)
10
- minitest (5.18.0)
10
+ minitest (5.18.1)
11
11
  rake (13.0.6)
12
- rake-compiler (1.2.1)
12
+ rake-compiler (1.2.3)
13
13
  rake
14
- stackprof (0.2.24)
14
+ stackprof (0.2.25)
15
15
 
16
16
  PLATFORMS
17
17
  ruby
@@ -27,4 +27,4 @@ DEPENDENCIES
27
27
  stackprof
28
28
 
29
29
  BUNDLED WITH
30
- 2.4.9
30
+ 2.4.10
data/ext/duckdb/duckdb.c CHANGED
@@ -2,23 +2,17 @@
2
2
 
3
3
  VALUE mDuckDB;
4
4
 
5
- #ifdef HAVE_DUCKDB_H_GE_V060
6
5
  static VALUE duckdb_s_library_version(VALUE self);
7
- #endif
8
6
 
9
- #ifdef HAVE_DUCKDB_H_GE_V060
10
7
  static VALUE duckdb_s_library_version(VALUE self) {
11
8
  return rb_str_new2(duckdb_library_version());
12
9
  }
13
- #endif
14
10
 
15
11
  void
16
12
  Init_duckdb_native(void) {
17
13
  mDuckDB = rb_define_module("DuckDB");
18
14
 
19
- #ifdef HAVE_DUCKDB_H_GE_V060
20
15
  rb_define_singleton_method(mDuckDB, "library_version", duckdb_s_library_version, 0);
21
- #endif
22
16
 
23
17
  init_duckdb_error();
24
18
  init_duckdb_database();
@@ -29,5 +23,4 @@ Init_duckdb_native(void) {
29
23
  init_duckdb_blob();
30
24
  init_duckdb_appender();
31
25
  init_duckdb_config();
32
-
33
26
  }
@@ -20,12 +20,12 @@ end
20
20
 
21
21
  dir_config('duckdb')
22
22
 
23
- check_duckdb_library('duckdb_pending_prepared', '0.5.0')
24
-
25
- # check duckdb >= 0.6.0
26
- have_func('duckdb_value_string', 'duckdb.h')
23
+ check_duckdb_library('duckdb_extract_statements', '0.7.0')
27
24
 
28
25
  # check duckdb >= 0.7.0
29
26
  have_func('duckdb_extract_statements', 'duckdb.h')
30
27
 
28
+ # check duckdb >= 0.8.0
29
+ have_func('duckdb_string_is_inlined', 'duckdb.h')
30
+
31
31
  create_makefile('duckdb/duckdb_native')
data/ext/duckdb/result.c CHANGED
@@ -37,6 +37,23 @@ static VALUE duckdb_result__enum_internal_type(VALUE oDuckDBResult, VALUE col_id
37
37
  static VALUE duckdb_result__enum_dictionary_size(VALUE oDuckDBResult, VALUE col_idx);
38
38
  static VALUE duckdb_result__enum_dictionary_value(VALUE oDuckDBResult, VALUE col_idx, VALUE idx);
39
39
 
40
+ #ifdef HAVE_DUCKDB_H_GE_V080
41
+ static VALUE vector_date(void *vector_data, idx_t row_idx);
42
+ static VALUE vector_timestamp(void* vector_data, idx_t row_idx);
43
+ static VALUE vector_interval(void* vector_data, idx_t row_idx);
44
+ static VALUE vector_blob(void* vector_data, idx_t row_idx);
45
+ static VALUE vector_varchar(void* vector_data, idx_t row_idx);
46
+ static VALUE vector_hugeint(void* vector_data, idx_t row_idx);
47
+ static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx);
48
+ static VALUE vector_enum(duckdb_logical_type ty, void* vector_data, idx_t row_idx);
49
+ static VALUE vector_list(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx);
50
+ static VALUE vector_map(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx);
51
+ static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx);
52
+ static VALUE vector_uuid(void* vector_data, idx_t row_idx);
53
+ static VALUE vector_value(duckdb_vector vector, idx_t row_idx);
54
+ static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult);
55
+ #endif
56
+
40
57
  static const rb_data_type_t result_data_type = {
41
58
  "DuckDB/Result",
42
59
  {NULL, deallocate, memsize,},
@@ -300,25 +317,15 @@ static VALUE duckdb_result__to_double(VALUE oDuckDBResult, VALUE row_idx, VALUE
300
317
 
301
318
  static VALUE duckdb_result__to_string(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) {
302
319
  rubyDuckDBResult *ctx;
303
- #ifdef HAVE_DUCKDB_H_GE_V060
304
320
  duckdb_string p;
305
- #else
306
- char *p;
307
- #endif
308
321
  VALUE obj;
322
+
309
323
  TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
310
324
 
311
- #ifdef HAVE_DUCKDB_H_GE_V060
312
325
  p = duckdb_value_string(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx));
313
326
  if (p.data) {
314
327
  obj = rb_utf8_str_new(p.data, p.size);
315
328
  duckdb_free(p.data);
316
- #else
317
- p = duckdb_value_varchar(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx));
318
- if (p) {
319
- obj = rb_utf8_str_new_cstr(p);
320
- duckdb_free(p);
321
- #endif
322
329
  return obj;
323
330
  }
324
331
  return Qnil;
@@ -326,23 +333,13 @@ static VALUE duckdb_result__to_string(VALUE oDuckDBResult, VALUE row_idx, VALUE
326
333
 
327
334
  static VALUE duckdb_result__to_string_internal(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) {
328
335
  rubyDuckDBResult *ctx;
329
- #ifdef HAVE_DUCKDB_H_GE_V060
330
336
  duckdb_string p;
331
- #else
332
- char *p;
333
- #endif
334
337
  VALUE obj;
335
338
  TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
336
339
 
337
- #ifdef HAVE_DUCKDB_H_GE_V060
338
340
  p = duckdb_value_string_internal(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx));
339
341
  if (p.data) {
340
342
  obj = rb_utf8_str_new(p.data, p.size);
341
- #else
342
- p = duckdb_value_varchar_internal(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx));
343
- if (p) {
344
- obj = rb_utf8_str_new_cstr(p);
345
- #endif
346
343
  return obj;
347
344
  }
348
345
  return Qnil;
@@ -403,6 +400,318 @@ VALUE create_result(void) {
403
400
  return allocate(cDuckDBResult);
404
401
  }
405
402
 
403
+ #ifdef HAVE_DUCKDB_H_GE_V080
404
+ static VALUE vector_date(void *vector_data, idx_t row_idx) {
405
+ duckdb_date_struct date = duckdb_from_date(((duckdb_date *) vector_data)[row_idx]);
406
+ VALUE mConverter = rb_const_get(mDuckDB, rb_intern("Converter"));
407
+
408
+ return rb_funcall(mConverter, rb_intern("_to_date"), 3,
409
+ INT2FIX(date.year),
410
+ INT2FIX(date.month),
411
+ INT2FIX(date.day)
412
+ );
413
+ }
414
+
415
+ static VALUE vector_timestamp(void* vector_data, idx_t row_idx) {
416
+ duckdb_timestamp_struct data = duckdb_from_timestamp(((duckdb_timestamp *)vector_data)[row_idx]);
417
+ VALUE mConverter = rb_const_get(mDuckDB, rb_intern("Converter"));
418
+ return rb_funcall(mConverter, rb_intern("_to_time"), 7,
419
+ INT2FIX(data.date.year),
420
+ INT2FIX(data.date.month),
421
+ INT2FIX(data.date.day),
422
+ INT2FIX(data.time.hour),
423
+ INT2FIX(data.time.min),
424
+ INT2FIX(data.time.sec),
425
+ INT2NUM(data.time.micros)
426
+ );
427
+ }
428
+
429
+ static VALUE vector_interval(void* vector_data, idx_t row_idx) {
430
+ duckdb_interval data = ((duckdb_interval *)vector_data)[row_idx];
431
+ VALUE mConverter = rb_const_get(mDuckDB, rb_intern("Converter"));
432
+ return rb_funcall(mConverter, rb_intern("_to_interval_from_vector"), 3,
433
+ INT2NUM(data.months),
434
+ INT2NUM(data.days),
435
+ LL2NUM(data.micros)
436
+ );
437
+ }
438
+
439
+ static VALUE vector_blob(void* vector_data, idx_t row_idx) {
440
+ duckdb_string_t s = (((duckdb_string_t *)vector_data)[row_idx]);
441
+ if(duckdb_string_is_inlined(s)) {
442
+ return rb_str_new(s.value.inlined.inlined, s.value.inlined.length);
443
+ } else {
444
+ return rb_str_new(s.value.pointer.ptr, s.value.pointer.length);
445
+ }
446
+ }
447
+
448
+ static VALUE vector_varchar(void* vector_data, idx_t row_idx) {
449
+ duckdb_string_t s = (((duckdb_string_t *)vector_data)[row_idx]);
450
+ if(duckdb_string_is_inlined(s)) {
451
+ return rb_utf8_str_new(s.value.inlined.inlined, s.value.inlined.length);
452
+ } else {
453
+ return rb_utf8_str_new(s.value.pointer.ptr, s.value.pointer.length);
454
+ }
455
+ }
456
+
457
+ static VALUE vector_hugeint(void* vector_data, idx_t row_idx) {
458
+ duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
459
+ VALUE mConverter = rb_const_get(mDuckDB, rb_intern("Converter"));
460
+ return rb_funcall(mConverter, rb_intern("_to_hugeint_from_vector"), 2,
461
+ ULL2NUM(hugeint.lower),
462
+ LL2NUM(hugeint.upper)
463
+ );
464
+ }
465
+
466
+ static VALUE vector_decimal(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
467
+ uint8_t width = duckdb_decimal_width(ty);
468
+ uint8_t scale = duckdb_decimal_scale(ty);
469
+ VALUE mConverter = rb_const_get(mDuckDB, rb_intern("Converter"));
470
+ duckdb_type type = duckdb_decimal_internal_type(ty);
471
+ duckdb_hugeint value;
472
+
473
+ value.upper = 0;
474
+ value.lower = 0;
475
+
476
+ switch(duckdb_decimal_internal_type(ty)) {
477
+ case DUCKDB_TYPE_HUGEINT:
478
+ value = ((duckdb_hugeint *) vector_data)[row_idx];
479
+ break;
480
+ default:
481
+ rb_warn("Unknown decimal internal type %d", type);
482
+ }
483
+
484
+ return rb_funcall(mConverter, rb_intern("_to_decimal_from_vector"), 4,
485
+ INT2FIX(width),
486
+ INT2FIX(scale),
487
+ ULL2NUM(value.lower),
488
+ LL2NUM(value.upper)
489
+ );
490
+ }
491
+
492
+ static VALUE vector_enum(duckdb_logical_type ty, void* vector_data, idx_t row_idx) {
493
+ duckdb_type type = duckdb_enum_internal_type(ty);
494
+ uint8_t index;
495
+ char *p;
496
+ VALUE value = Qnil;
497
+
498
+ switch(type) {
499
+ case DUCKDB_TYPE_UTINYINT:
500
+ index = ((uint8_t *) vector_data)[row_idx];
501
+ p = duckdb_enum_dictionary_value(ty, index);
502
+ if (p) {
503
+ value = rb_utf8_str_new_cstr(p);
504
+ duckdb_free(p);
505
+ }
506
+ break;
507
+ default:
508
+ rb_warn("Unknown enum internal type %d", type);
509
+ }
510
+ return value;
511
+ }
512
+
513
+ static VALUE vector_list(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx) {
514
+ // Lists are stored as vectors within vectors
515
+
516
+ VALUE ary = Qnil;
517
+ VALUE element = Qnil;
518
+ idx_t i;
519
+
520
+ // rb_warn("ruby-duckdb does not support List yet");
521
+
522
+ duckdb_logical_type child_logical_type = duckdb_list_type_child_type(ty);
523
+ // duckdb_type child_type = duckdb_get_type_id(child_logical_type);
524
+
525
+ duckdb_list_entry list_entry = ((duckdb_list_entry *)vector)[row_idx];
526
+ ary = rb_ary_new2(list_entry.length);
527
+
528
+ for (i = list_entry.offset; i < list_entry.offset + list_entry.length; ++i) {
529
+ /*
530
+ * FIXME: How to get the child element?
531
+ */
532
+ // element = ???
533
+ rb_ary_store(ary, i - list_entry.offset, element);
534
+ }
535
+ duckdb_destroy_logical_type(&child_logical_type);
536
+ return ary;
537
+ }
538
+
539
+ static VALUE vector_map(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx) {
540
+ VALUE hash = rb_hash_new();
541
+
542
+ duckdb_logical_type key_logical_type = duckdb_map_type_key_type(ty);
543
+ duckdb_logical_type value_logical_type = duckdb_map_type_value_type(ty);
544
+ // duckdb_type key_type = duckdb_get_type_id(key_logical_type);
545
+ // duckdb_type value_type = duckdb_get_type_id(value_logical_type);
546
+
547
+ /*
548
+ * FIXME: How to get key and value?
549
+ *
550
+ * rb_hash_aset(hash, key, value);
551
+ */
552
+ duckdb_destroy_logical_type(&key_logical_type);
553
+ duckdb_destroy_logical_type(&value_logical_type);
554
+ return hash;
555
+ }
556
+
557
+ static VALUE vector_struct(duckdb_logical_type ty, duckdb_vector vector, idx_t row_idx) {
558
+ VALUE hash = rb_hash_new();
559
+ VALUE value = Qnil;
560
+ VALUE key = Qnil;
561
+ char *p;
562
+
563
+ idx_t child_count = duckdb_struct_type_child_count(ty);
564
+
565
+ for (idx_t i = 0; i < child_count; ++i) {
566
+ p = duckdb_struct_type_child_name(ty, i);
567
+ if (p) {
568
+ key = rb_str_new2(p);
569
+ // FIXME
570
+ // How to get Struct values?
571
+ // value = ???
572
+ // duckdb_vector child_vector = duckdb_struct_vector_get_child(vector, i);
573
+ // VALUE value = vector_value(child_vector, i);
574
+ rb_hash_aset(hash, key, value);
575
+ duckdb_free(p);
576
+ }
577
+ }
578
+
579
+ return hash;
580
+ }
581
+
582
+ static VALUE vector_uuid(void* vector_data, idx_t row_idx) {
583
+ duckdb_hugeint hugeint = ((duckdb_hugeint *)vector_data)[row_idx];
584
+ VALUE mConverter = rb_const_get(mDuckDB, rb_intern("Converter"));
585
+ return rb_funcall(mConverter, rb_intern("_to_uuid_from_vector"), 2,
586
+ ULL2NUM(hugeint.lower),
587
+ LL2NUM(hugeint.upper)
588
+ );
589
+ }
590
+
591
+ static VALUE vector_value(duckdb_vector vector, idx_t row_idx) {
592
+ uint64_t *validity;
593
+ duckdb_logical_type ty;
594
+ duckdb_type type_id;
595
+ void* vector_data;
596
+ VALUE obj = Qnil;
597
+
598
+ validity = duckdb_vector_get_validity(vector);
599
+ if (!duckdb_validity_row_is_valid(validity, row_idx)) {
600
+ return Qnil;
601
+ }
602
+
603
+ ty = duckdb_vector_get_column_type(vector);
604
+ type_id = duckdb_get_type_id(ty);
605
+ vector_data = duckdb_vector_get_data(vector);
606
+
607
+ switch(type_id) {
608
+ case DUCKDB_TYPE_INVALID:
609
+ obj = Qnil;
610
+ break;
611
+ case DUCKDB_TYPE_BOOLEAN:
612
+ obj = (((bool*) vector_data)[row_idx]) ? Qtrue : Qfalse;
613
+ break;
614
+ case DUCKDB_TYPE_TINYINT:
615
+ obj = INT2FIX(((int8_t *) vector_data)[row_idx]);
616
+ break;
617
+ case DUCKDB_TYPE_SMALLINT:
618
+ obj = INT2FIX(((int16_t *) vector_data)[row_idx]);
619
+ break;
620
+ case DUCKDB_TYPE_INTEGER:
621
+ obj = INT2NUM(((int32_t *) vector_data)[row_idx]);
622
+ break;
623
+ case DUCKDB_TYPE_BIGINT:
624
+ obj = LL2NUM(((int64_t *) vector_data)[row_idx]);
625
+ break;
626
+ case DUCKDB_TYPE_HUGEINT:
627
+ obj = vector_hugeint(vector_data, row_idx);
628
+ break;
629
+ case DUCKDB_TYPE_FLOAT:
630
+ obj = DBL2NUM((((float *) vector_data)[row_idx]));
631
+ break;
632
+ case DUCKDB_TYPE_DOUBLE:
633
+ obj = DBL2NUM((((double *) vector_data)[row_idx]));
634
+ break;
635
+ case DUCKDB_TYPE_DATE:
636
+ obj = vector_date(vector_data, row_idx);
637
+ break;
638
+ case DUCKDB_TYPE_TIMESTAMP:
639
+ obj = vector_timestamp(vector_data, row_idx);
640
+ break;
641
+ case DUCKDB_TYPE_INTERVAL:
642
+ obj = vector_interval(vector_data, row_idx);
643
+ break;
644
+ case DUCKDB_TYPE_VARCHAR:
645
+ obj = vector_varchar(vector_data, row_idx);
646
+ break;
647
+ case DUCKDB_TYPE_BLOB:
648
+ obj = vector_blob(vector_data, row_idx);
649
+ break;
650
+ case DUCKDB_TYPE_DECIMAL:
651
+ obj = vector_decimal(ty, vector_data, row_idx);
652
+ break;
653
+ case DUCKDB_TYPE_ENUM:
654
+ obj = vector_enum(ty, vector_data, row_idx);
655
+ break;
656
+ case DUCKDB_TYPE_LIST:
657
+ obj = vector_list(ty, vector_data, row_idx);
658
+ break;
659
+ case DUCKDB_TYPE_MAP:
660
+ obj = vector_map(ty, vector_data, row_idx);
661
+ break;
662
+ case DUCKDB_TYPE_STRUCT:
663
+ obj = vector_struct(ty, vector_data, row_idx);
664
+ break;
665
+ case DUCKDB_TYPE_UUID:
666
+ obj = vector_uuid(vector_data, row_idx);
667
+ break;
668
+ default:
669
+ rb_warn("Unknown type %d", type_id);
670
+ obj = Qnil;
671
+ }
672
+
673
+ duckdb_destroy_logical_type(&ty);
674
+ return obj;
675
+ }
676
+
677
+ static VALUE duckdb_result_chunk_each(VALUE oDuckDBResult) {
678
+ rubyDuckDBResult *ctx;
679
+ VALUE row;
680
+ idx_t col_count;
681
+ idx_t row_count;
682
+ idx_t chunk_count;
683
+ idx_t col_idx;
684
+ idx_t row_idx;
685
+ idx_t chunk_idx;
686
+ duckdb_data_chunk chunk;
687
+ duckdb_vector vector;
688
+ VALUE val;
689
+
690
+ TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx);
691
+
692
+ col_count = duckdb_column_count(&(ctx->result));
693
+ chunk_count = duckdb_result_chunk_count(ctx->result);
694
+
695
+ RETURN_ENUMERATOR(oDuckDBResult, 0, 0);
696
+
697
+ for (chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) {
698
+ chunk = duckdb_result_get_chunk(ctx->result, chunk_idx);
699
+ row_count = duckdb_data_chunk_get_size(chunk);
700
+ for (row_idx = 0; row_idx < row_count; row_idx++) {
701
+ row = rb_ary_new2(col_count);
702
+ for (col_idx = 0; col_idx < col_count; col_idx++) {
703
+ vector = duckdb_data_chunk_get_vector(chunk, col_idx);
704
+ val = vector_value(vector, row_idx);
705
+ rb_ary_store(row, col_idx, val);
706
+ }
707
+ rb_yield(row);
708
+ }
709
+ duckdb_destroy_data_chunk(&chunk);
710
+ }
711
+ return Qnil;
712
+ }
713
+ #endif
714
+
406
715
  void init_duckdb_result(void) {
407
716
  cDuckDBResult = rb_define_class_under(mDuckDB, "Result", rb_cObject);
408
717
  rb_define_alloc_func(cDuckDBResult, allocate);
@@ -428,4 +737,7 @@ void init_duckdb_result(void) {
428
737
  rb_define_private_method(cDuckDBResult, "_enum_internal_type", duckdb_result__enum_internal_type, 1);
429
738
  rb_define_private_method(cDuckDBResult, "_enum_dictionary_size", duckdb_result__enum_dictionary_size, 1);
430
739
  rb_define_private_method(cDuckDBResult, "_enum_dictionary_value", duckdb_result__enum_dictionary_value, 2);
740
+ #ifdef HAVE_DUCKDB_H_GE_V080
741
+ rb_define_method(cDuckDBResult, "chunk_each", duckdb_result_chunk_each, 0);
742
+ #endif
431
743
  }
@@ -4,14 +4,14 @@
4
4
  #include "ruby.h"
5
5
  #include <duckdb.h>
6
6
 
7
- #ifdef HAVE_DUCKDB_VALUE_STRING
8
- #define HAVE_DUCKDB_H_GE_V060 1
9
- #endif
10
-
11
7
  #ifdef HAVE_DUCKDB_EXTRACT_STATEMENTS
12
8
  #define HAVE_DUCKDB_H_GE_V070 1
13
9
  #endif
14
10
 
11
+ #ifdef HAVE_DUCKDB_STRING_IS_INLINED
12
+ #define HAVE_DUCKDB_H_GE_V080 1
13
+ #endif
14
+
15
15
  #include "./error.h"
16
16
  #include "./database.h"
17
17
  #include "./connection.h"
@@ -1,8 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'date'
4
+
3
5
  module DuckDB
4
6
  module Converter
5
7
  HALF_HUGEINT = 1 << 64
8
+ FLIP_HUGEINT = 1 << 63
9
+
10
+ module_function
11
+
12
+ def _to_date(year, month, day)
13
+ Date.new(year, month, day)
14
+ end
15
+
16
+ def _to_time(year, month, day, hour, minute, second, microsecond)
17
+ Time.local(year, month, day, hour, minute, second, microsecond)
18
+ end
19
+
20
+ def _to_hugeint_from_vector(lower, upper)
21
+ (upper * HALF_HUGEINT) + lower
22
+ end
23
+
24
+ def _to_decimal_from_vector(_width, scale, lower, upper)
25
+ v = _to_hugeint_from_vector(lower, upper).to_s
26
+ v[-scale, 0] = '.'
27
+ BigDecimal(v)
28
+ end
29
+
30
+ def _to_interval_from_vector(months, days, micros)
31
+ hash = { year: 0, month: 0, day: 0, hour: 0, min: 0, sec: 0, usec: 0 }
32
+ hash[:year] = months / 12
33
+ hash[:month] = months % 12
34
+ hash[:day] = days
35
+ hash[:hour] = micros / 3_600_000_000
36
+ hash[:min] = (micros % 3_600_000_000) / 60_000_000
37
+ hash[:sec] = (micros % 60_000_000) / 1_000_000
38
+ hash[:usec] = micros % 1_000_000
39
+ hash
40
+ end
41
+
42
+ def _to_uuid_from_vector(lower, upper)
43
+ upper = upper ^ FLIP_HUGEINT
44
+ upper += HALF_HUGEINT if upper.negative?
45
+
46
+ str = _to_hugeint_from_vector(lower, upper).to_s(16).rjust(32, '0')
47
+ "#{str[0, 8]}-#{str[8, 4]}-#{str[12, 4]}-#{str[16, 4]}-#{str[20, 12]}"
48
+ end
6
49
 
7
50
  private
8
51
 
data/lib/duckdb/result.rb CHANGED
@@ -42,11 +42,27 @@ module DuckDB
42
42
  alias column_size column_count
43
43
  alias row_size row_count
44
44
 
45
+ def self.use_chunk_each=(val)
46
+ raise DuckDB::Error, 'chunk_each is not available. Install duckdb >= 0.8.0 and rerun `gem install duckdb`.' unless instance_methods.include?(:chunk_each)
47
+
48
+ @use_chunk_each = val
49
+ end
50
+
51
+ def self.use_chunk_each?
52
+ !!@use_chunk_each
53
+ end
54
+
45
55
  def each
46
- return to_enum { row_size } unless block_given?
56
+ if self.class.use_chunk_each?
57
+ return chunk_each unless block_given?
58
+
59
+ chunk_each { |row| yield row }
60
+ else
61
+ return to_enum { row_size } unless block_given?
47
62
 
48
- row_count.times do |row_index|
49
- yield row(row_index)
63
+ row_count.times do |row_index|
64
+ yield row(row_index)
65
+ end
50
66
  end
51
67
  end
52
68
 
@@ -3,5 +3,5 @@
3
3
  module DuckDB
4
4
  # The version string of ruby-duckdb.
5
5
  # Currently, ruby-duckdb is NOT semantic versioning.
6
- VERSION = '0.8.0'.freeze
6
+ VERSION = '0.8.1'
7
7
  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.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masaki Suketa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-20 00:00:00.000000000 Z
11
+ date: 2023-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler