From 57dc5ec0cc052a06a5e402ddb5cf881143c6ca2a Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 18 Jan 2025 07:29:32 +0900 Subject: [PATCH 01/36] get error from duckdb when Appender#append_int32 failed. --- CHANGELOG.md | 3 ++- ext/duckdb/appender.c | 28 +++++----------------------- lib/duckdb/appender.rb | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 311f7fa7..2df0519e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ All notable changes to this project will be documented in this file. # Unreleased - add `DuckDB::Appender#error_message`. - fix error message when `DuckDB::Appender#flush`, `DuckDB::Appender#close`, `DuckDB::Appender#end_row`, - `DuckDB::Appender#append_bool`, `DuckDB::Appender#append_int8`, `DuckDB::Appender#append_int16` failed. + `DuckDB::Appender#append_bool`, `DuckDB::Appender#append_int8`, `DuckDB::Appender#append_int16`, + `DuckDB::Appender#append_int32` failed. - `DuckDB::Appender#begin_row` does nothing. Only returns self. `DuckDB::Appender#end_row` is only required. # 1.1.3.1 - 2024-11-27 diff --git a/ext/duckdb/appender.c b/ext/duckdb/appender.c index 1bbcc8bf..f5207806 100644 --- a/ext/duckdb/appender.c +++ b/ext/duckdb/appender.c @@ -10,7 +10,7 @@ static VALUE appender_error_message(VALUE self); static VALUE appender__append_bool(VALUE self, VALUE val); static VALUE appender__append_int8(VALUE self, VALUE val); static VALUE appender__apend_int16(VALUE self, VALUE val); -static VALUE appender_append_int32(VALUE self, VALUE val); +static VALUE appender__append_int32(VALUE self, VALUE val); static VALUE appender_append_int64(VALUE self, VALUE val); static VALUE appender_append_uint8(VALUE self, VALUE val); static VALUE appender_append_uint16(VALUE self, VALUE val); @@ -147,32 +147,14 @@ static VALUE appender__apend_int16(VALUE self, VALUE val) { return duckdb_state_to_bool_value(duckdb_append_int16(ctx->appender, i16val)); } -/* call-seq: - * appender.append_int32(val) -> self - * - * Appends an int32(INTEGER) value to the current row in the appender. - * - * require 'duckdb' - * db = DuckDB::Database.open - * con = db.connect - * con.query('CREATE TABLE users (id INTEGER, age INTEGER)') - * appender = con.appender('users') - * appender - * .append_int32(1) - * .append_int32(20) - * .end_row - * .flush - */ -static VALUE appender_append_int32(VALUE self, VALUE val) { +/* :nodoc: */ +static VALUE appender__append_int32(VALUE self, VALUE val) { rubyDuckDBAppender *ctx; int32_t i32val = (int32_t)NUM2INT(val); TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx); - if (duckdb_append_int32(ctx->appender, i32val) == DuckDBError) { - rb_raise(eDuckDBError, "failed to append int32"); - } - return self; + return duckdb_state_to_bool_value(duckdb_append_int32(ctx->appender, i32val)); } /* call-seq: @@ -458,7 +440,6 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_alloc_func(cDuckDBAppender, allocate); rb_define_method(cDuckDBAppender, "initialize", appender_initialize, 3); rb_define_method(cDuckDBAppender, "error_message", appender_error_message, 0); - rb_define_method(cDuckDBAppender, "append_int32", appender_append_int32, 1); rb_define_method(cDuckDBAppender, "append_int64", appender_append_int64, 1); rb_define_method(cDuckDBAppender, "append_uint8", appender_append_uint8, 1); rb_define_method(cDuckDBAppender, "append_uint16", appender_append_uint16, 1); @@ -481,6 +462,7 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_private_method(cDuckDBAppender, "_append_bool", appender__append_bool, 1); rb_define_private_method(cDuckDBAppender, "_append_int8", appender__append_int8, 1); rb_define_private_method(cDuckDBAppender, "_append_int16", appender__apend_int16, 1); + rb_define_private_method(cDuckDBAppender, "_append_int32", appender__append_int32, 1); rb_define_private_method(cDuckDBAppender, "_append_date", appender__append_date, 3); rb_define_private_method(cDuckDBAppender, "_append_interval", appender__append_interval, 3); rb_define_private_method(cDuckDBAppender, "_append_time", appender__append_time, 4); diff --git a/lib/duckdb/appender.rb b/lib/duckdb/appender.rb index acd02005..31f806f2 100644 --- a/lib/duckdb/appender.rb +++ b/lib/duckdb/appender.rb @@ -160,6 +160,27 @@ def append_int16(value) raise_appender_error('failed to append_int16') end + # call-seq: + # appender.append_int32(val) -> self + # + # Appends an int32(INTEGER) value to the current row in the appender. + # + # require 'duckdb' + # db = DuckDB::Database.open + # con = db.connect + # con.query('CREATE TABLE users (id INTEGER, age INTEGER)') + # appender = con.appender('users') + # appender + # .append_int32(1) + # .append_int32(20) + # .end_row + # .flush + def append_int32(value) + return self if _append_int32(value) + + raise_appender_error('failed to append_int32') + end + # appends huge int value. # # require 'duckdb' From ec96ef5bc14b220cf77ac5076d2d6b0b1e97916e Mon Sep 17 00:00:00 2001 From: otegami Date: Sun, 12 Jan 2025 08:45:22 +0800 Subject: [PATCH 02/36] add DuckDB::LogicalType#type refs: GH-690 In this PR, we add DuckDB::LogicalType#type, which returns logical type's type. - [duckdb_type duckdb_get_type_id(duckdb_logical_type type);](https://duckdb.org/docs/api/c/api.html#duckdb_get_type_id) This is one of the steps for supporting duckdb_logical_column_type C API. --- ext/duckdb/logical_type.c | 15 +++++ lib/duckdb.rb | 1 + lib/duckdb/logical_type.rb | 22 +++++++ test/duckdb_test/logical_type_test.rb | 90 +++++++++++++++++++++++++-- 4 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 lib/duckdb/logical_type.rb diff --git a/ext/duckdb/logical_type.c b/ext/duckdb/logical_type.c index e2254f32..c6217df5 100644 --- a/ext/duckdb/logical_type.c +++ b/ext/duckdb/logical_type.c @@ -5,6 +5,7 @@ static VALUE cDuckDBLogicalType; static void deallocate(void *ctx); static VALUE allocate(VALUE klass); static size_t memsize(const void *p); +static VALUE duckdb_logical_type__type(VALUE self); static VALUE duckdb_logical_type_width(VALUE self); static VALUE duckdb_logical_type_scale(VALUE self); @@ -33,6 +34,19 @@ static size_t memsize(const void *p) { return sizeof(rubyDuckDBLogicalType); } +/* + * call-seq: + * decimal_col.logical_type.type -> Symbol + * + * Returns the logical type's type symbol. + * + */ +static VALUE duckdb_logical_type__type(VALUE self) { + rubyDuckDBLogicalType *ctx; + TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx); + return INT2FIX(duckdb_get_type_id(ctx->logical_type)); +} + /* * call-seq: * decimal_col.logical_type.width -> Integer @@ -78,6 +92,7 @@ void rbduckdb_init_duckdb_logical_type(void) { cDuckDBLogicalType = rb_define_class_under(mDuckDB, "LogicalType", rb_cObject); rb_define_alloc_func(cDuckDBLogicalType, allocate); + rb_define_private_method(cDuckDBLogicalType, "_type", duckdb_logical_type__type, 0); rb_define_method(cDuckDBLogicalType, "width", duckdb_logical_type_width, 0); rb_define_method(cDuckDBLogicalType, "scale", duckdb_logical_type_scale, 0); } diff --git a/lib/duckdb.rb b/lib/duckdb.rb index 2418f037..839b5995 100644 --- a/lib/duckdb.rb +++ b/lib/duckdb.rb @@ -13,6 +13,7 @@ require 'duckdb/appender' require 'duckdb/config' require 'duckdb/column' +require 'duckdb/logical_type' require 'duckdb/infinity' # DuckDB provides Ruby interface of DuckDB. diff --git a/lib/duckdb/logical_type.rb b/lib/duckdb/logical_type.rb new file mode 100644 index 00000000..fb38b670 --- /dev/null +++ b/lib/duckdb/logical_type.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module DuckDB + class LogicalType + # returns logical type's type symbol + # `:unknown` means that the logical type's type is unknown/unsupported by ruby-duckdb. + # `:invalid` means that the logical type's type is invalid in duckdb. + # + # require 'duckdb' + # db = DuckDB::Database.open + # con = db.connect + # con.query('CREATE TABLE climates (id INTEGER, temperature DECIMAIL)') + # + # users = con.query('SELECT * FROM climates') + # columns = users.columns + # columns.second.logical_type.type #=> :decimal + def type + type_id = _type + DuckDB::Converter::IntToSym.type_to_sym(type_id) + end + end +end diff --git a/test/duckdb_test/logical_type_test.rb b/test/duckdb_test/logical_type_test.rb index 9599d6b9..466b1d89 100644 --- a/test/duckdb_test/logical_type_test.rb +++ b/test/duckdb_test/logical_type_test.rb @@ -4,22 +4,98 @@ module DuckDBTest class LogicalTypeTest < Minitest::Test + CREATE_TYPE_ENUM_SQL = <<~SQL + CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy', 'π˜ΎπΎΦ…Ι­ 😎'); + SQL + CREATE_TABLE_SQL = <<~SQL - CREATE TABLE table1 - ( - decimal_col DECIMAL(9, 6) + CREATE TABLE table1( + boolean_col BOOLEAN, + tinyint_col TINYINT, + smallint_col SMALLINT, + integer_col INTEGER, + bigint_col BIGINT, + utinyint_col UTINYINT, + usmallint_col USMALLINT, + uinteger_col UINTEGER, + ubigint_col UBIGINT, + real_col REAL, + double_col DOUBLE, + date_col DATE, + time_col TIME, + timestamp_col timestamp, + interval_col INTERVAL, + hugeint_col HUGEINT, + varchar_col VARCHAR, + decimal_col DECIMAL(9, 6), + enum_col mood, + int_list_col INT[], + varchar_list_col VARCHAR[], + struct_col STRUCT(word VARCHAR, length INTEGER), + uuid_col UUID, + map_col MAP(INTEGER, VARCHAR) ); SQL INSERT_SQL = <<~SQL INSERT INTO table1 VALUES ( - 123.456789 + true, + 1, + 32767, + 2147483647, + 9223372036854775807, + 1, + 32767, + 2147483647, + 9223372036854775807, + 12345.375, + 123.456789, + '2019-11-03', + '12:34:56', + '2019-11-03 12:34:56', + '1 day', + 170141183460469231731687303715884105727, + 'string', + 123.456789, + 'sad', + [1, 2, 3], + ['a', 'b', 'c'], + ROW('Ruby', 4), + '#{SecureRandom.uuid}', + MAP{1: 'foo'} ) SQL SELECT_SQL = 'SELECT * FROM table1' + EXPECTED_TYPES = %i[ + boolean + tinyint + smallint + integer + bigint + utinyint + usmallint + uinteger + ubigint + float + double + date + time + timestamp + interval + hugeint + varchar + decimal + enum + list + list + struct + uuid + map + ].freeze + def setup @db = DuckDB::Database.open @con = @db.connect @@ -32,6 +108,11 @@ def test_defined_klass assert(DuckDB.const_defined?(:LogicalType)) end + def test_type + logical_types = @columns.map(&:logical_type) + assert_equal(EXPECTED_TYPES, logical_types.map(&:type)) + end + def test_decimal_width decimal_column = @columns.find { |column| column.type == :decimal } assert_equal(9, decimal_column.logical_type.width) @@ -45,6 +126,7 @@ def test_decimal_scale private def create_data(con) + con.query(CREATE_TYPE_ENUM_SQL) con.query(CREATE_TABLE_SQL) con.query(INSERT_SQL) end From 0582631b081d5222cfd7ad21a1cd09edcbfa9776 Mon Sep 17 00:00:00 2001 From: otegami Date: Sun, 12 Jan 2025 08:51:14 +0800 Subject: [PATCH 03/36] Remove an unnecessary test because we explicitly define LogicalType class --- test/duckdb_test/logical_type_test.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/duckdb_test/logical_type_test.rb b/test/duckdb_test/logical_type_test.rb index 466b1d89..0a244831 100644 --- a/test/duckdb_test/logical_type_test.rb +++ b/test/duckdb_test/logical_type_test.rb @@ -104,10 +104,6 @@ def setup @columns = result.columns end - def test_defined_klass - assert(DuckDB.const_defined?(:LogicalType)) - end - def test_type logical_types = @columns.map(&:logical_type) assert_equal(EXPECTED_TYPES, logical_types.map(&:type)) From 4cc26a72b1d3dd608f705b2dfc27a77943b1f562 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 18 Jan 2025 20:12:18 +0900 Subject: [PATCH 04/36] fix appender rdoc. - fix indent - fix call-seq --- lib/duckdb/appender.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/duckdb/appender.rb b/lib/duckdb/appender.rb index 31f806f2..e07ba7b0 100644 --- a/lib/duckdb/appender.rb +++ b/lib/duckdb/appender.rb @@ -51,7 +51,7 @@ def end_row end # :call-seq: - # flush -> self + # appender.flush -> self # # Flushes the appender to the table, forcing the cache of the appender to be cleared. # If flushing the data triggers a constraint violation or any other error, then all @@ -74,7 +74,7 @@ def flush end # :call-seq: - # close -> self + # appender.close -> self # # Closes the appender by flushing all intermediate states and closing it for further appends. # If flushing the data triggers a constraint violation or any other error, then all data is From 82109e7491263880835f17fd04280842b7169040 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 12:42:35 +0900 Subject: [PATCH 05/36] try to make documents --- .github/make_documents | 39 +++++++++++++++++++++++++++++++++++++++ .gitignore | 1 + 2 files changed, 40 insertions(+) create mode 100644 .github/make_documents diff --git a/.github/make_documents b/.github/make_documents new file mode 100644 index 00000000..02572a99 --- /dev/null +++ b/.github/make_documents @@ -0,0 +1,39 @@ +name: Deploy RDoc to GitHub Pages + +on: + push: + branches: + - main + +jobs: + deploy: + name: Build and Deploy RDoc + runs-on: ubuntu-latest + + steps: + # γƒͺγƒγ‚Έγƒˆγƒͺをクローン + - name: Checkout code + uses: actions/checkout@v3 + + # Ruby γ‚’γ‚»γƒƒγƒˆγ‚’γƒƒγƒ— + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.4 + bundler-cache: true + + # 必要γͺδΎε­˜ι–’δΏ‚γ‚’γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ« + - name: Install dependencies + run: bundle install + + # RDoc ドキγƒ₯γƒ‘γƒ³γƒˆγ‚’η”Ÿζˆ + - name: Generate RDoc + run: bundle exec rdoc -o ruby-duckdb-documents + + # GitHub Pages 用にデプロむ + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: ./ruby-duckdb-documents diff --git a/.gitignore b/.gitignore index 6299c232..6736c275 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ *.so Makefile ng_test +/ruby-duckdb-documents/ From 307cd4ea96b6d868d2209b115fa779e14ba6472f Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 12:47:12 +0900 Subject: [PATCH 06/36] fix directory. --- .github/{ => workflows}/make_documents | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/{ => workflows}/make_documents (96%) diff --git a/.github/make_documents b/.github/workflows/make_documents similarity index 96% rename from .github/make_documents rename to .github/workflows/make_documents index 02572a99..8e288d45 100644 --- a/.github/make_documents +++ b/.github/workflows/make_documents @@ -35,5 +35,5 @@ jobs: uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages + publish_branch: main publish_dir: ./ruby-duckdb-documents From 279373b0b723430ae62866b4503d483fbbe5c9d5 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 12:53:34 +0900 Subject: [PATCH 07/36] fix docs directory. --- .github/workflows/make_documents | 4 ++-- .gitignore | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/make_documents b/.github/workflows/make_documents index 8e288d45..6b23c6f3 100644 --- a/.github/workflows/make_documents +++ b/.github/workflows/make_documents @@ -28,7 +28,7 @@ jobs: # RDoc ドキγƒ₯γƒ‘γƒ³γƒˆγ‚’η”Ÿζˆ - name: Generate RDoc - run: bundle exec rdoc -o ruby-duckdb-documents + run: bundle exec rdoc -o docs # GitHub Pages 用にデプロむ - name: Deploy to GitHub Pages @@ -36,4 +36,4 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_branch: main - publish_dir: ./ruby-duckdb-documents + publish_dir: ./docs diff --git a/.gitignore b/.gitignore index 6736c275..704f235a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,4 @@ *.so Makefile ng_test -/ruby-duckdb-documents/ +/docs/ From c7d9572e4c1c2e87c38b39c16f630c1226f1e25e Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 13:08:20 +0900 Subject: [PATCH 08/36] rename filename --- .github/workflows/{make_documents => make_documents.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{make_documents => make_documents.yml} (100%) diff --git a/.github/workflows/make_documents b/.github/workflows/make_documents.yml similarity index 100% rename from .github/workflows/make_documents rename to .github/workflows/make_documents.yml From 5fd216000787824da18edb1e93c2c66352c59742 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 13:14:41 +0900 Subject: [PATCH 09/36] skip bundle install --- .github/workflows/make_documents.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/make_documents.yml b/.github/workflows/make_documents.yml index 6b23c6f3..f81917e3 100644 --- a/.github/workflows/make_documents.yml +++ b/.github/workflows/make_documents.yml @@ -22,13 +22,9 @@ jobs: ruby-version: 3.4 bundler-cache: true - # 必要γͺδΎε­˜ι–’δΏ‚γ‚’γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ« - - name: Install dependencies - run: bundle install - # RDoc ドキγƒ₯γƒ‘γƒ³γƒˆγ‚’η”Ÿζˆ - name: Generate RDoc - run: bundle exec rdoc -o docs + run: rdoc -o docs # GitHub Pages 用にデプロむ - name: Deploy to GitHub Pages From 69dcac91f7f057d381117ce67e2dd7c998fa6e56 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 13:27:40 +0900 Subject: [PATCH 10/36] change create published branch --- .github/workflows/make_documents.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/make_documents.yml b/.github/workflows/make_documents.yml index f81917e3..69a54d5c 100644 --- a/.github/workflows/make_documents.yml +++ b/.github/workflows/make_documents.yml @@ -31,5 +31,5 @@ jobs: uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: main + publish_branch: gh-pages publish_dir: ./docs From 40e62f948d5b2dc8b09a2e4c756aad46d2146aea Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 13:43:55 +0900 Subject: [PATCH 11/36] fix rdoc files --- .github/workflows/make_documents.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/make_documents.yml b/.github/workflows/make_documents.yml index 69a54d5c..65c2954d 100644 --- a/.github/workflows/make_documents.yml +++ b/.github/workflows/make_documents.yml @@ -20,7 +20,6 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: 3.4 - bundler-cache: true # RDoc ドキγƒ₯γƒ‘γƒ³γƒˆγ‚’η”Ÿζˆ - name: Generate RDoc From 90e633d35e524463d87229b86b9d4af1efab3e8e Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 14:06:56 +0900 Subject: [PATCH 12/36] setup rdoc options --- .rdoc_options | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .rdoc_options diff --git a/.rdoc_options b/.rdoc_options new file mode 100644 index 00000000..ccd1f6b1 --- /dev/null +++ b/.rdoc_options @@ -0,0 +1,22 @@ +--- +encoding: UTF-8 +static_path: [] +rdoc_include: [] +charset: UTF-8 +exclude: +- "~\\z" +- "\\.orig\\z" +- "\\.rej\\z" +- "\\.bak\\z" +- "\\.gemspec\\z" +- "ext/duckdb/extconf.rb" +- "Gemfile" +- "Gemfile.lock" +- "Rakefile" +- "getduckdb.sh" +- "rdoc.log" +- "tmp" +- "mkmf.log" +- "Dockerfile" +- "bin" +main_page: "README.md" From 234eaf5247a04b999fb8c682418d9ffa1d8f3a77 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 19 Jan 2025 18:22:38 +0900 Subject: [PATCH 13/36] add documentation url. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 70aa0635..8fa158bc 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,8 @@ gem install duckdb -- --with-duckdb-include=/duckdb_header_directory --with-duck ## Usage +The followings are some examples, for more detailed information, please refer to the [documentation](https://suketa.github.io/ruby-duckdb/index.html). + ```ruby require 'duckdb' From ffd7c276940318457c63b62ee22aee0354df0c81 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 06:20:37 +0900 Subject: [PATCH 14/36] get error message from duckdb when appender_int64 failed. --- CHANGELOG.md | 2 +- ext/duckdb/appender.c | 28 +++++----------------------- lib/duckdb/appender.rb | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2df0519e..fde6119a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. - add `DuckDB::Appender#error_message`. - fix error message when `DuckDB::Appender#flush`, `DuckDB::Appender#close`, `DuckDB::Appender#end_row`, `DuckDB::Appender#append_bool`, `DuckDB::Appender#append_int8`, `DuckDB::Appender#append_int16`, - `DuckDB::Appender#append_int32` failed. + `DuckDB::Appender#append_int32`, `DuckDB::Appender#append_int64` failed. - `DuckDB::Appender#begin_row` does nothing. Only returns self. `DuckDB::Appender#end_row` is only required. # 1.1.3.1 - 2024-11-27 diff --git a/ext/duckdb/appender.c b/ext/duckdb/appender.c index f5207806..c5a3ac87 100644 --- a/ext/duckdb/appender.c +++ b/ext/duckdb/appender.c @@ -11,7 +11,7 @@ static VALUE appender__append_bool(VALUE self, VALUE val); static VALUE appender__append_int8(VALUE self, VALUE val); static VALUE appender__apend_int16(VALUE self, VALUE val); static VALUE appender__append_int32(VALUE self, VALUE val); -static VALUE appender_append_int64(VALUE self, VALUE val); +static VALUE appender__apend_int64(VALUE self, VALUE val); static VALUE appender_append_uint8(VALUE self, VALUE val); static VALUE appender_append_uint16(VALUE self, VALUE val); static VALUE appender_append_uint32(VALUE self, VALUE val); @@ -157,32 +157,14 @@ static VALUE appender__append_int32(VALUE self, VALUE val) { return duckdb_state_to_bool_value(duckdb_append_int32(ctx->appender, i32val)); } -/* call-seq: - * appender.append_int64(val) -> self - * - * Appends an int64(BIGINT) value to the current row in the appender. - * - * require 'duckdb' - * db = DuckDB::Database.open - * con = db.connect - * con.query('CREATE TABLE users (id INTEGER, age BIGINT)') - * appender = con.appender('users') - * appender - * .append_int32(1) - * .append_int64(20) - * .end_row - * .flush - */ -static VALUE appender_append_int64(VALUE self, VALUE val) { +/* :nodoc: */ +static VALUE appender__apend_int64(VALUE self, VALUE val) { rubyDuckDBAppender *ctx; int64_t i64val = (int64_t)NUM2LL(val); TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx); - if (duckdb_append_int64(ctx->appender, i64val) == DuckDBError) { - rb_raise(eDuckDBError, "failed to append int64"); - } - return self; + return duckdb_state_to_bool_value(duckdb_append_int64(ctx->appender, i64val)); } static VALUE appender_append_uint8(VALUE self, VALUE val) { @@ -440,7 +422,6 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_alloc_func(cDuckDBAppender, allocate); rb_define_method(cDuckDBAppender, "initialize", appender_initialize, 3); rb_define_method(cDuckDBAppender, "error_message", appender_error_message, 0); - rb_define_method(cDuckDBAppender, "append_int64", appender_append_int64, 1); rb_define_method(cDuckDBAppender, "append_uint8", appender_append_uint8, 1); rb_define_method(cDuckDBAppender, "append_uint16", appender_append_uint16, 1); rb_define_method(cDuckDBAppender, "append_uint32", appender_append_uint32, 1); @@ -463,6 +444,7 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_private_method(cDuckDBAppender, "_append_int8", appender__append_int8, 1); rb_define_private_method(cDuckDBAppender, "_append_int16", appender__apend_int16, 1); rb_define_private_method(cDuckDBAppender, "_append_int32", appender__append_int32, 1); + rb_define_private_method(cDuckDBAppender, "_append_int64", appender__apend_int64, 1); rb_define_private_method(cDuckDBAppender, "_append_date", appender__append_date, 3); rb_define_private_method(cDuckDBAppender, "_append_interval", appender__append_interval, 3); rb_define_private_method(cDuckDBAppender, "_append_time", appender__append_time, 4); diff --git a/lib/duckdb/appender.rb b/lib/duckdb/appender.rb index e07ba7b0..efc5d256 100644 --- a/lib/duckdb/appender.rb +++ b/lib/duckdb/appender.rb @@ -181,6 +181,27 @@ def append_int32(value) raise_appender_error('failed to append_int32') end + # call-seq: + # appender.append_int64(val) -> self + # + # Appends an int64(BIGINT) value to the current row in the appender. + # + # require 'duckdb' + # db = DuckDB::Database.open + # con = db.connect + # con.query('CREATE TABLE users (id INTEGER, age BIGINT)') + # appender = con.appender('users') + # appender + # .append_int32(1) + # .append_int64(20) + # .end_row + # .flush + def append_int64(value) + return self if _append_int64(value) + + raise_appender_error('failed to append_int64') + end + # appends huge int value. # # require 'duckdb' From 7e7f0bcecfee56e039f1d4713c9e228b990f503f Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 06:28:00 +0900 Subject: [PATCH 15/36] fix typo --- ext/duckdb/appender.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/duckdb/appender.c b/ext/duckdb/appender.c index c5a3ac87..b438dcd9 100644 --- a/ext/duckdb/appender.c +++ b/ext/duckdb/appender.c @@ -11,7 +11,7 @@ static VALUE appender__append_bool(VALUE self, VALUE val); static VALUE appender__append_int8(VALUE self, VALUE val); static VALUE appender__apend_int16(VALUE self, VALUE val); static VALUE appender__append_int32(VALUE self, VALUE val); -static VALUE appender__apend_int64(VALUE self, VALUE val); +static VALUE appender__append_int64(VALUE self, VALUE val); static VALUE appender_append_uint8(VALUE self, VALUE val); static VALUE appender_append_uint16(VALUE self, VALUE val); static VALUE appender_append_uint32(VALUE self, VALUE val); @@ -158,7 +158,7 @@ static VALUE appender__append_int32(VALUE self, VALUE val) { } /* :nodoc: */ -static VALUE appender__apend_int64(VALUE self, VALUE val) { +static VALUE appender__append_int64(VALUE self, VALUE val) { rubyDuckDBAppender *ctx; int64_t i64val = (int64_t)NUM2LL(val); @@ -444,7 +444,7 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_private_method(cDuckDBAppender, "_append_int8", appender__append_int8, 1); rb_define_private_method(cDuckDBAppender, "_append_int16", appender__apend_int16, 1); rb_define_private_method(cDuckDBAppender, "_append_int32", appender__append_int32, 1); - rb_define_private_method(cDuckDBAppender, "_append_int64", appender__apend_int64, 1); + rb_define_private_method(cDuckDBAppender, "_append_int64", appender__append_int64, 1); rb_define_private_method(cDuckDBAppender, "_append_date", appender__append_date, 3); rb_define_private_method(cDuckDBAppender, "_append_interval", appender__append_interval, 3); rb_define_private_method(cDuckDBAppender, "_append_time", appender__append_time, 4); From 3d0e8963384c9221a66f69f168419379f41bdf26 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 06:39:49 +0900 Subject: [PATCH 16/36] fix typo. --- ext/duckdb/appender.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/duckdb/appender.c b/ext/duckdb/appender.c index b438dcd9..b74d8c5f 100644 --- a/ext/duckdb/appender.c +++ b/ext/duckdb/appender.c @@ -9,7 +9,7 @@ static VALUE appender_initialize(VALUE klass, VALUE con, VALUE schema, VALUE tab static VALUE appender_error_message(VALUE self); static VALUE appender__append_bool(VALUE self, VALUE val); static VALUE appender__append_int8(VALUE self, VALUE val); -static VALUE appender__apend_int16(VALUE self, VALUE val); +static VALUE appender__append_int16(VALUE self, VALUE val); static VALUE appender__append_int32(VALUE self, VALUE val); static VALUE appender__append_int64(VALUE self, VALUE val); static VALUE appender_append_uint8(VALUE self, VALUE val); @@ -138,7 +138,7 @@ static VALUE appender__append_int8(VALUE self, VALUE val) { } /* :nodoc: */ -static VALUE appender__apend_int16(VALUE self, VALUE val) { +static VALUE appender__append_int16(VALUE self, VALUE val) { rubyDuckDBAppender *ctx; int16_t i16val = (int16_t)NUM2INT(val); @@ -442,7 +442,7 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_private_method(cDuckDBAppender, "_close", appender__close, 0); rb_define_private_method(cDuckDBAppender, "_append_bool", appender__append_bool, 1); rb_define_private_method(cDuckDBAppender, "_append_int8", appender__append_int8, 1); - rb_define_private_method(cDuckDBAppender, "_append_int16", appender__apend_int16, 1); + rb_define_private_method(cDuckDBAppender, "_append_int16", appender__append_int16, 1); rb_define_private_method(cDuckDBAppender, "_append_int32", appender__append_int32, 1); rb_define_private_method(cDuckDBAppender, "_append_int64", appender__append_int64, 1); rb_define_private_method(cDuckDBAppender, "_append_date", appender__append_date, 3); From a1dc64fcf79a2c12df849a1875d353cd73e333f1 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 26 Jan 2025 09:03:29 +0900 Subject: [PATCH 17/36] change error handling of DuckDB::Appender#append_uint8 get error message from duckdb when DuckDB::Appender#append_uint8 failed. --- CHANGELOG.md | 2 +- ext/duckdb/appender.c | 12 +++++------- lib/duckdb/appender.rb | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fde6119a..0e1e3b48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. - add `DuckDB::Appender#error_message`. - fix error message when `DuckDB::Appender#flush`, `DuckDB::Appender#close`, `DuckDB::Appender#end_row`, `DuckDB::Appender#append_bool`, `DuckDB::Appender#append_int8`, `DuckDB::Appender#append_int16`, - `DuckDB::Appender#append_int32`, `DuckDB::Appender#append_int64` failed. + `DuckDB::Appender#append_int32`, `DuckDB::Appender#append_int64`, `DuckDB::Appender#append_uint8` failed. - `DuckDB::Appender#begin_row` does nothing. Only returns self. `DuckDB::Appender#end_row` is only required. # 1.1.3.1 - 2024-11-27 diff --git a/ext/duckdb/appender.c b/ext/duckdb/appender.c index b74d8c5f..6525b830 100644 --- a/ext/duckdb/appender.c +++ b/ext/duckdb/appender.c @@ -12,7 +12,7 @@ static VALUE appender__append_int8(VALUE self, VALUE val); static VALUE appender__append_int16(VALUE self, VALUE val); static VALUE appender__append_int32(VALUE self, VALUE val); static VALUE appender__append_int64(VALUE self, VALUE val); -static VALUE appender_append_uint8(VALUE self, VALUE val); +static VALUE appender__append_uint8(VALUE self, VALUE val); static VALUE appender_append_uint16(VALUE self, VALUE val); static VALUE appender_append_uint32(VALUE self, VALUE val); static VALUE appender_append_uint64(VALUE self, VALUE val); @@ -167,16 +167,14 @@ static VALUE appender__append_int64(VALUE self, VALUE val) { return duckdb_state_to_bool_value(duckdb_append_int64(ctx->appender, i64val)); } -static VALUE appender_append_uint8(VALUE self, VALUE val) { +/* :nodoc: */ +static VALUE appender__append_uint8(VALUE self, VALUE val) { rubyDuckDBAppender *ctx; int8_t ui8val = (uint8_t)NUM2UINT(val); TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx); - if (duckdb_append_uint8(ctx->appender, ui8val) == DuckDBError) { - rb_raise(eDuckDBError, "failed to append uint8"); - } - return self; + return duckdb_state_to_bool_value(duckdb_append_uint8(ctx->appender, ui8val)); } static VALUE appender_append_uint16(VALUE self, VALUE val) { @@ -422,7 +420,6 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_alloc_func(cDuckDBAppender, allocate); rb_define_method(cDuckDBAppender, "initialize", appender_initialize, 3); rb_define_method(cDuckDBAppender, "error_message", appender_error_message, 0); - rb_define_method(cDuckDBAppender, "append_uint8", appender_append_uint8, 1); rb_define_method(cDuckDBAppender, "append_uint16", appender_append_uint16, 1); rb_define_method(cDuckDBAppender, "append_uint32", appender_append_uint32, 1); rb_define_method(cDuckDBAppender, "append_uint64", appender_append_uint64, 1); @@ -445,6 +442,7 @@ void rbduckdb_init_duckdb_appender(void) { rb_define_private_method(cDuckDBAppender, "_append_int16", appender__append_int16, 1); rb_define_private_method(cDuckDBAppender, "_append_int32", appender__append_int32, 1); rb_define_private_method(cDuckDBAppender, "_append_int64", appender__append_int64, 1); + rb_define_private_method(cDuckDBAppender, "_append_uint8", appender__append_uint8, 1); rb_define_private_method(cDuckDBAppender, "_append_date", appender__append_date, 3); rb_define_private_method(cDuckDBAppender, "_append_interval", appender__append_interval, 3); rb_define_private_method(cDuckDBAppender, "_append_time", appender__append_time, 4); diff --git a/lib/duckdb/appender.rb b/lib/duckdb/appender.rb index efc5d256..3fa2db95 100644 --- a/lib/duckdb/appender.rb +++ b/lib/duckdb/appender.rb @@ -202,6 +202,28 @@ def append_int64(value) raise_appender_error('failed to append_int64') end + # call-seq: + # appender.append_uint8(val) -> self + # + # Appends an uint8 value to the current row in the appender. + # The value must be in the range of 0 to 255. + # + # require 'duckdb' + # db = DuckDB::Database.open + # con = db.connect + # con.query('CREATE TABLE users (id INTEGER, age UTINYINT)') + # appender = con.appender('users') + # appender + # .append_int32(1) + # .append_uint8(20) + # .end_row + # .flush + def append_uint8(value) + return self if _append_uint8(value) + + raise_appender_error('failed to append_uint8') + end + # appends huge int value. # # require 'duckdb' From 54b3caa4dd656cbe20c0c9834536c3312553ccb9 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 26 Jan 2025 09:34:43 +0900 Subject: [PATCH 18/36] fix type casting --- ext/duckdb/appender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/duckdb/appender.c b/ext/duckdb/appender.c index 6525b830..4f7be1d0 100644 --- a/ext/duckdb/appender.c +++ b/ext/duckdb/appender.c @@ -170,7 +170,7 @@ static VALUE appender__append_int64(VALUE self, VALUE val) { /* :nodoc: */ static VALUE appender__append_uint8(VALUE self, VALUE val) { rubyDuckDBAppender *ctx; - int8_t ui8val = (uint8_t)NUM2UINT(val); + uint8_t ui8val = (uint8_t)NUM2UINT(val); TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx); From 026695cb3676b7af15101ccd9cfb1d36e7f8c03d Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 26 Jan 2025 09:40:25 +0900 Subject: [PATCH 19/36] remove comment. --- lib/duckdb/appender.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/duckdb/appender.rb b/lib/duckdb/appender.rb index 3fa2db95..46712578 100644 --- a/lib/duckdb/appender.rb +++ b/lib/duckdb/appender.rb @@ -206,7 +206,6 @@ def append_int64(value) # appender.append_uint8(val) -> self # # Appends an uint8 value to the current row in the appender. - # The value must be in the range of 0 to 255. # # require 'duckdb' # db = DuckDB::Database.open From 73632c3184b0b5ddf7b58a9ce486fdc710fb385b Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 26 Jan 2025 09:20:25 +0900 Subject: [PATCH 20/36] try to fix CI failures. Try to fix CI failures of #845 by close and reopen database each test. --- test/duckdb_test/appender_test.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/test/duckdb_test/appender_test.rb b/test/duckdb_test/appender_test.rb index 681697ac..b1184c44 100644 --- a/test/duckdb_test/appender_test.rb +++ b/test/duckdb_test/appender_test.rb @@ -5,19 +5,24 @@ module DuckDBTest class AppenderTest < Minitest::Test - def self.con - @db ||= DuckDB::Database.open # FIXME + def setup + @db = DuckDB::Database.open # FIXME @db.connect + @con = @db.connect end - def setup - @con = AppenderTest.con + def safe_drop_table + @con.execute("DROP TABLE #{table};") + rescue DuckDB::Error + # ignore DuckDB::Error end def teardown - @con.execute("DROP TABLE #{table};") + safe_drop_table + @con.close + @db.close rescue DuckDB::Error - # ignore + # ignore DuckDB::Error end def table @@ -57,7 +62,7 @@ def sub_test_append_column2(method, type, values:, expected:) r = @con.execute("SELECT col FROM #{table}") assert_equal(expected, r.first.first, "in #{caller[0]}") ensure - teardown + safe_drop_table end def sub_assert_equal(expected, actual) @@ -82,7 +87,7 @@ def assert_duckdb_appender(expected, type, &block) r = @con.execute("SELECT col FROM #{table}") sub_assert_equal(expected, r.first.first) ensure - teardown + safe_drop_table end def test_begin_row From 6ac22ef1c34f1fe111f5a37087339b653725571e Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 26 Jan 2025 09:57:12 +0900 Subject: [PATCH 21/36] remove redundant connect --- test/duckdb_test/appender_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/test/duckdb_test/appender_test.rb b/test/duckdb_test/appender_test.rb index b1184c44..4ab91646 100644 --- a/test/duckdb_test/appender_test.rb +++ b/test/duckdb_test/appender_test.rb @@ -7,7 +7,6 @@ module DuckDBTest class AppenderTest < Minitest::Test def setup @db = DuckDB::Database.open # FIXME - @db.connect @con = @db.connect end From c60b06c49c4d58ea97296242d26d627d608c8310 Mon Sep 17 00:00:00 2001 From: otegami Date: Tue, 4 Feb 2025 18:16:27 +0800 Subject: [PATCH 22/36] logical_type: add DuckDB::LogicalType#child_type refs: GH-690 In this PR, we add DuckDB::LogicalType#child_type which is the following binding method. ```c duckdb_logical_type duckdb_list_type_child_type(duckdb_logical_type type); ``` ref: https://duckdb.org/docs/api/c/api.html#duckdb_list_type_child_type ref: https://github.com/duckdb/duckdb/blob/main/src/main/capi/logical_types-c.cpp#L226-L236 This is one of the steps for supporting duckdb_logical_column_type C API. --- ext/duckdb/logical_type.c | 23 +++++++++++++++++++++++ test/duckdb_test/logical_type_test.rb | 16 ++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/ext/duckdb/logical_type.c b/ext/duckdb/logical_type.c index c6217df5..bea4d8b2 100644 --- a/ext/duckdb/logical_type.c +++ b/ext/duckdb/logical_type.c @@ -8,6 +8,7 @@ static size_t memsize(const void *p); static VALUE duckdb_logical_type__type(VALUE self); static VALUE duckdb_logical_type_width(VALUE self); static VALUE duckdb_logical_type_scale(VALUE self); +static VALUE duckdb_logical_type_child_type(VALUE self); static const rb_data_type_t logical_type_data_type = { "DuckDB/LogicalType", @@ -73,6 +74,27 @@ static VALUE duckdb_logical_type_scale(VALUE self) { return INT2FIX(duckdb_decimal_scale(ctx->logical_type)); } +static VALUE duckdb_logical_type_child_type(VALUE self) { + rubyDuckDBLogicalType *ctx; + duckdb_type type_id; + duckdb_logical_type child_logical_type; + VALUE logical_type = Qnil; + + TypedData_Get_Struct(self, rubyDuckDBLogicalType, &logical_type_data_type, ctx); + type_id = duckdb_get_type_id(ctx->logical_type); + + switch(type_id) { + case DUCKDB_TYPE_LIST: + case DUCKDB_TYPE_MAP: + child_logical_type = duckdb_list_type_child_type(ctx->logical_type); + logical_type = rbduckdb_create_logical_type(child_logical_type); + break; + default: + logical_type = Qnil; + } + return logical_type; +} + VALUE rbduckdb_create_logical_type(duckdb_logical_type logical_type) { VALUE obj; rubyDuckDBLogicalType *ctx; @@ -95,4 +117,5 @@ void rbduckdb_init_duckdb_logical_type(void) { rb_define_private_method(cDuckDBLogicalType, "_type", duckdb_logical_type__type, 0); rb_define_method(cDuckDBLogicalType, "width", duckdb_logical_type_width, 0); rb_define_method(cDuckDBLogicalType, "scale", duckdb_logical_type_scale, 0); + rb_define_method(cDuckDBLogicalType, "child_type", duckdb_logical_type_child_type, 0); } diff --git a/test/duckdb_test/logical_type_test.rb b/test/duckdb_test/logical_type_test.rb index 0a244831..1410a7f1 100644 --- a/test/duckdb_test/logical_type_test.rb +++ b/test/duckdb_test/logical_type_test.rb @@ -119,6 +119,22 @@ def test_decimal_scale assert_equal(6, decimal_column.logical_type.scale) end + def test_list_child_type + list_columns = @columns.select { |column| column.type == :list } + child_types = list_columns.map do |list_column| + list_column.logical_type.child_type + end + assert(child_types.all? { |child_type| child_type.is_a?(DuckDB::LogicalType) }) + assert_equal([:integer, :varchar], child_types.map(&:type)) + end + + def test_map_child_type + map_column = @columns.detect { |column| column.type == :map } + child_type = map_column.logical_type.child_type + assert(child_type.is_a?(DuckDB::LogicalType)) + assert_equal(:struct, child_type.type) + end + private def create_data(con) From 43013b259904888bf0d8570bffb0fa88d9ddfbeb Mon Sep 17 00:00:00 2001 From: otegami Date: Tue, 4 Feb 2025 20:20:58 +0800 Subject: [PATCH 23/36] add documentation to DuckDB::LogicalType#child_type --- ext/duckdb/logical_type.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ext/duckdb/logical_type.c b/ext/duckdb/logical_type.c index bea4d8b2..971776c5 100644 --- a/ext/duckdb/logical_type.c +++ b/ext/duckdb/logical_type.c @@ -74,6 +74,13 @@ static VALUE duckdb_logical_type_scale(VALUE self) { return INT2FIX(duckdb_decimal_scale(ctx->logical_type)); } +/* + * call-seq: + * list_col.logical_type.child_type -> DuckDB::LogicalType + * + * Returns the child logical type for list and map types, otherwise nil. + * + */ static VALUE duckdb_logical_type_child_type(VALUE self) { rubyDuckDBLogicalType *ctx; duckdb_type type_id; From dacf0164b93688bca07bb8593bf0446777284ad5 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 8 Feb 2025 06:05:28 +0900 Subject: [PATCH 24/36] update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e1e3b48..60c505e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to this project will be documented in this file. # Unreleased +- add `DuckDB::LogicalType` class(Thanks to @otegami). + - `DuckDB::LogicalType` class is under construction. `DuckDB::LogicalType#type`, `DuckDB::LogicalType#width`, + `DuckDB::LogicalType#scale`, `DuckDB::LogicalType#child_type` are available. - add `DuckDB::Appender#error_message`. - fix error message when `DuckDB::Appender#flush`, `DuckDB::Appender#close`, `DuckDB::Appender#end_row`, `DuckDB::Appender#append_bool`, `DuckDB::Appender#append_int8`, `DuckDB::Appender#append_int16`, From c4d5f1fbcd1dc042d3031fd98b32b46097342811 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 8 Feb 2025 07:12:49 +0900 Subject: [PATCH 25/36] bump duckdb 1.2.0 - CI checks with duckdb 1.2.0. - change duckdb 1.2.0 in Dockerfile. --- .github/workflows/test_on_macos.yml | 2 +- .github/workflows/test_on_ubuntu.yml | 2 +- .github/workflows/test_on_windows.yml | 2 +- CHANGELOG.md | 1 + Dockerfile | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_on_macos.yml b/.github/workflows/test_on_macos.yml index 18b0a5af..17da2b4d 100644 --- a/.github/workflows/test_on_macos.yml +++ b/.github/workflows/test_on_macos.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: ruby: ['3.1.6', '3.2.6', '3.3.6', '3.4.1', 'head'] - duckdb: ['1.1.3', '1.1.1', '1.0.0'] + duckdb: ['1.2.0', '1.1.3', '1.1.1', '1.0.0'] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test_on_ubuntu.yml b/.github/workflows/test_on_ubuntu.yml index dd4334a4..21b0367e 100644 --- a/.github/workflows/test_on_ubuntu.yml +++ b/.github/workflows/test_on_ubuntu.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: ruby: ['3.1.6', '3.2.6', '3.3.6', '3.4.1', 'head'] - duckdb: ['1.1.3', '1.1.1', '1.0.0'] + duckdb: ['1.2.0', '1.1.3', '1.1.1', '1.0.0'] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test_on_windows.yml b/.github/workflows/test_on_windows.yml index 8ca1b357..2ff5882e 100644 --- a/.github/workflows/test_on_windows.yml +++ b/.github/workflows/test_on_windows.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: ruby: ['3.1.6', '3.2.6', '3.3.6', 'ucrt', 'mingw', 'mswin', 'head'] - duckdb: ['1.1.3', '1.1.1', '1.0.0'] + duckdb: ['1.2.0', '1.1.3', '1.1.1', '1.0.0'] steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 60c505e2..c5749099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ All notable changes to this project will be documented in this file. # Unreleased +- bump duckdb to 1.2.0. - add `DuckDB::LogicalType` class(Thanks to @otegami). - `DuckDB::LogicalType` class is under construction. `DuckDB::LogicalType#type`, `DuckDB::LogicalType#width`, `DuckDB::LogicalType#scale`, `DuckDB::LogicalType#child_type` are available. diff --git a/Dockerfile b/Dockerfile index 7f038706..435c1952 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ ARG RUBY_VERSION=3.3.6 FROM ruby:${RUBY_VERSION} -ARG DUCKDB_VERSION=1.1.3 +ARG DUCKDB_VERSION=1.2.0 ARG VALGRIND_VERSION=3.21.0 RUN apt update -qq && \ From a2758d583e11ff9e25689b1c80bfc904ee99b42c Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 9 Feb 2025 07:42:59 +0900 Subject: [PATCH 26/36] DuckDB::Result#row_count is depreacted DuckDB::Result#row_count, DuckDB::Result#row_size are deprecated. Because duckdb_row_count C-API of duckdb has been removed and may be removed in future versions of DuckDB. --- CHANGELOG.md | 3 +++ ext/duckdb/result.c | 32 -------------------------------- lib/duckdb/result.rb | 1 - test/duckdb_test/result_test.rb | 9 --------- 4 files changed, 3 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5749099..a154a1cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ All notable changes to this project will be documented in this file. `DuckDB::Appender#append_int32`, `DuckDB::Appender#append_int64`, `DuckDB::Appender#append_uint8` failed. - `DuckDB::Appender#begin_row` does nothing. Only returns self. `DuckDB::Appender#end_row` is only required. +## Breaking changes +- `DuckDB::Result#row_count`, `DuckDB::Result#row_size` are deprecated. + # 1.1.3.1 - 2024-11-27 - fix to `DuckDB::Connection#query` with multiple SQL statements. Calling PreparedStatement#destroy after each statement executed. - install valgrind in docker development environment. diff --git a/ext/duckdb/result.c b/ext/duckdb/result.c index 33a7fd3d..57958862 100644 --- a/ext/duckdb/result.c +++ b/ext/duckdb/result.c @@ -24,7 +24,6 @@ static void deallocate(void *ctx); static VALUE allocate(VALUE klass); static size_t memsize(const void *p); static VALUE duckdb_result_column_count(VALUE oDuckDBResult); -static VALUE duckdb_result_row_count(VALUE oDuckDBResult); static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult); static VALUE duckdb_result_columns(VALUE oDuckDBResult); static VALUE duckdb_result_streaming_p(VALUE oDuckDBResult); @@ -147,36 +146,6 @@ static VALUE duckdb_result_column_count(VALUE oDuckDBResult) { return LL2NUM(duckdb_column_count(&(ctx->result))); } -/* - * call-seq: - * result.row_count -> Integer - * - * Returns the column size of the result. - * - * DuckDB::Database.open do |db| - * db.connect do |con| - * r = con.query('CREATE TABLE t2 (id INT, name VARCHAR(128))') - * r = con.query("INSERT INTO t2 VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Catherine')") - * r = con.query('SELECT * FROM t2') - * r.row_count # => 3 - * r = con.query('SELECT * FROM t2 where id = 1') - * r.row_count # => 1 - * end - * end - * - */ -static VALUE duckdb_result_row_count(VALUE oDuckDBResult) { - -#ifdef DUCKDB_API_NO_DEPRECATED - return Qnil; -#else - rubyDuckDBResult *ctx; - rb_warn("`row_count` will be deprecated in the future."); - TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); - return LL2NUM(duckdb_row_count(&(ctx->result))); -#endif -} - /* * call-seq: * result.columns -> DuckDB::Column[] @@ -913,7 +882,6 @@ void rbduckdb_init_duckdb_result(void) { rb_define_alloc_func(cDuckDBResult, allocate); rb_define_method(cDuckDBResult, "column_count", duckdb_result_column_count, 0); - rb_define_method(cDuckDBResult, "row_count", duckdb_result_row_count, 0); /* deprecated */ rb_define_method(cDuckDBResult, "rows_changed", duckdb_result_rows_changed, 0); rb_define_method(cDuckDBResult, "columns", duckdb_result_columns, 0); rb_define_method(cDuckDBResult, "streaming?", duckdb_result_streaming_p, 0); diff --git a/lib/duckdb/result.rb b/lib/duckdb/result.rb index 0a1502c9..3c02dfac 100644 --- a/lib/duckdb/result.rb +++ b/lib/duckdb/result.rb @@ -27,7 +27,6 @@ class Result RETURN_TYPES = %i[invalid changed_rows nothing query_result].freeze alias column_size column_count - alias row_size row_count class << self def new diff --git a/test/duckdb_test/result_test.rb b/test/duckdb_test/result_test.rb index 82972b86..35607fd8 100644 --- a/test/duckdb_test/result_test.rb +++ b/test/duckdb_test/result_test.rb @@ -135,15 +135,6 @@ def test_column_count assert_equal(2, r.column_size) end - def test_row_count - r = @@con.query('SELECT * FROM table1') - assert_equal(2, r.row_count) - assert_equal(2, r.row_size) - r = @@con.query('SELECT * FROM table1 WHERE boolean_col = true') - assert_equal(1, r.row_count) - assert_equal(1, r.row_size) - end - def test_columns assert_instance_of(DuckDB::Column, @result.columns.first) end From 35e1246fc4381850424d5e1a88c40bcf73733d12 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 9 Feb 2025 08:11:10 +0900 Subject: [PATCH 27/36] deprecate DuckDB::Result.use_chunk_each, DuckDB::Result.use_chunk_each? Thease methods don't effect any behavior changes of ruby-duckdb. --- CHANGELOG.md | 1 + lib/duckdb/result.rb | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a154a1cf..0d752e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ## Breaking changes - `DuckDB::Result#row_count`, `DuckDB::Result#row_size` are deprecated. +- `DuckDB::Result#use_chunk_each?`, `DuckDB::Result#use_chunk_each=` are deprecated. # 1.1.3.1 - 2024-11-27 - fix to `DuckDB::Connection#query` with multiple SQL statements. Calling PreparedStatement#destroy after each statement executed. diff --git a/lib/duckdb/result.rb b/lib/duckdb/result.rb index 3c02dfac..41ca7d75 100644 --- a/lib/duckdb/result.rb +++ b/lib/duckdb/result.rb @@ -32,19 +32,6 @@ class << self def new raise DuckDB::Error, 'DuckDB::Result cannot be instantiated directly.' end - - def use_chunk_each=(value) # :nodoc: - raise('`changing DuckDB::Result.use_chunk_each to false` was deprecated.') unless value - - warn('`DuckDB::Result.use_chunk_each=` will be deprecated.') - - true - end - - def use_chunk_each? # :nodoc: - warn('`DuckDB::Result.use_chunk_each?` will be deprecated.') - true - end end def each(&) From 654b7b5b5ba75a7f55be364825add1d75773601c Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sun, 9 Feb 2025 08:44:49 +0900 Subject: [PATCH 28/36] always use duckdb_fetch_chunk use duckdb_fetch_chunk because ruby-duckdb supports duckdb >= 1.0.0. --- ext/duckdb/extconf.rb | 3 --- ext/duckdb/result.c | 4 ---- 2 files changed, 7 deletions(-) diff --git a/ext/duckdb/extconf.rb b/ext/duckdb/extconf.rb index 9324095c..cce41d2a 100644 --- a/ext/duckdb/extconf.rb +++ b/ext/duckdb/extconf.rb @@ -61,9 +61,6 @@ def print_message(msg) # check duckdb >= 1.0.0 have_func('duckdb_fetch_chunk', 'duckdb.h') -# check duckdb >= 1.0.0 -have_func('duckdb_fetch_chunk', 'duckdb.h') - # check duckdb >= 1.1.0 have_func('duckdb_result_error_type', 'duckdb.h') diff --git a/ext/duckdb/result.c b/ext/duckdb/result.c index 57958862..8bdab51c 100644 --- a/ext/duckdb/result.c +++ b/ext/duckdb/result.c @@ -239,11 +239,7 @@ static VALUE duckdb_result__chunk_stream(VALUE oDuckDBResult) { arg.col_count = duckdb_column_count(&(ctx->result)); -#ifdef HAVE_DUCKDB_H_GE_V1_0_0 while((arg.chunk = duckdb_fetch_chunk(ctx->result)) != NULL) { -#else - while((arg.chunk = duckdb_stream_fetch_chunk(ctx->result)) != NULL) { -#endif rb_ensure(yield_rows, (VALUE)&arg, destroy_data_chunk, (VALUE)&arg); } return Qnil; From 777093c237222139882385d4d8ae6f5f441123b9 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 06:59:06 +0900 Subject: [PATCH 29/36] try to ruby-asan test --- .github/workflows/ruby_asan_on_ubuntu.yml | 71 +++++++++++++++++++++++ ext/duckdb/prepared_statement.c | 7 ++- test/duckdb_test/ruby_asan_test.rb | 12 ++++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ruby_asan_on_ubuntu.yml create mode 100644 test/duckdb_test/ruby_asan_test.rb diff --git a/.github/workflows/ruby_asan_on_ubuntu.yml b/.github/workflows/ruby_asan_on_ubuntu.yml new file mode 100644 index 00000000..83d0f250 --- /dev/null +++ b/.github/workflows/ruby_asan_on_ubuntu.yml @@ -0,0 +1,71 @@ +name: Ubuntu + +on: + push: + branches: + - main + pull_request: + types: + - opened + - synchronize + - reopened + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + ruby: ['asan'] + duckdb: ['1.1.3', '1.1.1', '1.0.0'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + + - name: duckdb cache + id: duckdb-cache + uses: actions/cache@v4 + with: + path: duckdb-v${{ matrix.duckdb }} + key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }} + + - name: Build duckdb ${{ matrix.duckdb }} + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + if: steps.duckdb-cache.outputs.cache-hit != 'true' + run: | + git clone -b v$DUCKDB_VERSION https://github.com/cwida/duckdb.git duckdb-tmp-v$DUCKDB_VERSION + cd duckdb-tmp-v$DUCKDB_VERSION && make && cd .. + rm -rf duckdb-v$DUCKDB_VERSION + mkdir -p duckdb-v$DUCKDB_VERSION/build/release/src duckdb-v$DUCKDB_VERSION/src + cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.so duckdb-v$DUCKDB_VERSION/build/release/src + cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/ + + - name: bundle install with Ruby ${{ matrix.ruby }} + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + run: | + bundle install --jobs 4 --retry 3 + + - name: Build test with DUCKDB_API_NO_DEPRECATED and Ruby ${{ matrix.ruby }} + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + run: | + 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/ + bundle exec rake clean + + - name: Build with Ruby ${{ matrix.ruby }} + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + run: | + 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/ + + - name: test with Ruby ${{ matrix.ruby }} + env: + DUCKDB_VERSION: ${{ matrix.duckdb }} + run: | + env RUBYOPT=-W:deprecated ruby -Ilib test/duckdb_test/ruby_asan_test.rb diff --git a/ext/duckdb/prepared_statement.c b/ext/duckdb/prepared_statement.c index edf4b97e..d4d96172 100644 --- a/ext/duckdb/prepared_statement.c +++ b/ext/duckdb/prepared_statement.c @@ -82,6 +82,8 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q rubyDuckDBConnection *ctxcon; rubyDuckDBPreparedStatement *ctx; + duckdb_prepared_statement prepared_statement; + if (!rb_obj_is_kind_of(con, cDuckDBConnection)) { rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection"); } @@ -89,10 +91,11 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx); ctxcon = get_struct_connection(con); - if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) { - const char *error = duckdb_prepare_error(ctx->prepared_statement); + if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(prepared_statement)) == DuckDBError) { + const char *error = duckdb_prepare_error(prepared_statement); rb_raise(eDuckDBError, "%s", error ? error : "Failed to prepare statement(Database connection closed?)."); } + ctx->prepared_statement = prepared_statement; return self; } diff --git a/test/duckdb_test/ruby_asan_test.rb b/test/duckdb_test/ruby_asan_test.rb new file mode 100644 index 00000000..d21ac262 --- /dev/null +++ b/test/duckdb_test/ruby_asan_test.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +require 'duckdb' + +def run_duckdb_asan_test + db = DuckDB::Database.open + con = db.connect + stmt = DuckDB::PreparedStatement.new(con, 'INSERT INTO test VALUES (?, "hello")') +rescue Exception => e + p e +end + +run_duckdb_asan_test From 1e3b05c5a6381f7ff7a936aa3f38e1696e9cc1e6 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 07:29:34 +0900 Subject: [PATCH 30/36] fix some code. - calling duckdb_destroy_prepare. - rescue StandardError. --- ext/duckdb/prepared_statement.c | 1 + test/duckdb_test/ruby_asan_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/duckdb/prepared_statement.c b/ext/duckdb/prepared_statement.c index d4d96172..42a86060 100644 --- a/ext/duckdb/prepared_statement.c +++ b/ext/duckdb/prepared_statement.c @@ -93,6 +93,7 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(prepared_statement)) == DuckDBError) { const char *error = duckdb_prepare_error(prepared_statement); + duckdb_destroy_prepare(&prepared_statement); rb_raise(eDuckDBError, "%s", error ? error : "Failed to prepare statement(Database connection closed?)."); } ctx->prepared_statement = prepared_statement; diff --git a/test/duckdb_test/ruby_asan_test.rb b/test/duckdb_test/ruby_asan_test.rb index d21ac262..3524094b 100644 --- a/test/duckdb_test/ruby_asan_test.rb +++ b/test/duckdb_test/ruby_asan_test.rb @@ -4,8 +4,8 @@ def run_duckdb_asan_test db = DuckDB::Database.open con = db.connect - stmt = DuckDB::PreparedStatement.new(con, 'INSERT INTO test VALUES (?, "hello")') -rescue Exception => e + DuckDB::PreparedStatement.new(con, 'INSERT INTO test VALUES (?, "hello")') +rescue StandardError => e p e end From a602be3afee25d30809c0ed8822a92018cc956da Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 07:34:25 +0900 Subject: [PATCH 31/36] fix memory leak. --- ext/duckdb/prepared_statement.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ext/duckdb/prepared_statement.c b/ext/duckdb/prepared_statement.c index 42a86060..edf4b97e 100644 --- a/ext/duckdb/prepared_statement.c +++ b/ext/duckdb/prepared_statement.c @@ -82,8 +82,6 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q rubyDuckDBConnection *ctxcon; rubyDuckDBPreparedStatement *ctx; - duckdb_prepared_statement prepared_statement; - if (!rb_obj_is_kind_of(con, cDuckDBConnection)) { rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection"); } @@ -91,12 +89,10 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx); ctxcon = get_struct_connection(con); - if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(prepared_statement)) == DuckDBError) { - const char *error = duckdb_prepare_error(prepared_statement); - duckdb_destroy_prepare(&prepared_statement); + if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) { + const char *error = duckdb_prepare_error(ctx->prepared_statement); rb_raise(eDuckDBError, "%s", error ? error : "Failed to prepare statement(Database connection closed?)."); } - ctx->prepared_statement = prepared_statement; return self; } From 32c33f95d03f16f3fef5ab71764b21e5c28ab159 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 08:35:46 +0900 Subject: [PATCH 32/36] update --- ext/duckdb/prepared_statement.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/duckdb/prepared_statement.c b/ext/duckdb/prepared_statement.c index edf4b97e..67b20054 100644 --- a/ext/duckdb/prepared_statement.c +++ b/ext/duckdb/prepared_statement.c @@ -42,6 +42,7 @@ static const rb_data_type_t prepared_statement_data_type = { static void destroy_prepared_statement(rubyDuckDBPreparedStatement *p) { if (p->prepared_statement) { + fprintf(stderr, "destroy prepared statement\n"); duckdb_destroy_prepare(&(p->prepared_statement)); } } From 807d3f77291c3ec14acae8b53954c3f598f741a2 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 08:36:48 +0900 Subject: [PATCH 33/36] Revert "update" This reverts commit 504a919e7e33cf1994bc763354d920e80d740a92. --- ext/duckdb/prepared_statement.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/duckdb/prepared_statement.c b/ext/duckdb/prepared_statement.c index 67b20054..edf4b97e 100644 --- a/ext/duckdb/prepared_statement.c +++ b/ext/duckdb/prepared_statement.c @@ -42,7 +42,6 @@ static const rb_data_type_t prepared_statement_data_type = { static void destroy_prepared_statement(rubyDuckDBPreparedStatement *p) { if (p->prepared_statement) { - fprintf(stderr, "destroy prepared statement\n"); duckdb_destroy_prepare(&(p->prepared_statement)); } } From 57b8b7a6494fdfbe99a74b6495be2b1e4cdcdc68 Mon Sep 17 00:00:00 2001 From: Masaki Suketa Date: Sat, 25 Jan 2025 14:27:13 +0900 Subject: [PATCH 34/36] fix the DuckDB::PreparedStatement initialize function. --- ext/duckdb/prepared_statement.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ext/duckdb/prepared_statement.c b/ext/duckdb/prepared_statement.c index edf4b97e..ec6faff0 100644 --- a/ext/duckdb/prepared_statement.c +++ b/ext/duckdb/prepared_statement.c @@ -81,6 +81,8 @@ VALUE rbduckdb_prepared_statement_new(duckdb_connection con, duckdb_extracted_st static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE query) { rubyDuckDBConnection *ctxcon; rubyDuckDBPreparedStatement *ctx; + duckdb_state state; + const char *error; if (!rb_obj_is_kind_of(con, cDuckDBConnection)) { rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection"); @@ -89,10 +91,20 @@ static VALUE duckdb_prepared_statement_initialize(VALUE self, VALUE con, VALUE q TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx); ctxcon = get_struct_connection(con); - if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) { - const char *error = duckdb_prepare_error(ctx->prepared_statement); + // Initialize to NULL before preparing + ctx->prepared_statement = NULL; + + // Try to prepare the statement and get the state + state = duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)); + + // Get error message before any exception might be thrown + error = duckdb_prepare_error(ctx->prepared_statement); + + // If preparation failed, raise Ruby exception with the error message + if (state == DuckDBError) { rb_raise(eDuckDBError, "%s", error ? error : "Failed to prepare statement(Database connection closed?)."); } + return self; } From 88e34f6aeb6500c86371f8e2c6d84e2f984c36f4 Mon Sep 17 00:00:00 2001 From: otegami Date: Mon, 10 Feb 2025 18:41:16 +0800 Subject: [PATCH 35/36] use debug build for using asan --- .github/workflows/ruby_asan_on_ubuntu.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ruby_asan_on_ubuntu.yml b/.github/workflows/ruby_asan_on_ubuntu.yml index 83d0f250..9d93a557 100644 --- a/.github/workflows/ruby_asan_on_ubuntu.yml +++ b/.github/workflows/ruby_asan_on_ubuntu.yml @@ -39,10 +39,10 @@ jobs: if: steps.duckdb-cache.outputs.cache-hit != 'true' run: | git clone -b v$DUCKDB_VERSION https://github.com/cwida/duckdb.git duckdb-tmp-v$DUCKDB_VERSION - cd duckdb-tmp-v$DUCKDB_VERSION && make && cd .. + cd duckdb-tmp-v$DUCKDB_VERSION && make debug && cd .. rm -rf duckdb-v$DUCKDB_VERSION - mkdir -p duckdb-v$DUCKDB_VERSION/build/release/src duckdb-v$DUCKDB_VERSION/src - cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/release/src/*.so duckdb-v$DUCKDB_VERSION/build/release/src + mkdir -p duckdb-v$DUCKDB_VERSION/build/debug/src duckdb-v$DUCKDB_VERSION/src + cp -rip duckdb-tmp-v$DUCKDB_VERSION/build/debug/src/*.so duckdb-v$DUCKDB_VERSION/build/debug/src/ cp -rip duckdb-tmp-v$DUCKDB_VERSION/src/include duckdb-v$DUCKDB_VERSION/src/ - name: bundle install with Ruby ${{ matrix.ruby }} @@ -55,14 +55,14 @@ jobs: env: DUCKDB_VERSION: ${{ matrix.duckdb }} run: | - 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/ + 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/debug/src/ bundle exec rake clean - name: Build with Ruby ${{ matrix.ruby }} env: DUCKDB_VERSION: ${{ matrix.duckdb }} run: | - 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/ + 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/debug/src/ - name: test with Ruby ${{ matrix.ruby }} env: From e4f30bca19efd0ff47a80e79425af6b166952149 Mon Sep 17 00:00:00 2001 From: otegami Date: Mon, 10 Feb 2025 21:22:55 +0900 Subject: [PATCH 36/36] disable cache --- .github/workflows/ruby_asan_on_ubuntu.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ruby_asan_on_ubuntu.yml b/.github/workflows/ruby_asan_on_ubuntu.yml index 9d93a557..a9eaafb7 100644 --- a/.github/workflows/ruby_asan_on_ubuntu.yml +++ b/.github/workflows/ruby_asan_on_ubuntu.yml @@ -26,12 +26,12 @@ jobs: with: ruby-version: ${{ matrix.ruby }} - - name: duckdb cache - id: duckdb-cache - uses: actions/cache@v4 - with: - path: duckdb-v${{ matrix.duckdb }} - key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }} + # - name: duckdb cache + # id: duckdb-cache + # uses: actions/cache@v4 + # with: + # path: duckdb-v${{ matrix.duckdb }} + # key: ${{ runner.os }}-duckdb-v${{ matrix.duckdb }} - name: Build duckdb ${{ matrix.duckdb }} env: