duckdb 0.7.1 → 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: 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.