duckdb 1.5.0.2 → 1.5.1.0

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_on_macos.yml +28 -20
  3. data/.github/workflows/test_on_ubuntu.yml +30 -18
  4. data/.github/workflows/test_on_windows.yml +15 -9
  5. data/CHANGELOG.md +23 -0
  6. data/Dockerfile +1 -1
  7. data/Gemfile.lock +5 -14
  8. data/README.md +3 -5
  9. data/ext/duckdb/client_context.c +70 -0
  10. data/ext/duckdb/client_context.h +14 -0
  11. data/ext/duckdb/converter.h +29 -0
  12. data/ext/duckdb/conveter.c +162 -0
  13. data/ext/duckdb/duckdb.c +6 -3
  14. data/ext/duckdb/expression.c +104 -0
  15. data/ext/duckdb/expression.h +13 -0
  16. data/ext/duckdb/logical_type.c +21 -0
  17. data/ext/duckdb/result.c +9 -142
  18. data/ext/duckdb/ruby-duckdb.h +6 -3
  19. data/ext/duckdb/scalar_function.c +91 -0
  20. data/ext/duckdb/scalar_function.h +1 -0
  21. data/ext/duckdb/scalar_function_bind_info.c +109 -0
  22. data/ext/duckdb/scalar_function_bind_info.h +13 -0
  23. data/ext/duckdb/table_function.c +7 -7
  24. data/ext/duckdb/table_function.h +1 -0
  25. data/ext/duckdb/{bind_info.c → table_function_bind_info.c} +13 -52
  26. data/ext/duckdb/table_function_bind_info.h +14 -0
  27. data/ext/duckdb/{function_info.c → table_function_function_info.c} +6 -6
  28. data/ext/duckdb/{function_info.h → table_function_function_info.h} +3 -3
  29. data/ext/duckdb/{init_info.c → table_function_init_info.c} +6 -6
  30. data/ext/duckdb/table_function_init_info.h +14 -0
  31. data/ext/duckdb/value_impl.c +88 -0
  32. data/ext/duckdb/value_impl.h +2 -0
  33. data/lib/duckdb/appender.rb +1 -1
  34. data/lib/duckdb/client_context.rb +10 -0
  35. data/lib/duckdb/converter/int_to_sym.rb +1 -0
  36. data/lib/duckdb/expression.rb +24 -0
  37. data/lib/duckdb/logical_type.rb +15 -0
  38. data/lib/duckdb/scalar_function/bind_info.rb +35 -0
  39. data/lib/duckdb/scalar_function.rb +100 -9
  40. data/lib/duckdb/table_function/bind_info.rb +34 -0
  41. data/lib/duckdb/table_function/function_info.rb +23 -0
  42. data/lib/duckdb/table_function/init_info.rb +24 -0
  43. data/lib/duckdb/version.rb +1 -1
  44. data/lib/duckdb.rb +20 -3
  45. metadata +20 -11
  46. data/ext/duckdb/bind_info.h +0 -13
  47. data/ext/duckdb/init_info.h +0 -13
  48. data/lib/duckdb/bind_info.rb +0 -32
  49. data/lib/duckdb/function_info.rb +0 -21
  50. data/lib/duckdb/init_info.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35eae50625fd72c7cb1b870ff496d259c0271453404a0646fd05514b4a3f7338
4
- data.tar.gz: e96e82fcbffa7427f63cf8a7af0ba9434b5cb7daefbd9951c3eba4866508d67e
3
+ metadata.gz: c55213e9e388de53b04f29987c7714975ab5c1a8fa10a40ae378189507dae752
4
+ data.tar.gz: a96e6256ce85583fd395d936994d2a871727af8f7ba11fadc40a9d9ca79c15fa
5
5
  SHA512:
6
- metadata.gz: c7fdc287942e832ee9f33fbbf0056add1a7b7fc8db0e633356b7cf73c3d086f1d7a89ac7cf79673d0ecbbecda15ee33d365182c2874a74ac23aaf95270fe90dd
7
- data.tar.gz: 7cc3079783a36442e43b7228223e2ded5cb453184e1eb4344788f5b7c1758e2ba665d8a9d087f6239d84dfb16a389f18fe091bd346a439e7e3c32ed9a333a9ce
6
+ metadata.gz: 67c2d5de633c5999ca07e3deb7c98a091b4eaedb70eacce2d2f7c34b9e8795b012d4415e197d5996ca80eb9c526dc28e86ced8f1d977cc040fcfd8c59a9a3ad2
7
+ data.tar.gz: 38de479e2069a0b4dd1fa8684b2174d6f42c15375d54269f56983b530e2b7ea43150284b8825879cdceca1fe959f1c05b8043bb1c2202b30456c63eac8dbc6ab
@@ -21,7 +21,7 @@ jobs:
21
21
  strategy:
22
22
  matrix:
23
23
  ruby: ['3.2.9', '3.3.10', '3.4.9', '4.0.2', 'head']
24
- duckdb: ['1.4.4', '1.5.0']
24
+ duckdb: ['1.4.4', '1.5.1']
25
25
 
