Files
scylladb/cql3/functions/user_function.cc
Wojciech Mitros 56c5459c50 wasm: add null handling for wasm udf
As the name suggests, for UDFs defined as RETURNS NULL ON NULL
INPUT, we sometimes want to return nulls. However, currently
we do not return nulls. Instead, we fail on the null check in
init_arg_visitor. Fix by adding null handling before passing
arguments, same as in lua.

Signed-off-by: Wojciech Mitros <wojciech.mitros@scylladb.com>

Closes #10298
2022-03-31 12:27:38 +03:00

70 lines
2.4 KiB
C++

/*
* Copyright (C) 2019-present ScyllaDB
*/
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "user_function.hh"
#include "log.hh"
#include "cql_serialization_format.hh"
#include <seastar/core/thread.hh>
namespace cql3 {
namespace functions {
extern logging::logger log;
user_function::user_function(function_name name, std::vector<data_type> arg_types, std::vector<sstring> arg_names,
sstring body, sstring language, data_type return_type, bool called_on_null_input, context ctx)
: abstract_function(std::move(name), std::move(arg_types), std::move(return_type)),
_arg_names(std::move(arg_names)), _body(std::move(body)), _language(std::move(language)),
_called_on_null_input(called_on_null_input), _ctx(std::move(ctx)) {}
bool user_function::is_pure() const { return true; }
bool user_function::is_native() const { return false; }
bool user_function::is_aggregate() const { return false; }
bool user_function::requires_thread() const { return true; }
bytes_opt user_function::execute(cql_serialization_format sf, const std::vector<bytes_opt>& parameters) {
const auto& types = arg_types();
if (parameters.size() != types.size()) {
throw std::logic_error("Wrong number of parameters");
}
if (!seastar::thread::running_in_thread()) {
on_internal_error(log, "User function cannot be executed in this context");
}
for (auto& param : parameters) {
if (!param && !_called_on_null_input) {
return std::nullopt;
}
}
return seastar::visit(_ctx,
[&] (lua_context& ctx) -> bytes_opt {
std::vector<data_value> values;
values.reserve(parameters.size());
for (int i = 0, n = types.size(); i != n; ++i) {
const data_type& type = types[i];
const bytes_opt& bytes = parameters[i];
values.push_back(bytes ? type->deserialize(*bytes) : data_value::make_null(type));
}
return lua::run_script(lua::bitcode_view{ctx.bitcode}, values, return_type(), ctx.cfg).get0();
},
[&] (wasm::context& ctx) {
try {
return wasm::run_script(ctx, arg_types(), parameters, return_type(), _called_on_null_input).get0();
} catch (const wasm::exception& e) {
throw exceptions::invalid_request_exception(format("UDF error: {}", e.what()));
}
});
}
}
}