|
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 |
|
| 17 | +#include "neug/common/columns/value_columns.h" |
17 | 18 | #include "neug/compiler/extension/extension_api.h" |
| 19 | +#include "neug/compiler/function/neug_call_function.h" |
| 20 | +#include "neug/execution/common/context.h" |
| 21 | +#include "neug/execution/common/params_map.h" |
| 22 | +#include "neug/utils/exception/exception.h" |
| 23 | + |
| 24 | +namespace { |
| 25 | + |
| 26 | +// String literal, or $param (ParamsMap key without '$'). |
| 27 | +struct DeferredCallArg { |
| 28 | + bool is_param = false; |
| 29 | + std::string param_name; |
| 30 | + std::string literal; |
| 31 | + |
| 32 | + static DeferredCallArg FromLiteral(std::string value) { |
| 33 | + DeferredCallArg arg; |
| 34 | + arg.literal = std::move(value); |
| 35 | + return arg; |
| 36 | + } |
| 37 | + |
| 38 | + static DeferredCallArg FromParam(std::string name) { |
| 39 | + DeferredCallArg arg; |
| 40 | + arg.is_param = true; |
| 41 | + arg.param_name = std::move(name); |
| 42 | + return arg; |
| 43 | + } |
| 44 | + |
| 45 | + std::string resolve(const neug::execution::ParamsMap& params) const { |
| 46 | + if (!is_param) { |
| 47 | + return literal; |
| 48 | + } |
| 49 | + auto it = params.find(param_name); |
| 50 | + if (it == params.end() || it->second.IsNull()) { |
| 51 | + THROW_INVALID_ARGUMENT_EXCEPTION( |
| 52 | + "Missing parameter for TEST_ECHO_PARAM: " + param_name); |
| 53 | + } |
| 54 | + return it->second.GetValue<std::string>(); |
| 55 | + } |
| 56 | +}; |
| 57 | + |
| 58 | +struct EchoParamFuncInput : public neug::function::CallFuncInputBase { |
| 59 | + DeferredCallArg arg; |
| 60 | + std::string value; |
| 61 | + |
| 62 | + std::unique_ptr<neug::function::CallFuncInputBase> bindParams( |
| 63 | + const neug::execution::ParamsMap& params) const override { |
| 64 | + auto bound = std::make_unique<EchoParamFuncInput>(*this); |
| 65 | + bound->value = arg.resolve(params); |
| 66 | + return bound; |
| 67 | + } |
| 68 | +}; |
| 69 | + |
| 70 | +struct TestEchoParamFunction { |
| 71 | + static constexpr const char* name = "TEST_ECHO_PARAM"; |
| 72 | + |
| 73 | + static neug::function::function_set getFunctionSet() { |
| 74 | + auto func = std::make_unique<neug::function::NeugCallFunction>( |
| 75 | + name, |
| 76 | + neug::function::call_input_types{ |
| 77 | + neug::common::DataType(neug::common::DataTypeId::kVarchar)}, |
| 78 | + neug::function::call_output_columns{ |
| 79 | + {"value", |
| 80 | + neug::common::DataType(neug::common::DataTypeId::kVarchar)}}); |
| 81 | + |
| 82 | + func->bindFunc = |
| 83 | + [](const neug::Schema&, const neug::execution::ContextMeta&, |
| 84 | + const ::physical::PhysicalPlan& plan, |
| 85 | + int op_idx) -> std::unique_ptr<neug::function::CallFuncInputBase> { |
| 86 | + const auto& procedure = plan.plan(op_idx).opr().procedure_call(); |
| 87 | + if (procedure.query().arguments_size() < 1) { |
| 88 | + THROW_INVALID_ARGUMENT_EXCEPTION( |
| 89 | + "TEST_ECHO_PARAM requires 1 VARCHAR argument"); |
| 90 | + } |
| 91 | + auto input = std::make_unique<EchoParamFuncInput>(); |
| 92 | + const auto& arg = procedure.query().arguments(0); |
| 93 | + if (arg.has_param()) { |
| 94 | + input->arg = DeferredCallArg::FromParam(arg.param().name()); |
| 95 | + } else if (arg.has_const_() && arg.const_().has_str()) { |
| 96 | + input->arg = DeferredCallArg::FromLiteral(arg.const_().str()); |
| 97 | + } else { |
| 98 | + THROW_INVALID_ARGUMENT_EXCEPTION( |
| 99 | + "TEST_ECHO_PARAM requires a string constant or $param"); |
| 100 | + } |
| 101 | + return input; |
| 102 | + }; |
| 103 | + |
| 104 | + func->execFunc = [](const neug::function::CallFuncInputBase& input_base, |
| 105 | + neug::IStorageInterface&) { |
| 106 | + const auto& input = static_cast<const EchoParamFuncInput&>(input_base); |
| 107 | + |
| 108 | + neug::ValueColumnBuilder<std::string> builder; |
| 109 | + builder.reserve(1); |
| 110 | + builder.push_back_opt(input.value); |
| 111 | + |
| 112 | + neug::execution::Context ctx; |
| 113 | + neug::DataChunk chunk; |
| 114 | + chunk.set(0, builder.finish()); |
| 115 | + ctx.append_chunk(std::move(chunk)); |
| 116 | + ctx.tag_ids = {0}; |
| 117 | + return ctx; |
| 118 | + }; |
| 119 | + |
| 120 | + neug::function::function_set set; |
| 121 | + set.push_back(std::move(func)); |
| 122 | + return set; |
| 123 | + } |
| 124 | +}; |
| 125 | + |
| 126 | +} // namespace |
18 | 127 |
|
19 | 128 | extern "C" { |
20 | 129 |
|
21 | 130 | void Init() { |
| 131 | + neug::extension::ExtensionAPI::registerFunction<TestEchoParamFunction>( |
| 132 | + neug::catalog::CatalogEntryType::TABLE_FUNCTION_ENTRY); |
22 | 133 | neug::extension::ExtensionAPI::registerExtension( |
23 | 134 | neug::extension::ExtensionInfo{ |
24 | 135 | "test_out_of_tree", |
25 | | - "Test extension for validating out-of-tree extension builds."}); |
| 136 | + "Test extension for out-of-tree builds and CALL $params " |
| 137 | + "(TEST_ECHO_PARAM)."}); |
26 | 138 | } |
27 | 139 |
|
28 | 140 | const char* Name() { return "TEST_OUT_OF_TREE"; } |
|
0 commit comments