26
26
  steps:
27
27
  - uses: actions/checkout@v4
@@ -35,39 +35,36 @@ jobs:
35
35
  id: duckdb-cache
36
36
  uses: actions/cache@v4
37
37
  with:
38
- path: duckdb-v${{ matrix.duckdb }}
38
+ path: libduckdb-osx-universal
39
39
  key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }}
40
40
 
41
- - name: Build duckdb ${{ matrix.duckdb }}
41
+ - name: Download duckdb ${{ matrix.duckdb }}
42
+ if: steps.duckdb-cache.outputs.cache-hit != 'true'
42
43
  env:
43
44
  DUCKDB_VERSION: ${{ matrix.duckdb }}
44
- if: steps.duckdb-cache.outputs.cache-hit != 'true'
45
45
  run: |
46
- git clone -b v$DUCKDB_VERSION https://github.com/cwida/duckdb.git duckdb-tmp-v$DUCKDB_VERSION
47
- cd duckdb-tmp-v$DUCKDB_VERSION && make && cd ..
48
- rm -rf duckdb-v$DUCKDB_VERSION
49
- mkdir -p duckdb-v$DUCKDB_VERSION/build/release/src duckdb-v$DUCKDB_VERSION/src
50
- cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.dylib duckdb-v$DUCKDB_VERSION/build/release/src
51
- cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/
46
+ curl -OL https://github.com/duckdb/duckdb/releases/download/v${DUCKDB_VERSION}/libduckdb-osx-universal.zip
47
+ case "${DUCKDB_VERSION}" in
48
+ "1.5.1") EXPECTED_SHA256="d9dd723c59f8571202b468f6bf71d4555238544553dd1445e6c9ecb39f54c0f3" ;;
49
+ "1.4.4") EXPECTED_SHA256="5e6d79f5fb86bbd4f24d59cee3bc38f113d1433761df35337e3c01c62eeafe26" ;;
50
+ *) echo "No known SHA256 for DuckDB v${DUCKDB_VERSION}"; exit 1 ;;
51
+ esac
52
+ echo "${EXPECTED_SHA256} libduckdb-osx-universal.zip" | shasum -a 256 -c
53
+ mkdir libduckdb-osx-universal
54
+ unzip libduckdb-osx-universal.zip -d libduckdb-osx-universal
52
55
 
53
56
  - name: bundle install with Ruby ${{ matrix.ruby }}
54
- env:
55
- DUCKDB_VERSION: ${{ matrix.duckdb }}
56
57
  run: |
57
58
  bundle install --jobs 4 --retry 3
58
59
 
59
60
  - name: Build test with DUCKDB_API_NO_DEPRECATED and Ruby ${{ matrix.ruby }}
60
- env:
61
- DUCKDB_VERSION: ${{ matrix.duckdb }}
62
61
  run: |
63
- env DUCKDB_API_NO_DEPRECATED=1 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/
62
+ env DUCKDB_API_NO_DEPRECATED=1 bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/libduckdb-osx-universal --with-duckdb-lib=${GITHUB_WORKSPACE}/libduckdb-osx-universal
64
63
  bundle exec rake clean
65
64
 
66
65
  - name: Build with Ruby ${{ matrix.ruby }}
67
- env:
68
- DUCKDB_VERSION: ${{ matrix.duckdb }}
69
66
  run: |
70
- 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/
67
+ bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/libduckdb-osx-universal --with-duckdb-lib=${GITHUB_WORKSPACE}/libduckdb-osx-universal
71
68
 
72
69
  - name: Setup MySQL
73
70
  run: |
@@ -79,12 +76,23 @@ jobs:
79
76
  mysql -u root -e "GRANT ALL PRIVILEGES ON test_db.* TO 'test_user'@'127.0.0.1';"
80
77
  mysql -u root -e "FLUSH PRIVILEGES;"
81
78
 
79
+ - name: confirm duckdb library version
80
+ env:
81
+ EXPECTED_DUCKDB_VERSION: ${{ matrix.duckdb }}
82
+ DYLD_LIBRARY_PATH: ${{ github.workspace }}/libduckdb-osx-universal
83
+ run: |
84
+ ruby -Ilib -rduckdb -e '
85
+ actual = DuckDB::LIBRARY_VERSION
86
+ expected = ENV.fetch("EXPECTED_DUCKDB_VERSION")
87
+ abort("Expected DuckDB #{expected}, got #{actual}") if actual != expected
88
+ puts "duckdb library #{actual}"
89
+ '
90
+
82
91
  - name: test with Ruby ${{ matrix.ruby }}
83
92
  env:
84
- DUCKDB_VERSION: ${{ matrix.duckdb }}
85
93
  MYSQL_TEST: 1
94
+ DYLD_LIBRARY_PATH: ${{ github.workspace }}/libduckdb-osx-universal
86
95
  run: |
87
- export DYLD_LIBRARY_PATH=${GITHUB_WORKSPACE}/duckdb-v${DUCKDB_VERSION}/build/release/src:${DYLD_LIBRARY_PATH}
88
96
  env RUBYOPT=-W:deprecated rake test
