Skip to content

Commit

Permalink
Add ADBC integration with the adbcdrivermanager package
Browse files Browse the repository at this point in the history
- Merge pull request duckdb/duckdb#8172 from paleolimbot/r-adbcdrivermanager
  • Loading branch information
hannes authored and krlmlr committed Sep 2, 2023
1 parent a5baf9b commit 6136364
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 2 deletions.
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ Suggests:
testthat,
tibble,
vctrs,
withr
withr,
adbcdrivermanager
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ S3method(print,duckdb_explain)
S3method(print,duckdb_expr)
S3method(print,duckdb_relation)
export(duckdb)
export(duckdb_adbc)
export(duckdb_fetch_arrow)
export(duckdb_fetch_record_batch)
export(duckdb_get_substrait)
Expand Down
42 changes: 42 additions & 0 deletions R/Driver.R
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,48 @@ duckdb_shutdown <- function(drv) {
invisible(TRUE)
}

#' @description
#' Return an [adbcdrivermanager::adbc_driver()] for use with Arrow Database
#' Connectivity via the adbcdrivermanager package.
#'
#' @return An object of class "adbc_driver"
#' @rdname duckdb
#' @export
#' @examplesIf requireNamespace("adbcdrivermanager", quietly = TRUE)
#' library(adbcdrivermanager)
#' with_adbc(db <- adbc_database_init(duckdb_adbc()), {
#' as.data.frame(read_adbc(db, "SELECT 1 as one;"))
#' })
duckdb_adbc <- function() {
init_func <- structure(rapi_adbc_init_func(), class = "adbc_driver_init_func")
adbcdrivermanager::adbc_driver(init_func, subclass = "duckdb_driver_adbc")
}

# Registered in zzz.R
adbc_database_init.duckdb_driver_adbc <- function(driver, ...) {
adbcdrivermanager::adbc_database_init_default(
driver,
list(...),
subclass = "duckdb_database_adbc"
)
}

adbc_connection_init.duckdb_database_adbc <- function(database, ...) {
adbcdrivermanager::adbc_connection_init_default(
database,
list(...),
subclass = "duckdb_connection_adbc"
)
}

adbc_statement_init.duckdb_connection_adbc <- function(connection, ...) {
adbcdrivermanager::adbc_statement_init_default(
connection,
list(...),
subclass = "duckdb_statement_adbc"
)
}

is_installed <- function(pkg) {
as.logical(requireNamespace(pkg, quietly = TRUE)) == TRUE
}
Expand Down
4 changes: 4 additions & 0 deletions R/cpp11.R
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ rapi_execute <- function(stmt, arrow, integer64) {
.Call(`_duckdb_rapi_execute`, stmt, arrow, integer64)
}

rapi_adbc_init_func <- function() {
.Call(`_duckdb_rapi_adbc_init_func`)
}

rapi_ptr_to_str <- function(extptr) {
.Call(`_duckdb_rapi_ptr_to_str`, extptr)
}
3 changes: 3 additions & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
s3_register("dbplyr::sql_escape_date", "duckdb_connection")
s3_register("dbplyr::sql_escape_datetime", "duckdb_connection")
s3_register("dplyr::tbl", "duckdb_connection")
s3_register("adbcdrivermanager::adbc_database_init", "duckdb_driver_adbc")
s3_register("adbcdrivermanager::adbc_connection_init", "duckdb_database_adbc")
s3_register("adbcdrivermanager::adbc_statement_init", "duckdb_connection_adbc")

invisible()
}
14 changes: 14 additions & 0 deletions man/duckdb.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,13 @@ extern "C" SEXP _duckdb_rapi_execute(SEXP stmt, SEXP arrow, SEXP integer64) {
END_CPP11
}
// utils.cpp
SEXP rapi_adbc_init_func();
extern "C" SEXP _duckdb_rapi_adbc_init_func() {
BEGIN_CPP11
return cpp11::as_sexp(rapi_adbc_init_func());
END_CPP11
}
// utils.cpp
cpp11::r_string rapi_ptr_to_str(SEXP extptr);
extern "C" SEXP _duckdb_rapi_ptr_to_str(SEXP extptr) {
BEGIN_CPP11
Expand All @@ -366,6 +373,7 @@ extern "C" SEXP _duckdb_rapi_ptr_to_str(SEXP extptr) {

extern "C" {
static const R_CallMethodDef CallEntries[] = {
{"_duckdb_rapi_adbc_init_func", (DL_FUNC) &_duckdb_rapi_adbc_init_func, 0},
{"_duckdb_rapi_bind", (DL_FUNC) &_duckdb_rapi_bind, 4},
{"_duckdb_rapi_connect", (DL_FUNC) &_duckdb_rapi_connect, 1},
{"_duckdb_rapi_disconnect", (DL_FUNC) &_duckdb_rapi_disconnect, 1},
Expand Down
10 changes: 9 additions & 1 deletion src/utils.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
#include "duckdb/common/types/timestamp.hpp"
#include "rapi.hpp"
#include "typesr.hpp"
#include "duckdb/common/types/timestamp.hpp"

using namespace duckdb;

typedef uint8_t AdbcStatusCode;
struct AdbcError;
extern "C" AdbcStatusCode duckdb_adbc_init(int version, void *raw_driver, struct AdbcError *error);

[[cpp11::register]] SEXP rapi_adbc_init_func() {
return R_MakeExternalPtrFn((DL_FUNC)duckdb_adbc_init, R_NilValue, R_NilValue);
}

SEXP duckdb::ToUtf8(SEXP string_sexp) {
cpp11::function enc2utf8 = RStrings::get().enc2utf8_sym;
return enc2utf8(string_sexp);
Expand Down
24 changes: 24 additions & 0 deletions tests/testthat/test-adbc.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
test_that("ADBC driver can create databases, connections, and statements", {
skip_if_not_installed("adbcdrivermanager")

drv <- duckdb_adbc()
expect_s3_class(drv, "duckdb_driver_adbc")

db <- adbcdrivermanager::local_adbc(
adbcdrivermanager::adbc_database_init(duckdb_adbc())
)
expect_s3_class(db, "duckdb_database_adbc")

con <- adbcdrivermanager::local_adbc(
adbcdrivermanager::adbc_connection_init(db)
)
expect_s3_class(con, "duckdb_connection_adbc")

stmt <- adbcdrivermanager::local_adbc(
adbcdrivermanager::adbc_statement_init(con)
)
expect_s3_class(stmt, "duckdb_statement_adbc")

stream <- adbcdrivermanager::read_adbc(con, "SELECT 1 as one;")
expect_identical(as.data.frame(stream), data.frame(one = 1L))
})

0 comments on commit 6136364

Please sign in to comment.