Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion r/R/compute.R
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,15 @@ register_scalar_function <- function(name, fun, in_type, out_type,
RegisterScalarUDF(name, scalar_function)

# register with dplyr binding (enables its use in mutate(), filter(), etc.)
# extra step to avoid saving this execution environment in the binding,
# which eliminates a warning when the same binding is registered twice
binding_fun <- function(...) build_expr(name, ...)
body(binding_fun)[[2]] <- name

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, what does this do? Why 2?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a less cryptic version of this...it's inlining the value of name into the function body:

binding_fun <- function(...) build_expr(name, ...)
str(as.list(body(binding_fun)))
#> List of 3
#>  $ : symbol build_expr
#>  $ : symbol name
#>  $ : symbol ...

environment(binding_fun) <- asNamespace("arrow")

register_binding(
name,
function(...) build_expr(name, ...),
binding_fun,
update_cache = TRUE
)

Expand Down
2 changes: 1 addition & 1 deletion r/R/dplyr-funcs.R
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ register_binding <- function(fun_name,
previous_fun <- registry[[unqualified_name]]

# if the unqualified name exists in the registry, warn
if (!is.null(previous_fun)) {
if (!is.null(previous_fun) && !identical(fun, previous_fun)) {
warn(
paste0(
"A \"",
Expand Down
10 changes: 9 additions & 1 deletion r/src/compute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,18 @@ std::vector<std::string> compute__GetFunctionNames() {
class RScalarUDFKernelState : public arrow::compute::KernelState {
public:
RScalarUDFKernelState(cpp11::sexp exec_func, cpp11::sexp resolver)
: exec_func_(exec_func), resolver_(resolver) {}
: exec_func_(exec_func),
resolver_(resolver),
exec_fun_shelter_(exec_func),
resolver_shelter_(resolver) {}

cpp11::function exec_func_;
cpp11::function resolver_;
// cpp11::function does not protect its argument from garbage collection,
// so we need a C++ object that does to make sure the functions still exist
// when called.
cpp11::sexp exec_fun_shelter_;
cpp11::sexp resolver_shelter_;
};

arrow::Result<arrow::TypeHolder> ResolveScalarUDFOutputType(
Expand Down
4 changes: 3 additions & 1 deletion r/src/recordbatchreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class RFunctionRecordBatchReader : public arrow::RecordBatchReader {
public:
RFunctionRecordBatchReader(cpp11::sexp fun,
const std::shared_ptr<arrow::Schema>& schema)
: fun_(fun), schema_(schema) {}
: fun_(fun), fun_shelter_(fun), schema_(schema) {}

std::shared_ptr<arrow::Schema> schema() const { return schema_; }

Expand Down Expand Up @@ -95,6 +95,8 @@ class RFunctionRecordBatchReader : public arrow::RecordBatchReader {

private:
cpp11::function fun_;
// Because cpp11::function does not protect its argument from garbage collection
cpp11::sexp fun_shelter_;
std::shared_ptr<arrow::Schema> schema_;
};

Expand Down
3 changes: 3 additions & 0 deletions r/tests/testthat/test-dplyr-funcs.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ test_that("register_binding()/unregister_binding() works", {
register_binding("some.pkg2::some_fun", fun2, fake_registry),
"A \"some_fun\" binding already exists in the registry and will be overwritten."
)

# No warning when an identical function is re-registered
expect_silent(register_binding("some.pkg2::some_fun", fun2, fake_registry))
})

test_that("register_binding_agg() works", {
Expand Down