Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/workflows/ruby_asan_on_ubuntu.yml
Original file line number Diff line number Diff line change
@@ -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.2.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
16 changes: 13 additions & 3 deletions ext/duckdb/prepared_statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ 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;
char *pquery;
VALUE msg;

if (!rb_obj_is_kind_of(con, cDuckDBConnection)) {
rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection");
Expand All @@ -89,10 +93,16 @@ 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);
rb_raise(eDuckDBError, "%s", error ? error : "Failed to prepare statement(Database connection closed?).");
pquery = StringValueCStr(query);
state = duckdb_prepare(ctxcon->con, pquery, &(ctx->prepared_statement));

// If preparation failed, raise Ruby exception with the error message
if (state == DuckDBError) {
error = duckdb_prepare_error(ctx->prepared_statement);
msg = rb_str_new2(error ? error : "Failed to execute prepared statement.");
rb_raise(eDuckDBError, "%s", StringValueCStr(msg));
}

return self;
}

Expand Down
14 changes: 14 additions & 0 deletions test/duckdb_test/ruby_asan_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'duckdb'

def run_duckdb_asan_test
db = DuckDB::Database.open
con = db.connect
con.query('CREATE TABLE test (a INTEGER, b VARCHAR)')
DuckDB::PreparedStatement.new(con, 'INSERT INTO test VALUES (?, ?)')
# DuckDB::PreparedStatement.new(con, 'INSERT INTO test VALUES (?, "hello")')
rescue StandardError => e
p e
end

run_duckdb_asan_test