duckdb 0.7.1 → 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: 469588c48fb9f9d16254cd6f78f3fd4ceb1e6886e3fc859a507d635542ba50fa
4
- data.tar.gz: 1ccee32eb696806c13da87d5c8825965575575e83c45e466712a69bfa107547e
3
+ metadata.gz: dab5e8d5f3beafce29f2d545b736b34b3502f2f31120d1d7d0714fdb83512457
4
+ data.tar.gz: a73a7438ec5762af143b8590923b0fd3c54ec99926aa48b485346e943fe66916
5
5
  SHA512:
6
- metadata.gz: ebd03d8e45cb57530924a62c94e02df312b6d93624c303a1f05fb1a886b9c92aaae208feaa4419774dc325ba4078c3d90b281819dbc695f0d5a37139c787a481
7
- data.tar.gz: 6096e668ea12bd32950cea838844537ea3ed872398d944e88473f4efc9f9088320dc8f565cd62e9c48522596062a2034d3c89456afc4b2952df42d57492b0b2a
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.7', '3.0.5', '3.1.3', '3.2.1', 'head']
19
- duckdb: ['0.7.1', '0.6.1']
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
@@ -52,11 +52,14 @@ jobs:
52
52
  cp duckdb-v$DUCKDB_VERSION/src/include/*.h /usr/local/include
53
53
  cp duckdb-v$DUCKDB_VERSION/build/release/src/*.dylib /usr/local/lib
54
54
 
55
- - name: Build and test with Rake with Ruby ${{ matrix.ruby }}
55
+ - name: Build with Ruby ${{ matrix.ruby }}
56
56
  run: |
57
- ruby -v
58
57
  bundle install --jobs 4 --retry 3
59
- bundle exec rake
58
+ rake build
59
+
60
+ - name: run test with Ruby ${{ matrix.ruby }}
61
+ run: |
62
+ rake test
60
63
 
61
64
  post-test:
62
65
  name: All tests passed on macos
@@ -15,8 +15,8 @@ jobs:
15
15
  runs-on: ubuntu-latest
16
16
  strategy:
17
17
  matrix:
18
- ruby: ['2.7.7', '3.0.5', '3.1.3', '3.2.1', 'head']
19
- duckdb: ['0.7.1', '0.6.1']
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
@@ -45,13 +45,19 @@ jobs:
45
45
  cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.so duckdb-v$DUCKDB_VERSION/build/release/src
46
46
  cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/
47
47
 
48
- - name: Build and test with Rake with Ruby ${{ matrix.ruby }}
48
+ - name: Build with Ruby ${{ matrix.ruby }}
49
49
  env:
50
50
  DUCKDB_VERSION: ${{ matrix.duckdb }}
51
51
  run: |
52
52
  gem install bundler
53
53
  bundle install --jobs 4 --retry 3
54
- bundle exec rake -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/
54
+ bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/src/include --with-duckdb-lib=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src/
55
+
56
+ - name: test with Ruby ${{ matrix.ruby }}
57
+ env:
58
+ DUCKDB_VERSION: ${{ matrix.duckdb }}
59
+ run: |
60
+ rake test
55
61
 
56
62
  post-test:
57
63
  name: All tests passed on Ubuntu
@@ -15,8 +15,8 @@ jobs:
15
15
  runs-on: windows-latest
16
16
  strategy:
17
17
  matrix:
18
- ruby: ['2.7.7', '3.0.5', '3.1.3', '3.2.1', 'ucrt', 'mingw', 'mswin', 'head']
19
- duckdb: ['0.7.1', '0.6.1']
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.1']
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
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
+
27
+ # 0.8.0
28
+ - bump duckdb to 0.8.0
29
+ - add DuckDB::Result#_to_decimal_internal
30
+ - add DuckDB::Result#_to_hugeint_internal
31
+
32
+ ## Breaking Change
33
+ - DuckDB::Result returns BigDecimal object instead of String object if the column type is DECIMAL.
34
+
35
+ # 0.7.1
3
36
  - bump duckdb to 0.7.1
4
37
  - fix docker build error on M1 Mac
5
38
 
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 CHANGED
@@ -2,3 +2,8 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in duckdb.gemspec
4
4
  gemspec
5
+
6
+ if /(linux|darwin)/ =~ RUBY_PLATFORM
7
+ gem 'benchmark-ips'
8
+ gem 'stackprof'
9
+ end
data/Gemfile.lock CHANGED
@@ -1,23 +1,30 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (0.7.1)
4
+ duckdb (0.8.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- minitest (5.17.0)
9
+ benchmark-ips (2.12.0)
10
+ minitest (5.18.1)
10
11
  rake (13.0.6)
11
- rake-compiler (1.2.1)
12
+ rake-compiler (1.2.3)
12
13
  rake
14
+ stackprof (0.2.25)
13
15
 
14
16
  PLATFORMS
15
17
  ruby
16
18
  x86_64-linux
17
19
 
18
20
  DEPENDENCIES
21
+ benchmark-ips
19
22
  bundler (~> 2.3)
20
23
  duckdb!
21
24
  minitest (~> 5.0)
22
25
  rake (~> 13.0)
23
26
  rake-compiler
27
+ stackprof
28
+
29
+ BUNDLED WITH
30
+ 2.4.10
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'duckdb'
5
+ require 'benchmark/ips'
6
+
7
+ db = DuckDB::Database.open
8
+ con = db.connect
9
+ con.query('CREATE TABLE decimals (decimal_value DECIMAL(38, 3))')
10
+ con.query('INSERT INTO decimals VALUES (1234567890123.456)')
11
+ result = con.query('SELECT decimal_value FROM decimals')
12
+
13
+ Benchmark.ips do |x|
14
+ x.report('_to_decimal') { result.send(:_to_decimal, 0, 0) }
15
+ x.report('_to_decimal_internal') { result.send(:_to_decimal_internal, 0, 0) }
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'duckdb'
5
+ require 'benchmark/ips'
6
+
7
+ db = DuckDB::Database.open
8
+ con = db.connect
9
+ con.query('CREATE TABLE hugeints (hugeint_value HUGEINT)')
10
+ con.query('INSERT INTO hugeints VALUES (123456789012345678901234567890123456789)')
11
+ result = con.query('SELECT hugeint_value FROM hugeints')
12
+
13
+ Benchmark.ips do |x|
14
+ x.report('_to_hugeint') { result.send(:_to_hugeint, 0, 0) }
15
+ x.report('_to_hugeint_internal') { result.send(:_to_hugeint_internal, 0, 0) }
16
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'duckdb'
5
+ require 'stackprof'
6
+
7
+ db = DuckDB::Database.open
8
+ con = db.connect
9
+ con.query('CREATE TABLE hugeints (hugeint_value HUGEINT)')
10
+ con.query('INSERT INTO hugeints VALUES (123456789012345678901234567890123456789)')
11
+ result = con.query('SELECT hugeint_value FROM hugeints')
12
+
13
+ def profile(name, &block)
14
+ profile = StackProf.run(mode: :wall, interval: 1_000) do
15
+ 2_000_000.times(&block)
16
+ end
17
+
18
+ result = StackProf::Report.new(profile)
19
+ puts
20
+ puts "=== #{name} ==="
21
+ result.print_text
22
+ puts
23
+ end
24
+
25
+ profile(:_to_hugeint) { result.send(:_to_hugeint, 0, 0) }
26
+ profile(:_to_hugeint_internal) { result.send(:_to_hugeint_internal, 0, 0) }
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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'date'
2
4
  require 'time'
3
5
  require_relative './converter'
data/lib/duckdb/column.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DuckDB
2
4
  class Column
3
5
  #
data/lib/duckdb/config.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DuckDB
2
4
  if defined?(DuckDB::Config)
3
5
  # The DuckDB::Config encapsulates DuckDB Configuration.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DuckDB
2
4
  # The DuckDB::Connection encapsulates connection with DuckDB database.
3
5
  #
@@ -1,6 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
1
5
  module DuckDB
2
6
  module Converter
3
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
4
49
 
5
50
  private
6
51
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DuckDB
2
4
  # The Database class encapsulates a DuckDB database.
3
5
  #
@@ -1,4 +1,5 @@
1
1
  require 'date'
2
+ require 'bigdecimal'
2
3
  require_relative './converter'
3
4
 
4
5
  module DuckDB
@@ -192,6 +193,8 @@ module DuckDB
192
193
  bind_varchar(i, value.strftime('%Y-%m-%d %H:%M:%S.%N'))
193
194
  when Date
194
195
  bind_varchar(i, value.strftime('%Y-%m-%d'))
196
+ when BigDecimal
197
+ bind_varchar(i, value.to_s('F'))
195
198
  else
196
199
  raise(DuckDB::Error, "not supported type `#{value}` (#{value.class})")
197
200
  end
data/lib/duckdb/result.rb CHANGED
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bigdecimal'
4
+
1
5
  module DuckDB
2
6
  # The Result class encapsulates a execute result of DuckDB database.
3
7
  #
@@ -28,8 +32,9 @@ module DuckDB
28
32
  5 => :_to_bigint,
29
33
  10 => :_to_float,
30
34
  11 => :_to_double,
31
- 16 => :_to_hugeint,
35
+ 16 => :_to_hugeint_internal,
32
36
  18 => :_to_blob,
37
+ 19 => :_to_decimal_internal
33
38
  }
34
39
 
35
40
  ToRuby.default = :_to_string
@@ -37,11 +42,27 @@ module DuckDB
37
42
  alias column_size column_count
38
43
  alias row_size row_count
39
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
+
40
55
  def each
41
- return to_enum { row_size } unless block_given?
56
+ if self.class.use_chunk_each?
57
+ return chunk_each unless block_given?
42
58
 
43
- row_count.times do |row_index|
44
- yield row(row_index)
59
+ chunk_each { |row| yield row }
60
+ else
61
+ return to_enum { row_size } unless block_given?
62
+
63
+ row_count.times do |row_index|
64
+ yield row(row_index)
65
+ end
45
66
  end
46
67
  end
47
68
 
@@ -70,5 +91,21 @@ module DuckDB
70
91
  def _to_hugeint(row, col)
71
92
  _to_string(row, col).to_i
72
93
  end
94
+
95
+ def _to_hugeint_internal(row, col)
96
+ lower, upper = __to_hugeint_internal(row, col)
97
+ upper * Converter::HALF_HUGEINT + lower
98
+ end
99
+
100
+ def _to_decimal(row, col)
101
+ BigDecimal(_to_string(row, col))
102
+ end
103
+
104
+ def _to_decimal_internal(row, col)
105
+ lower, upper, _width, scale = __to_decimal_internal(row, col)
106
+ v = (upper * Converter::HALF_HUGEINT + lower).to_s
107
+ v[-scale, 0] = '.'
108
+ BigDecimal(v)
109
+ end
73
110
  end
74
111
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DuckDB
2
4
  # The version string of ruby-duckdb.
3
5
  # Currently, ruby-duckdb is NOT semantic versioning.
4
- VERSION = '0.7.1'.freeze
6
+ VERSION = '0.8.1'
5
7
  end
data/lib/duckdb.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'duckdb/duckdb_native'
2
4
  require 'duckdb/library_version'
3
5
  require 'duckdb/version'
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.7.1
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-03-05 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
@@ -87,6 +87,9 @@ files:
87
87
  - LICENSE
88
88
  - README.md
89
89
  - Rakefile
90
+ - benchmark/to_bigdecimal_ips.rb
91
+ - benchmark/to_hugeint_ips.rb
92
+ - benchmark/to_hugeint_profile.rb
90
93
  - bin/console
91
94
  - bin/setup
92
95
  - docker-compose.yml
@@ -148,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
151
  - !ruby/object:Gem::Version
149
152
  version: '0'
150
153
  requirements: []
151
- rubygems_version: 3.4.6
154
+ rubygems_version: 3.4.10
152
155
  signing_key:
153
156
  specification_version: 4
154
157
  summary: This module is Ruby binding for DuckDB database engine.