89
97
 
90
98
  post-test:
@@ -21,7 +21,7 @@ jobs:
21
21
  strategy:
22
22
  matrix:
23
23
  ruby: ['3.2.9', '3.3.10', '3.4.9', '4.0.2', 'head']
24
- duckdb: ['1.4.4', '1.5.0']
24
+ duckdb: ['1.4.4', '1.5.1']
25
25
 
26
26
  services:
27
27
  mysql:
@@ -47,43 +47,55 @@ jobs:
47
47
  id: duckdb-cache
48
48
  uses: actions/cache@v4
49
49
  with:
50
- path: duckdb-v${{ matrix.duckdb }}
50
+ path: libduckdb-linux-amd64
51
51
  key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }}
52
52
 
53
- - name: Build duckdb ${{ matrix.duckdb }}
53
+ - name: Download duckdb ${{ matrix.duckdb }}
54
+ if: steps.duckdb-cache.outputs.cache-hit != 'true'
54
55
  env:
55
56
  DUCKDB_VERSION: ${{ matrix.duckdb }}
56
- if: steps.duckdb-cache.outputs.cache-hit != 'true'
57
57
  run: |
58
- git clone -b v$DUCKDB_VERSION https://github.com/cwida/duckdb.git duckdb-tmp-v$DUCKDB_VERSION
59
- cd duckdb-tmp-v$DUCKDB_VERSION && make && cd ..
60
- rm -rf duckdb-v$DUCKDB_VERSION
61
- mkdir -p duckdb-v$DUCKDB_VERSION/build/release/src duckdb-v$DUCKDB_VERSION/src
62
- cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.so duckdb-v$DUCKDB_VERSION/build/release/src
63
- cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/
58
+ curl -OL https://github.com/duckdb/duckdb/releases/download/v${DUCKDB_VERSION}/libduckdb-linux-amd64.zip
59
+ case "${DUCKDB_VERSION}" in
60
+ "1.5.1") EXPECTED_SHA256="21aec66a60eae1696270ba715a481ab066a88d99a62718d0577579ac1a7a4834" ;;
61
+ "1.4.4") EXPECTED_SHA256="09cc288295964d897b47665d1898e16e8ef176cae9ea615797fc136eae15bd5d" ;;
62
+ *) echo "No known SHA256 for DuckDB v${DUCKDB_VERSION}"; exit 1 ;;
63
+ esac
64
+ echo "${EXPECTED_SHA256} libduckdb-linux-amd64.zip" | sha256sum -c
65
+ mkdir libduckdb-linux-amd64
66
+ unzip libduckdb-linux-amd64.zip -d libduckdb-linux-amd64
67
+
68
+ - name: setup libduckdb.so
69
+ run: |
70
+ sudo cp libduckdb-linux-amd64/libduckdb.so /usr/local/lib/
71
+ sudo ldconfig
64
72
 
65
73
  - name: bundle install with Ruby ${{ matrix.ruby }}
66
- env:
67
- DUCKDB_VERSION: ${{ matrix.duckdb }}
68
74
  run: |
69
75
  bundle install --jobs 4 --retry 3
70
76
 
71
77
  - name: Build test with DUCKDB_API_NO_DEPRECATED and Ruby ${{ matrix.ruby }}
72
- env:
73
- DUCKDB_VERSION: ${{ matrix.duckdb }}
74
78
  run: |
75
- env DUCKDB_API_NO_DEPRECATED=1 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/
79
+ env DUCKDB_API_NO_DEPRECATED=1 bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/libduckdb-linux-amd64 --with-duckdb-lib=${GITHUB_WORKSPACE}/libduckdb-linux-amd64
76
80
  bundle exec rake clean
77
81
 
78
82
  - name: Build with Ruby ${{ matrix.ruby }}
83
+ run: |
84
+ bundle exec rake build -- --with-duckdb-include=${GITHUB_WORKSPACE}/libduckdb-linux-amd64 --with-duckdb-lib=${GITHUB_WORKSPACE}/libduckdb-linux-amd64
85
+
86
+ - name: confirm duckdb library version
79
87
  env:
80
- DUCKDB_VERSION: ${{ matrix.duckdb }}
88
+ EXPECTED_DUCKDB_VERSION: ${{ matrix.duckdb }}
81
89
  run: |
82
- 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/
90
+ ruby -Ilib -rduckdb -e '
91
+ actual = DuckDB::LIBRARY_VERSION
92
+ expected = ENV.fetch("EXPECTED_DUCKDB_VERSION")
93
+ abort("Expected DuckDB #{expected}, got #{actual}") if actual != expected
94
+ puts "duckdb library #{actual}"
95
+ '
83
96
 
84
97
  - name: test with Ruby ${{ matrix.ruby }}
85
98
  env:
86
- DUCKDB_VERSION: ${{ matrix.duckdb }}
87
99
  MYSQL_TEST: 1
88
100
  run: |
89
101
  env RUBYOPT=-W:deprecated rake test
