tests/testthat/test-instance-cache.R

# The engine patch these guard --
# `patch/0042-Tell-a-database-still-in-use-from-a-shutdown-in-flight.patch` --
# is not reachable from R here: `rapi_startup()` builds a `DuckDB` directly, so
# no R call enters `DBInstanceCache`. Handing the driver cache to the engine
# (duckdb/duckdb-r#2857) would make it reachable. duckdb/duckdb-r#2644 tried
# that and was closed unmerged; on its branch, these two sequences wedged the
# session at 100% CPU.
# The subprocess is what makes the test safe to run either way: a spin inside
# `.Call()` reaches no interrupt check, so only a killed process ends it.

test_that("reopening a database that something still holds open returns", {
  skip_if_not_installed("callr")

  dir <- withr::local_tempdir()
  pkg <- get_package_name()

  answers <- callr::r(
    function(dir, pkg) {
      duckdb <- asNamespace(pkg)$duckdb

      reopen <- function(path) {
        tryCatch(
          {
            con <- DBI::dbConnect(duckdb(path))
            DBI::dbDisconnect(con)
            "reopened"
          },
          error = function(e) conditionMessage(e)
        )
      }

      # An unfinished result holds the connection's context, which holds the
      # instance, past the release of the last driver reference.
      held_by_result <- file.path(dir, "result.duckdb")
      con <- DBI::dbConnect(duckdb(held_by_result))
      res <- DBI::dbSendQuery(con, "SELECT 42")
      DBI::dbDisconnect(con)

      # A connection that is simply still open holds it too.
      held_by_connection <- file.path(dir, "connection.duckdb")
      drv <- duckdb(held_by_connection)
      open_con <- DBI::dbConnect(drv)

      out <- c(
        result = reopen(held_by_result),
        connection = reopen(held_by_connection)
      )

      DBI::dbClearResult(res)
      DBI::dbDisconnect(open_con)
      out
    },
    args = list(dir = dir, pkg = pkg),
    timeout = 60
  )

  # Reopening and refusing are both answers. Hanging is not, and is what the
  # timeout above turns into a failure rather than a stuck test run.
  expect_type(answers, "character")
  expect_named(answers, c("result", "connection"))
})

Try the duckdb package in your browser

Any scripts or data that you put into this service are public.

duckdb documentation built on Oct. 23, 2026, 5:06 p.m.