diff --git a/ext/sqlite3/database.c b/ext/sqlite3/database.c index 2c949b30..2a7adb09 100644 --- a/ext/sqlite3/database.c +++ b/ext/sqlite3/database.c @@ -10,6 +10,10 @@ if(!_ctxt->db) \ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database"); +#define REQUIRE_CLOSED_DB(_ctxt) \ + if(_ctxt->db) \ + rb_raise(rb_path2class("SQLite3::Exception"), "cannot open a database that is already open"); + VALUE cSqlite3Database; /* See adr/2024-09-fork-safety.md */ @@ -188,6 +192,7 @@ rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs) int flags; TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx); + REQUIRE_CLOSED_DB(ctx); #if defined TAINTING_SUPPORT # if defined StringValueCStr @@ -988,6 +993,7 @@ rb_sqlite3_open16(VALUE self, VALUE file) sqlite3RubyPtr ctx; TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx); + REQUIRE_CLOSED_DB(ctx); #if defined TAINTING_SUPPORT #if defined StringValueCStr diff --git a/test/test_database.rb b/test/test_database.rb index 4b02ee6e..95b6f8f9 100644 --- a/test/test_database.rb +++ b/test/test_database.rb @@ -66,6 +66,18 @@ def test_segv assert_raises { SQLite3::Database.new 1 } # rubocop:disable Minitest/UnspecifiedException end + def test_open_v2_raises_when_database_is_already_open + assert_raise(SQLite3::Exception) do + db.send(:open_v2, ":memory:", Constants::Open::READWRITE | Constants::Open::CREATE, nil) + end + end + + def test_open16_raises_when_database_is_already_open + assert_raise(SQLite3::Exception) do + db.send(:open16, ":memory:".encode(Encoding::UTF_16LE)) + end + end + def test_db_filename tf = nil assert_equal "", @db.filename("main")