diff --git a/R/cpp11.R b/R/cpp11.R index dcefa2f78..db272bb90 100644 --- a/R/cpp11.R +++ b/R/cpp11.R @@ -16,6 +16,10 @@ rapi_lock <- function(dual) { .Call(`_duckdb_rapi_lock`, dual) } +rapi_unlock <- function(dual) { + invisible(.Call(`_duckdb_rapi_unlock`, dual)) +} + rapi_is_locked <- function(dual) { .Call(`_duckdb_rapi_is_locked`, dual) } diff --git a/R/dbConnect__duckdb_driver.R b/R/dbConnect__duckdb_driver.R index 2307cc160..9b40aebe2 100644 --- a/R/dbConnect__duckdb_driver.R +++ b/R/dbConnect__duckdb_driver.R @@ -81,6 +81,7 @@ dbConnect__duckdb_driver <- function( # aha, a late comer. let's make a new instance. if (dbdir != drv@dbdir || !rapi_lock(drv@database_ref)) { + rapi_unlock(drv@database_ref) drv <- duckdb(dbdir, read_only, bigint, config) } diff --git a/src/cpp11.cpp b/src/cpp11.cpp index 7c9c811f6..cb3c53d39 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -35,6 +35,14 @@ extern "C" SEXP _duckdb_rapi_lock(SEXP dual) { END_CPP11 } // database.cpp +void rapi_unlock(duckdb::db_eptr_t dual); +extern "C" SEXP _duckdb_rapi_unlock(SEXP dual) { + BEGIN_CPP11 + rapi_unlock(cpp11::as_cpp>(dual)); + return R_NilValue; + END_CPP11 +} +// database.cpp bool rapi_is_locked(duckdb::db_eptr_t dual); extern "C" SEXP _duckdb_rapi_is_locked(SEXP dual) { BEGIN_CPP11 @@ -455,6 +463,7 @@ static const R_CallMethodDef CallEntries[] = { {"_duckdb_rapi_release", (DL_FUNC) &_duckdb_rapi_release, 1}, {"_duckdb_rapi_shutdown", (DL_FUNC) &_duckdb_rapi_shutdown, 1}, {"_duckdb_rapi_startup", (DL_FUNC) &_duckdb_rapi_startup, 3}, + {"_duckdb_rapi_unlock", (DL_FUNC) &_duckdb_rapi_unlock, 1}, {"_duckdb_rapi_unregister_arrow", (DL_FUNC) &_duckdb_rapi_unregister_arrow, 2}, {"_duckdb_rapi_unregister_df", (DL_FUNC) &_duckdb_rapi_unregister_df, 2}, {NULL, NULL, 0} diff --git a/src/database.cpp b/src/database.cpp index d6759535d..4b935a917 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -84,6 +84,13 @@ static bool CastRstringToVarchar(Vector &source, Vector &result, idx_t count, Ca return dual->has(); } +[[cpp11::register]] void rapi_unlock(duckdb::db_eptr_t dual) { + if (!dual || !dual.get()) { + cpp11::stop("rapi_unlock: Invalid database reference"); + } + dual->unlock(); +} + [[cpp11::register]] bool rapi_is_locked(duckdb::db_eptr_t dual) { if (!dual || !dual.get()) { cpp11::stop("rapi_is_locked: Invalid database reference"); diff --git a/tests/testthat/test-connect.R b/tests/testthat/test-connect.R index d8981f832..ba5b211c4 100644 --- a/tests/testthat/test-connect.R +++ b/tests/testthat/test-connect.R @@ -47,6 +47,14 @@ test_that("no warning after dbDisconnect() for driver stored in variable", { expect_warning(gc(), NA) }) +test_that("no warning on dbConnect() with other dbdir", { + con <- dbConnect(duckdb(), tempfile(fileext = ".duckdb")) + dbDisconnect(con) + + # The warning won't occur here anyway, this is to keep testthat happy + expect_warning(gc(), NA) +}) + test_that("can connect to the same in-memory database via the same driver object", { drv <- duckdb()