Opens a native DuckDB streaming result through the Rducks extension and
returns the rows in DuckDB-sized batches as data frames, instead of an eager
DBI::dbGetQuery() result. Each batch is materialized directly from DuckDB
vectors to R values on the recorded R thread. The stream uses the extension's
database-scoped connection, so
it cannot see caller-connection temporary tables or views, uncommitted
transactions, or connection-local settings.
Value
An object of class rducks_query_stream with $next_batch()
(returns the next data-frame batch, or NULL at end of stream),
$close(), $schema (column names and Rducks type tokens), and $token.
The stream closes at end of input, on $close(), on native query error, when its handle
is garbage-collected, or when rducks_release() drops the last runtime
anchor. Explicit $close() releases resources promptly after early exit.
Details
With rducks_execution_plan("inproc"), one persistent native driver prepares,
executes, fetches, and closes the query while the recorded R thread services
scalar callbacks. Requests keep their original task identity and result
destination; no source-row ordering is promised. R table and aggregate
callbacks are unsupported in this managed mode and fail before off-thread R
access. This mode requires a duckdb-r build exposing version 2 of its
off-main R-source guard and scheduler-lease capability; ordinary builds
without that capability fail with an explicit error. Serial and IPC plans
retain their synchronous execution paths.
Only one stream can be open for a database runtime at a time. Recursive
stream operations, release, and plan changes during callbacks are rejected.
While a managed stream is open, native configuration guards also reject
direct SQL changes to threads (including aliases),
external_threads, and the guard's configuration controls on every
connection to the database. The original configuration restrictions are
restored after the native driver has stopped. Close the stream before
changing those settings.
Examples
# \donttest{
db <- duckdb::dbConnect(duckdb::duckdb(config = list(allow_unsigned_extensions = "true")))
#> duckdb keeps downloaded extensions and secrets in a temporary directory:
#> ℹ /tmp/RtmpHWria6/duckdb
#> This is removed when the R session ends.
#> • Extensions are re-downloaded each session.
#> • Secrets are lost.
#> ℹ Run duckdb(shared_home = TRUE) (or create ~/.duckdb) to keep them (suitable for most users).
#> ℹ Run duckdb(shared_home = FALSE) to accept the temporary directory (and silence this message).
#> ℹ See ?duckdb_storage for details and alternatives.
rducks_enable(db, threads = "single")
stream <- rducks_query_stream(db, "SELECT i::INTEGER AS i FROM range(1, 6) t(i)")
stream$next_batch()
#> i
#> 1 1
#> 2 2
#> 3 3
#> 4 4
#> 5 5
stream$close()
rducks_release(db)
DBI::dbDisconnect(db, shutdown = TRUE)
# }