diff --git a/R/cpp11.R b/R/cpp11.R index bb7b55671..ee05cb968 100644 --- a/R/cpp11.R +++ b/R/cpp11.R @@ -52,8 +52,8 @@ rapi_expr_reference <- function(rnames) { .Call(`_duckdb_rapi_expr_reference`, rnames) } -rapi_expr_constant <- function(val) { - .Call(`_duckdb_rapi_expr_constant`, val) +rapi_expr_constant <- function(val, typed_logical_null) { + .Call(`_duckdb_rapi_expr_constant`, val, typed_logical_null) } rapi_expr_function <- function(name, args, order_bys, filter_bys) { diff --git a/R/relational.R b/R/relational.R index 32e9c3760..12badca1e 100644 --- a/R/relational.R +++ b/R/relational.R @@ -20,12 +20,17 @@ expr_reference <- function(names, table = NULL) { #' Create a constant expression #' @param val the constant value +#' @param typed_logical_null Whether NA is converted to a LOGICAL NULL or a SQLNULL #' @return a constant expression #' @noRd #' @examples #' const_int_expr <- expr_constant(42) #' const_str_expr <- expr_constant("Hello, World") -expr_constant <- rapi_expr_constant +#' const_sql_null_expr <- expr_constant(NA) +#' const_lgl_null_expr <- expr_constant(NA, TRUE) +expr_constant <- function(val, typed_logical_null = FALSE) { + rapi_expr_constant(val, typed_logical_null) +} #' Create a function call expression #' @param name the function name diff --git a/man/duckdb.Rd b/man/duckdb.Rd index b1eea5de7..d4d90fd1b 100644 --- a/man/duckdb.Rd +++ b/man/duckdb.Rd @@ -92,7 +92,7 @@ An object of class "adbc_driver" \code{duckdb_shutdown()} shuts down a database instance. -Return an \code{\link[adbcdrivermanager:adbc_driver_void]{adbcdrivermanager::adbc_driver()}} for use with Arrow Database +Return an \code{\link[adbcdrivermanager:adbc_driver]{adbcdrivermanager::adbc_driver()}} for use with Arrow Database Connectivity via the adbcdrivermanager package. \code{dbConnect()} connects to a database instance. diff --git a/src/cpp11.cpp b/src/cpp11.cpp index eec4d78f6..1d3f40fe6 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -104,10 +104,10 @@ extern "C" SEXP _duckdb_rapi_expr_reference(SEXP rnames) { END_CPP11 } // relational.cpp -SEXP rapi_expr_constant(sexp val); -extern "C" SEXP _duckdb_rapi_expr_constant(SEXP val) { +SEXP rapi_expr_constant(sexp val, bool typed_logical_null); +extern "C" SEXP _duckdb_rapi_expr_constant(SEXP val, SEXP typed_logical_null) { BEGIN_CPP11 - return cpp11::as_sexp(rapi_expr_constant(cpp11::as_cpp>(val))); + return cpp11::as_sexp(rapi_expr_constant(cpp11::as_cpp>(val), cpp11::as_cpp>(typed_logical_null))); END_CPP11 } // relational.cpp @@ -424,7 +424,7 @@ static const R_CallMethodDef CallEntries[] = { {"_duckdb_rapi_disconnect", (DL_FUNC) &_duckdb_rapi_disconnect, 1}, {"_duckdb_rapi_execute", (DL_FUNC) &_duckdb_rapi_execute, 3}, {"_duckdb_rapi_execute_arrow", (DL_FUNC) &_duckdb_rapi_execute_arrow, 2}, - {"_duckdb_rapi_expr_constant", (DL_FUNC) &_duckdb_rapi_expr_constant, 1}, + {"_duckdb_rapi_expr_constant", (DL_FUNC) &_duckdb_rapi_expr_constant, 2}, {"_duckdb_rapi_expr_function", (DL_FUNC) &_duckdb_rapi_expr_function, 4}, {"_duckdb_rapi_expr_reference", (DL_FUNC) &_duckdb_rapi_expr_reference, 1}, {"_duckdb_rapi_expr_set_alias", (DL_FUNC) &_duckdb_rapi_expr_set_alias, 2}, diff --git a/src/relational.cpp b/src/relational.cpp index bc4bda5eb..9c032fb8c 100644 --- a/src/relational.cpp +++ b/src/relational.cpp @@ -60,11 +60,11 @@ external_pointer make_external_prot(const string &rclass, SEXP prot, ARGS &&. return make_external("duckdb_expr", names); } -[[cpp11::register]] SEXP rapi_expr_constant(sexp val) { +[[cpp11::register]] SEXP rapi_expr_constant(sexp val, bool typed_logical_null) { if (LENGTH(val) != 1) { stop("expr_constant: Need value of length one"); } - return make_external("duckdb_expr", RApiTypes::SexpToValue(val, 0, false)); + return make_external("duckdb_expr", RApiTypes::SexpToValue(val, 0, typed_logical_null)); } [[cpp11::register]] SEXP rapi_expr_function(std::string name, list args, list order_bys, list filter_bys) { diff --git a/tests/testthat/test-list.R b/tests/testthat/test-list.R index c03b9fedc..10597cbf5 100644 --- a/tests/testthat/test-list.R +++ b/tests/testthat/test-list.R @@ -41,3 +41,4 @@ test_that("rel_filter() handles LIST logical type", { df2 <- rel_to_altrep(rel2) expect_equal(df1$a, df2$a) }) + diff --git a/tests/testthat/test-relational.R b/tests/testthat/test-relational.R index f0edc1a70..85e17c9b0 100644 --- a/tests/testthat/test-relational.R +++ b/tests/testthat/test-relational.R @@ -76,6 +76,13 @@ test_that("we can create various expressions and don't crash", { expect_true(TRUE) }) +test_that("we can create a constant NA with LOGICAL type", { + rel1 <- rel_from_df(con, data.frame(x = 42)) + exprs <- list( + y = expr_constant(NA, TRUE) + ) + expect_equal(rel_to_altrep(rel_project(rel1, exprs))[, ], NA) +}) # TODO should maybe be a different file, test_enum_strings.R