@@ -17,11 +17,11 @@ concurrency:
17
17
  jobs:
18
18
  test:
19
19
  runs-on: windows-latest
20
- timeout-minutes: 15
20
+ timeout-minutes: 8
21
21
  strategy:
22
22
  matrix:
23
23
  ruby: ['3.2.9', '3.3.10', '3.4.8', '4.0.1', 'ucrt', 'mingw', 'mswin', 'head']
24
- duckdb: ['1.4.4', '1.5.0']
24
+ duckdb: ['1.4.4', '1.5.1']
25
25
 
26
26
  steps:
27
27
  - uses: actions/checkout@v4
@@ -31,29 +31,35 @@ jobs:
31
31
  with:
32
32
  ruby-version: ${{ matrix.ruby }}
33
33
 
34
+ - name: duckdb cache
35
+ id: duckdb-cache
36
+ uses: actions/cache@v4
37
+ with:
38
+ path: libduckdb-windows-amd64
39
+ key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }}
40
+
34
41
  - name: download duckdb binary for windows 64bit
42
+ if: steps.duckdb-cache.outputs.cache-hit != 'true'
35
43
  env:
36
44
  DUCKDB_VERSION: ${{ matrix.duckdb }}
37
45
  run: |
38
46
  curl -OL https://github.com/duckdb/duckdb/releases/download/v${env:DUCKDB_VERSION}/libduckdb-windows-amd64.zip
39
-
40
- - name: extract zip file
41
- run: |
42
- unzip libduckdb-windows-amd64.zip
47
+ mkdir libduckdb-windows-amd64
48
+ unzip libduckdb-windows-amd64.zip -d libduckdb-windows-amd64
43
49
 
44
50
  - name: setup duckdb.dll
45
51
  run: |
46
- cp duckdb.dll C:/Windows/System32/
52
+ cp libduckdb-windows-amd64/duckdb.dll C:/Windows/System32/
47
53
 
48
54
  - name: Build with Rake with Ruby ${{ matrix.ruby }}
49
55
  run: |
50
56
  bundle install
51
- bundle exec rake build -- --with-duckdb-include=../../../.. --with-duckdb-lib=../../../..
57
+ bundle exec rake build -- --with-duckdb-include=../../../../libduckdb-windows-amd64 --with-duckdb-lib=../../../../libduckdb-windows-amd64
52
58
 
53
59
  - name: rake test
54
60
  uses: nick-fields/retry@v3
55
61
  with:
56
- timeout_minutes: 3
62
+ timeout_minutes: 1
57
63
  max_attempts: 3
58
64
  command: bundle exec rake test TESTOPTS="--verbose"
59
65
 
data/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  # Unreleased
6
6
 
7
+ # 1.5.1.0 - 2026-03-29
8
+
9
+ - add `DuckDB::ScalarFunction#varargs_type=` to register a scalar function that accepts a variable number of arguments of a given type (wraps `duckdb_scalar_function_set_varargs`).
10
+ - `DuckDB::ScalarFunction.create` accepts `varargs_type:` keyword argument (mutually exclusive with `parameter_type:`/`parameter_types:`).
11
+ - add `DuckDB::ScalarFunction#set_special_handling` to make the block receive `nil` for NULL inputs instead of DuckDB short-circuiting (wraps `duckdb_scalar_function_set_special_handling`).
12
+ - `DuckDB::ScalarFunction.create` accepts `null_handling: true` keyword to enable special NULL handling.
13
+ - add `34 => :any` to `Converter::IntToSym::HASH_TYPES` and `:any` to `ScalarFunction::SUPPORTED_TYPES` so `DuckDB::LogicalType::ANY` can be used with `varargs_type=`.
14
+ - add `DuckDB::ScalarFunction#set_bind` to register a bind callback (wraps `duckdb_scalar_function_set_bind`). The block receives a `DuckDB::ScalarFunction::BindInfo` object at query planning time (once, before per-row execution).
15
+ - add `DuckDB::ScalarFunction::BindInfo#argument_count` to return the number of arguments passed to the scalar function (wraps `duckdb_scalar_function_bind_get_argument_count`).
16
+ - add `DuckDB::ScalarFunction::BindInfo#set_error(message)` to report an error early at planning time (wraps `duckdb_scalar_function_bind_set_error`).
17
+ - add `DuckDB::ScalarFunction::BindInfo#get_argument(index)` to return the expression at the given argument index as a `DuckDB::Expression` object (wraps `duckdb_scalar_function_bind_get_argument`). Raises `ArgumentError` for out-of-range index.
18
+ - add `DuckDB::Expression#foldable?` to check whether an expression can be folded to a constant at query planning time (wraps `duckdb_expression_is_foldable`). Returns `true` for literals and constant arithmetic, `false` for column references and non-deterministic functions.
19
+ - add `DuckDB::LogicalType.create_map` to create a map logical type.
20
+ - bump duckdb to 1.5.1 on CI
21
+ - add `DuckDB::ScalarFunction::BindInfo#client_context` to return the client context of the bind phase as a `DuckDB::ClientContext` object (wraps `duckdb_scalar_function_get_client_context`).
22
+ - add `DuckDB::ClientContext#connection_id` to return the connection id of the client context (wraps `duckdb_client_context_get_connection_id`).
23
+ - add `DuckDB::Expression#fold(client_context)` to fold a constant expression to a native Ruby value at query planning time (wraps `duckdb_expression_fold`). Returns Integer, Float, String, true/false, or nil. Raises `DuckDB::Error` if the expression is not foldable.
24
+
25
+ ## Breaking changes
26
+ - rename `DuckDB::BindInfo` to `DuckDB::TableFunction::BindInfo`. `DuckDB::BindInfo` still works but emits a deprecation warning.
27
+ - rename `DuckDB::InitInfo` to `DuckDB::TableFunction::InitInfo`. `DuckDB::InitInfo` still works but emits a deprecation warning.
28
+ - rename `DuckDB::FunctionInfo` to `DuckDB::TableFunction::FunctionInfo`. `DuckDB::FunctionInfo` still works but emits a deprecation warning.
29
+
7
30
  # 1.5.0.2 - 2026-03-22
