diff --git a/CHANGELOG.md b/CHANGELOG.md index 985c5f9..6a2404e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,10 @@ All notable changes to this project will be documented in this file. # Unreleased -- add DuckDB::PreparedStatement#prepare. -- DuckDB::Connection#prepared_statement accepts block. +- add `DuckDB::ExtracteStatements#each` method. +- add `DuckDB::ExtracteStatementsImpl#destroy` method. +- add `DuckDB::PreparedStatement#prepare`. +- `DuckDB::Connection#prepared_statement` accepts block and calls `PreparedStatement#destroy` after block executed. ```ruby con.prepared_statement('SELECT * FROM table WHERE id = ?') do |stmt| stmt.bind(1) diff --git a/ext/duckdb/extracted_statements.c b/ext/duckdb/extracted_statements.c index 6662c7d..68e2043 100644 --- a/ext/duckdb/extracted_statements.c +++ b/ext/duckdb/extracted_statements.c @@ -17,6 +17,7 @@ static VALUE allocate(VALUE klass); static size_t memsize(const void *p); static VALUE duckdb_extracted_statements_initialize(VALUE self, VALUE con, VALUE query); +static VALUE duckdb_extracted_statements_destroy(VALUE self); static VALUE duckdb_extracted_statements_size(VALUE self); static VALUE duckdb_extracted_statements_prepared_statement(VALUE self, VALUE con, VALUE index); @@ -56,12 +57,22 @@ static VALUE duckdb_extracted_statements_initialize(VALUE self, VALUE con, VALUE if (ctx->num_statements == 0) { error = duckdb_extract_statements_error(ctx->extracted_statements); - rb_raise(eDuckDBError, "%s", error); + rb_raise(eDuckDBError, "%s", error ? error : "Failed to extract statements(Database connection closed?)."); } return self; } +static VALUE duckdb_extracted_statements_destroy(VALUE self) { + rubyDuckDBExtractedStatements *ctx; + + TypedData_Get_Struct(self, rubyDuckDBExtractedStatements, &extract_statements_data_type, ctx); + + duckdb_destroy_extracted(&(ctx->extracted_statements)); + + return Qnil; +} + static VALUE duckdb_extracted_statements_size(VALUE self) { rubyDuckDBExtractedStatements *ctx; @@ -85,10 +96,11 @@ static VALUE duckdb_extracted_statements_prepared_statement(VALUE self, VALUE co } void rbduckdb_init_duckdb_extracted_statements(void) { - cDuckDBExtractedStatements = rb_define_class_under(mDuckDB, "ExtractedStatements", rb_cObject); + cDuckDBExtractedStatements = rb_define_class_under(mDuckDB, "ExtractedStatementsImpl", rb_cObject); rb_define_alloc_func(cDuckDBExtractedStatements, allocate); rb_define_method(cDuckDBExtractedStatements, "initialize", duckdb_extracted_statements_initialize, 2); + rb_define_method(cDuckDBExtractedStatements, "destroy", duckdb_extracted_statements_destroy, 0); rb_define_method(cDuckDBExtractedStatements, "size", duckdb_extracted_statements_size, 0); rb_define_method(cDuckDBExtractedStatements, "prepared_statement", duckdb_extracted_statements_prepared_statement, 2); } diff --git a/lib/duckdb.rb b/lib/duckdb.rb index 669c84f..2418f03 100644 --- a/lib/duckdb.rb +++ b/lib/duckdb.rb @@ -6,6 +6,7 @@ require 'duckdb/converter' require 'duckdb/database' require 'duckdb/connection' +require 'duckdb/extracted_statements' require 'duckdb/result' require 'duckdb/prepared_statement' require 'duckdb/pending_result' diff --git a/lib/duckdb/extracted_statements.rb b/lib/duckdb/extracted_statements.rb new file mode 100644 index 0000000..a906750 --- /dev/null +++ b/lib/duckdb/extracted_statements.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module DuckDB + class ExtractedStatements < ExtractedStatementsImpl + include Enumerable + + def initialize(con, sql) + @con = con + super(con, sql) + end + + def each + return to_enum(__method__) { size } unless block_given? + + size.times do |i| + yield prepared_statement(@con, i) + end + end + end +end diff --git a/test/duckdb_test/extracted_statements_test.rb b/test/duckdb_test/extracted_statements_test.rb index e217c99..fdbdcb8 100644 --- a/test/duckdb_test/extracted_statements_test.rb +++ b/test/duckdb_test/extracted_statements_test.rb @@ -63,6 +63,28 @@ def test_prepared_statement_with_invalid_index assert_equal 'Fail to get DuckDB::PreparedStatement object from ExtractedStatements object', ex.message end + def test_destroy + stmts = DuckDB::ExtractedStatements.new(@con, 'SELECT 1; SELECT 2; SELECT 3') + assert_nil(stmts.destroy) + end + + def test_each_without_block + stmts = DuckDB::ExtractedStatements.new(@con, 'SELECT 1; SELECT 2; SELECT 3') + enum_stmts = stmts.each + assert_instance_of(Enumerator, enum_stmts) + assert_equal(3, enum_stmts.size) + end + + def test_each_with_block + stmts = DuckDB::ExtractedStatements.new(@con, 'SELECT 1; SELECT 2; SELECT 3') + i = 1 + stmts.each do |stmt| + r = stmt.execute + assert_equal([[i]], r.to_a) + i += 1 + end + end + def teardown @con.close @db.close