duckdb 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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