8
31
 
9
32
  - add `DuckDB.vector_size` to return the DuckDB vector size (number of rows processed per vectorized operation).
data/Dockerfile CHANGED
@@ -1,7 +1,7 @@
1
1
  ARG RUBY_VERSION=4.0.1
2
2
  FROM ruby:${RUBY_VERSION}
3
3
 
4
- ARG DUCKDB_VERSION=1.5.0
4
+ ARG DUCKDB_VERSION=1.5.1
5
5
  ARG VALGRIND_VERSION=3.21.0
6
6
 
7
7
  RUN apt-get update -qq && \
data/Gemfile.lock CHANGED
@@ -1,46 +1,37 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckdb (1.5.0.2)
4
+ duckdb (1.5.1.0)
5
5
  bigdecimal (>= 3.1.4)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- addressable (2.8.9)
11
- public_suffix (>= 2.0.2, < 8.0)
12
10
  ast (2.4.3)
13
- bigdecimal (4.0.1)
11
+ bigdecimal (4.1.0)
14
12
  csv (3.3.5)
15
13
  drb (2.2.3)
16
- json (2.19.2)
17
- json-schema (6.2.0)
18
- addressable (~> 2.8)
19
- bigdecimal (>= 3.1, < 5)
14
+ json (2.19.3)
20
15
  language_server-protocol (3.17.0.5)
21
16
  lint_roller (1.1.0)
22
- mcp (0.9.0)
23
- json-schema (>= 4.1)
24
17
  minitest (6.0.2)
25
18
  drb (~> 2.0)
26
19
  prism (~> 1.5)
27
20
  parallel (1.27.0)
28
- parser (3.3.10.2)
21
+ parser (3.3.11.1)
29
22
  ast (~> 2.4.1)
30
23
  racc
31
24
  prism (1.9.0)
32
- public_suffix (7.0.5)
33
25
  racc (1.8.1)
34
26
  rainbow (3.1.1)
35
27
  rake (13.3.1)
36
28
  rake-compiler (1.3.1)
37
29
  rake
38
30
  regexp_parser (2.11.3)
39
- rubocop (1.85.1)
31
+ rubocop (1.86.0)
40
32
  json (~> 2.3)
41
33
  language_server-protocol (~> 3.17.0.2)
42
34
  lint_roller (~> 1.1.0)
43
- mcp (~> 0.6)
44
35
  parallel (~> 1.10)
45
36
  parser (>= 3.3.0.2)
46
37
  rainbow (>= 2.2.2, < 4.0)
data/README.md CHANGED
@@ -14,11 +14,9 @@ This gem `duckdb` is Ruby client for the [DuckDB](https://www.duckdb.org) databa
14
14
  You must have [DuckDB](https://www.duckdb.org) engine installed in order to use this gem.
15
15
 
16
16
  ## Pre-requisite setup (Linux):
17
- 1. Head over to the [DuckDB](https://duckdb.org/) webpage.
17
+ 1. Download the latest [C++ package release for DuckDB](https://duckdb.org/install/?platform=linux&environment=c).
18
18
 
19
- 2. Download the latest C++ package release for DuckDB.
20
-
21
- 3. Move the files to their respective location:
19
+ 2. Move the files to their respective location:
22
20
  - Extract the `duckdb.h` and `duckdb.hpp` file to `/usr/local/include`.
23
21
  - Extract the `libduckdb.so` file to `/usr/local/lib`.
24
22
 
@@ -28,7 +26,7 @@ You must have [DuckDB](https://www.duckdb.org) engine installed in order to use
28
26
  sudo mv libduckdb/libduckdb.so /usr/local/lib
29
27
  ```
30
28
 
31
- 4. To create the necessary link, run `ldconfig` as root:
29
+ 3. To create the necessary link, run `ldconfig` as root:
32
30
 
33
31
  ```sh
34
32
  sudo ldconfig /usr/local/lib # adding a --verbose flag is optional - but this will let you know if the libduckdb.so library has been linked
@@ -0,0 +1,70 @@
1
+ #include "ruby-duckdb.h"
2
+
3
+ VALUE cDuckDBClientContext;
4
+
5
+ static void deallocate(void *ctx);
6
+ static VALUE allocate(VALUE klass);
7
+ static size_t memsize(const void *p);
8
+ static VALUE rbduckdb_client_context_connection_id(VALUE self);
9
+
10
+ static const rb_data_type_t client_context_data_type = {
11
+ "DuckDB/ClientContext",
12
+ {NULL, deallocate, memsize,},
13
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
14
+ };
15
+
16
+ static void deallocate(void *ctx) {
17
+ rubyDuckDBClientContext *p = (rubyDuckDBClientContext *)ctx;
18
+
19
+ if (p->client_context) {
20
+ duckdb_destroy_client_context(&(p->client_context));
21
+ }
22
+
23
+ xfree(p);
24
+ }
25
+
26
+ static VALUE allocate(VALUE klass) {
27
+ rubyDuckDBClientContext *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBClientContext));
28
+ return TypedData_Wrap_Struct(klass, &client_context_data_type, ctx);
29
+ }
30
+
31
+ static size_t memsize(const void *p) {
32
+ return sizeof(rubyDuckDBClientContext);
33
+ }
34
+
35
+ VALUE rbduckdb_client_context_new(duckdb_client_context client_context) {
36
+ rubyDuckDBClientContext *ctx;
37
+ VALUE obj = allocate(cDuckDBClientContext);
38
+
39
+ TypedData_Get_Struct(obj, rubyDuckDBClientContext, &client_context_data_type, ctx);
40
+ ctx->client_context = client_context;
41
+
42
+ return obj;
43
+ }
44
+
45
+ rubyDuckDBClientContext *get_struct_client_context(VALUE obj) {
46
+ rubyDuckDBClientContext *ctx;
47
+ TypedData_Get_Struct(obj, rubyDuckDBClientContext, &client_context_data_type, ctx);
48
+ return ctx;
49
+ }
50
+
51
+ /*
52
+ * call-seq:
53
+ * client_context.connection_id -> Integer
54
+ *
55
+ * Returns the connection id of the client context.
56
+ */
57
+ static VALUE rbduckdb_client_context_connection_id(VALUE self) {
58
+ rubyDuckDBClientContext *ctx;
59
+ TypedData_Get_Struct(self, rubyDuckDBClientContext, &client_context_data_type, ctx);
60
+ return ULL2NUM(duckdb_client_context_get_connection_id(ctx->client_context));
61
+ }
62
+
63
+ void rbduckdb_init_duckdb_client_context(void) {
64
+ #if 0
65
+ VALUE mDuckDB = rb_define_module("DuckDB");
66
+ #endif
67
+ cDuckDBClientContext = rb_define_class_under(mDuckDB, "ClientContext", rb_cObject);
68
+ rb_define_alloc_func(cDuckDBClientContext, allocate);
69
+ rb_define_method(cDuckDBClientContext, "connection_id", rbduckdb_client_context_connection_id, 0);
70
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef RUBY_DUCKDB_CLIENT_CONTEXT_H
2
+ #define RUBY_DUCKDB_CLIENT_CONTEXT_H
3
+
4
+ struct _rubyDuckDBClientContext {
5
+ duckdb_client_context client_context;
6
+ };
7
+
8
+ typedef struct _rubyDuckDBClientContext rubyDuckDBClientContext;
9
+
10
+ void rbduckdb_init_duckdb_client_context(void);
11
+ VALUE rbduckdb_client_context_new(duckdb_client_context client_context);
12
+ rubyDuckDBClientContext *get_struct_client_context(VALUE obj);
13
+
14
+ #endif
@@ -1,6 +1,35 @@
1
1
  #ifndef RUBY_DUCKDB_CONVERTER_H
2
2
  #define RUBY_DUCKDB_CONVERTER_H
3
3
 
4
+ extern ID id__to_date;
5
+ extern ID id__to_time;
6
+ extern ID id__to_time_from_duckdb_time;
7
+ extern ID id__to_interval_from_vector;
8
+ extern ID id__to_hugeint_from_vector;
9
+ extern ID id__to_decimal_from_hugeint;
10
+ extern ID id__to_uuid_from_vector;
11
+ extern ID id__to_time_from_duckdb_timestamp_s;
12
+ extern ID id__to_time_from_duckdb_timestamp_ms;
13
+ extern ID id__to_time_from_duckdb_timestamp_ns;
14
+ extern ID id__to_time_from_duckdb_time_tz;
15
+ extern ID id__to_time_from_duckdb_timestamp_tz;
16
+ extern ID id__to_infinity;
17
+
18
+ VALUE rbduckdb_timestamp_s_to_ruby(duckdb_timestamp_s ts);
19
+ VALUE rbduckdb_timestamp_ms_to_ruby(duckdb_timestamp_ms ts);
20
+ VALUE rbduckdb_timestamp_ns_to_ruby(duckdb_timestamp_ns ts);
21
+ VALUE rbduckdb_time_tz_to_ruby(duckdb_time_tz tz);
22
+ VALUE rbduckdb_timestamp_tz_to_ruby(duckdb_timestamp ts);
23
+ VALUE rbduckdb_time_to_ruby(duckdb_time t);
24
+ VALUE rbduckdb_date_to_ruby(duckdb_date date);
25
+ VALUE rbduckdb_timestamp_to_ruby(duckdb_timestamp ts);
26
+
27
+ VALUE infinite_date_value(duckdb_date date);
28
+ VALUE infinite_timestamp_value(duckdb_timestamp timestamp);
29
+ VALUE infinite_timestamp_s_value(duckdb_timestamp_s timestamp_s);
30
+ VALUE infinite_timestamp_ms_value(duckdb_timestamp_ms timestamp_ms);
31
+ VALUE infinite_timestamp_ns_value(duckdb_timestamp_ns timestamp_ns);
32
+
4
33
  void rbduckdb_init_duckdb_converter(void);
5
34
 
6
35
  #endif
@@ -2,6 +2,168 @@
2
2
 
3
3
  VALUE mDuckDBConverter;
4
4
 
5
+ ID id__to_date;
6
+ ID id__to_time;
7
+ ID id__to_time_from_duckdb_time;
8
+ ID id__to_interval_from_vector;
9
+ ID id__to_hugeint_from_vector;
10
+ ID id__to_decimal_from_hugeint;
11
+ ID id__to_uuid_from_vector;
12
+ ID id__to_time_from_duckdb_timestamp_s;
13
+ ID id__to_time_from_duckdb_timestamp_ms;
14
+ ID id__to_time_from_duckdb_timestamp_ns;
15
+ ID id__to_time_from_duckdb_time_tz;
16
+ ID id__to_time_from_duckdb_timestamp_tz;
17
+ ID id__to_infinity;
18
+
19
+ VALUE infinite_date_value(duckdb_date date) {
20
+ if (duckdb_is_finite_date(date) == false) {
21
+ return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
22
+ INT2NUM(date.days)
23
+ );
24
+ }
25
+ return Qnil;
26
+ }
27
+
28
+ VALUE infinite_timestamp_value(duckdb_timestamp timestamp) {
29
+ if (duckdb_is_finite_timestamp(timestamp) == false) {
30
+ return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
31
+ LL2NUM(timestamp.micros)
32
+ );
33
+ }
34
+ return Qnil;
35
+ }
36
+
37
+ VALUE infinite_timestamp_s_value(duckdb_timestamp_s timestamp_s) {
38
+ if (duckdb_is_finite_timestamp_s(timestamp_s) == false) {
39
+ return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
40
+ LL2NUM(timestamp_s.seconds)
41
+ );
42
+ }
43
+ return Qnil;
44
+ }
45
+
46
+ VALUE infinite_timestamp_ms_value(duckdb_timestamp_ms timestamp_ms) {
47
+ if (duckdb_is_finite_timestamp_ms(timestamp_ms) == false) {
48
+ return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
49
+ LL2NUM(timestamp_ms.millis)
50
+ );
51
+ }
52
+ return Qnil;
53
+ }
54
+
55
+ VALUE infinite_timestamp_ns_value(duckdb_timestamp_ns timestamp_ns) {
56
+ if (duckdb_is_finite_timestamp_ns(timestamp_ns) == false) {
57
+ return rb_funcall(mDuckDBConverter, id__to_infinity, 1,
58
+ LL2NUM(timestamp_ns.nanos)
59
+ );
60
+ }
61
+ return Qnil;
62
+ }
63
+
64
+ VALUE rbduckdb_timestamp_s_to_ruby(duckdb_timestamp_s ts) {
65
+ VALUE obj = infinite_timestamp_s_value(ts);
66
+ if (obj != Qnil) {
67
+ return obj;
68
+ }
69
+ return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_timestamp_s, 1,
70
+ LL2NUM(ts.seconds)
71
+ );
72
+ }
73
+
74
+ VALUE rbduckdb_timestamp_ms_to_ruby(duckdb_timestamp_ms ts) {
75
+ VALUE obj = infinite_timestamp_ms_value(ts);
76
+ if (obj != Qnil) {
77
+ return obj;
78
+ }
79
+ return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_timestamp_ms, 1,
80
+ LL2NUM(ts.millis)
81
+ );
82
+ }
83
+
84
+ VALUE rbduckdb_timestamp_ns_to_ruby(duckdb_timestamp_ns ts) {
85
+ VALUE obj = infinite_timestamp_ns_value(ts);
86
+ if (obj != Qnil) {
87
+ return obj;
88
+ }
89
+ return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_timestamp_ns, 1,
90
+ LL2NUM(ts.nanos)
91
+ );
92
+ }
93
+
94
+ VALUE rbduckdb_time_tz_to_ruby(duckdb_time_tz tz) {
95
+ duckdb_time_tz_struct data = duckdb_from_time_tz(tz);
96
+ return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_time_tz, 5,
97
+ INT2FIX(data.time.hour),
98
+ INT2FIX(data.time.min),
99
+ INT2FIX(data.time.sec),
100
+ INT2NUM(data.time.micros),
101
+ INT2NUM(data.offset)
102
+ );
103
+ }
104
+
105
+ VALUE rbduckdb_timestamp_tz_to_ruby(duckdb_timestamp ts) {
106
+ return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_timestamp_tz, 1,
107
+ LL2NUM(ts.micros)
108
+ );
109
+ }
110
+
111
+ VALUE rbduckdb_time_to_ruby(duckdb_time t) {
112
+ duckdb_time_struct data = duckdb_from_time(t);
113
+ return rb_funcall(mDuckDBConverter, id__to_time_from_duckdb_time, 4,
114
+ INT2FIX(data.hour),
115
+ INT2FIX(data.min),
116
+ INT2FIX(data.sec),
117
+ INT2NUM(data.micros)
118
+ );
119
+ }
120
+
121
+ VALUE rbduckdb_date_to_ruby(duckdb_date date) {
122
+ VALUE obj = infinite_date_value(date);
123
+
124
+ if (obj == Qnil) {
125
+ duckdb_date_struct date_st = duckdb_from_date(date);
126
+ obj = rb_funcall(mDuckDBConverter, id__to_date, 3,
127
+ INT2FIX(date_st.year),
128
+ INT2FIX(date_st.month),
129
+ INT2FIX(date_st.day)
130
+ );
131
+ }
132
+ return obj;
133
+ }
134
+
135
+ VALUE rbduckdb_timestamp_to_ruby(duckdb_timestamp ts) {
136
+ VALUE obj = infinite_timestamp_value(ts);
137
+
138
+ if (obj == Qnil) {
139
+ duckdb_timestamp_struct data_st = duckdb_from_timestamp(ts);
140
+ obj = rb_funcall(mDuckDBConverter, id__to_time, 7,
141
+ INT2FIX(data_st.date.year),
142
+ INT2FIX(data_st.date.month),
143
+ INT2FIX(data_st.date.day),
144
+ INT2FIX(data_st.time.hour),
145
+ INT2FIX(data_st.time.min),
146
+ INT2FIX(data_st.time.sec),
147
+ INT2NUM(data_st.time.micros)
148
+ );
149
+ }
150
+ return obj;
151
+ }
152
+
5
153
  void rbduckdb_init_duckdb_converter(void) {
6
154
  mDuckDBConverter = rb_define_module_under(mDuckDB, "Converter");
155
+
156
+ id__to_date = rb_intern("_to_date");
157
+ id__to_time = rb_intern("_to_time");
158
+ id__to_time_from_duckdb_time = rb_intern("_to_time_from_duckdb_time");
159
+ id__to_interval_from_vector = rb_intern("_to_interval_from_vector");
160
+ id__to_hugeint_from_vector = rb_intern("_to_hugeint_from_vector");
161
+ id__to_decimal_from_hugeint = rb_intern("_to_decimal_from_hugeint");
162
+ id__to_uuid_from_vector = rb_intern("_to_uuid_from_vector");
163
+ id__to_time_from_duckdb_timestamp_s = rb_intern("_to_time_from_duckdb_timestamp_s");
164
+ id__to_time_from_duckdb_timestamp_ms = rb_intern("_to_time_from_duckdb_timestamp_ms");
165
+ id__to_time_from_duckdb_timestamp_ns = rb_intern("_to_time_from_duckdb_timestamp_ns");
166
+ id__to_time_from_duckdb_time_tz = rb_intern("_to_time_from_duckdb_time_tz");
167
+ id__to_time_from_duckdb_timestamp_tz = rb_intern("_to_time_from_duckdb_timestamp_tz");
168
+ id__to_infinity = rb_intern("_to_infinity");
7
169
  }
data/ext/duckdb/duckdb.c CHANGED
@@ -57,11 +57,14 @@ Init_duckdb_native(void) {
57
57
  rbduckdb_init_duckdb_instance_cache();
58
58
  rbduckdb_init_duckdb_value_impl();
59
59
  rbduckdb_init_duckdb_scalar_function();
60
- rbduckdb_init_duckdb_bind_info();
61
- rbduckdb_init_duckdb_init_info();
62
- rbduckdb_init_duckdb_function_info();
60
+ rbduckdb_init_duckdb_expression();
61
+ rbduckdb_init_duckdb_client_context();
62
+ rbduckdb_init_duckdb_scalar_function_bind_info();
63
63
  rbduckdb_init_duckdb_vector();
64
64
  rbduckdb_init_duckdb_data_chunk();
65
65
  rbduckdb_init_memory_helper();
66
66
  rbduckdb_init_duckdb_table_function();
67
+ rbduckdb_init_duckdb_table_function_bind_info();
68
+ rbduckdb_init_duckdb_table_function_init_info();
69
+ rbduckdb_init_duckdb_table_function_function_info();
67
70
  }