Kùzu C++ API
Loading...
Searching...
No Matches
udf_function.h
Go to the documentation of this file.
1#pragma once
2
3#include "binder.h"
4#include "catalog.h"
5#include "type_utils.h"
6#include "ku_string.h"
7#include "scalar_function.h"
8
9namespace kuzu {
10namespace function {
11
13 template<class OPERAND_TYPE, class RESULT_TYPE>
14 static inline void operation(OPERAND_TYPE& input, RESULT_TYPE& result, void* udfFunc) {
15 typedef RESULT_TYPE (*unary_udf_func)(OPERAND_TYPE);
16 auto unaryUDFFunc = (unary_udf_func)udfFunc;
17 result = unaryUDFFunc(input);
18 }
19};
20
22 template<class LEFT_TYPE, class RIGHT_TYPE, class RESULT_TYPE>
23 static inline void operation(LEFT_TYPE& left, RIGHT_TYPE& right, RESULT_TYPE& result,
24 void* udfFunc) {
25 typedef RESULT_TYPE (*binary_udf_func)(LEFT_TYPE, RIGHT_TYPE);
26 auto binaryUDFFunc = (binary_udf_func)udfFunc;
27 result = binaryUDFFunc(left, right);
28 }
29};
30
32 template<class A_TYPE, class B_TYPE, class C_TYPE, class RESULT_TYPE>
33 static inline void operation(A_TYPE& a, B_TYPE& b, C_TYPE& c, RESULT_TYPE& result,
34 void* udfFunc) {
35 typedef RESULT_TYPE (*ternary_udf_func)(A_TYPE, B_TYPE, C_TYPE);
36 auto ternaryUDFFunc = (ternary_udf_func)udfFunc;
37 result = ternaryUDFFunc(a, b, c);
38 }
39};
40
41struct UDF {
42 template<typename T>
44 auto logicalType = common::LogicalType{type};
45 auto physicalType = logicalType.getPhysicalType();
46 auto physicalTypeMatch = common::TypeUtils::visit(physicalType,
47 []<typename T1>(T1) { return std::is_same<T, T1>::value; });
48 auto logicalTypeMatch = common::TypeUtils::visit(logicalType,
49 []<typename T1>(T1) { return std::is_same<T, T1>::value; });
50 return logicalTypeMatch || physicalTypeMatch;
51 }
52
53 template<typename T>
54 static void validateType(const common::LogicalTypeID& type) {
55 if (!templateValidateType<T>(type)) {
57 "Incompatible udf parameter/return type and templated type."};
58 }
59 }
60
61 template<typename RESULT_TYPE, typename... Args>
63 const std::vector<common::LogicalTypeID>&) {
65 }
66
67 template<typename RESULT_TYPE>
69 const std::vector<common::LogicalTypeID>&) {
70 KU_UNUSED(udfFunc); // Disable compiler warnings.
71 return [udfFunc](const std::vector<std::shared_ptr<common::ValueVector>>& params,
72 common::ValueVector& result, void* /*dataPtr*/ = nullptr) -> void {
73 (void)params;
74 KU_ASSERT(params.size() == 0);
75 auto& resultSelVector = result.state->getSelVector();
76 for (auto i = 0u; i < resultSelVector.getSelSize(); ++i) {
77 auto resultPos = resultSelVector[i];
78 result.copyFromValue(resultPos, common::Value(udfFunc()));
79 }
80 };
81 }
82
83 template<typename RESULT_TYPE, typename... Args>
84 static function::scalar_func_exec_t createUnaryExecFunc(RESULT_TYPE (* /*udfFunc*/)(Args...),
85 const std::vector<common::LogicalTypeID>& /*parameterTypes*/) {
87 }
88
89 template<typename RESULT_TYPE, typename OPERAND_TYPE>
90 static function::scalar_func_exec_t createUnaryExecFunc(RESULT_TYPE (*udfFunc)(OPERAND_TYPE),
91 const std::vector<common::LogicalTypeID>& parameterTypes) {
92 if (parameterTypes.size() != 1) {
94 "Expected exactly one parameter type for unary udf. Got: " +
95 std::to_string(parameterTypes.size()) + "."};
96 }
97 validateType<OPERAND_TYPE>(parameterTypes[0]);
99 [udfFunc](const std::vector<std::shared_ptr<common::ValueVector>>& params,
100 common::ValueVector& result, void* /*dataPtr*/ = nullptr) -> void {
101 KU_ASSERT(params.size() == 1);
103 *params[0], result, (void*)udfFunc);
104 };
105 return execFunc;
106 }
107
108 template<typename RESULT_TYPE, typename... Args>
109 static function::scalar_func_exec_t createBinaryExecFunc(RESULT_TYPE (* /*udfFunc*/)(Args...),
110 const std::vector<common::LogicalTypeID>& /*parameterTypes*/) {
112 }
113
114 template<typename RESULT_TYPE, typename LEFT_TYPE, typename RIGHT_TYPE>
116 RESULT_TYPE (*udfFunc)(LEFT_TYPE, RIGHT_TYPE),
117 const std::vector<common::LogicalTypeID>& parameterTypes) {
118 if (parameterTypes.size() != 2) {
120 "Expected exactly two parameter types for binary udf. Got: " +
121 std::to_string(parameterTypes.size()) + "."};
122 }
123 validateType<LEFT_TYPE>(parameterTypes[0]);
124 validateType<RIGHT_TYPE>(parameterTypes[1]);
126 [udfFunc](const std::vector<std::shared_ptr<common::ValueVector>>& params,
127 common::ValueVector& result, void* /*dataPtr*/ = nullptr) -> void {
128 KU_ASSERT(params.size() == 2);
129 BinaryFunctionExecutor::executeUDF<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE,
130 BinaryUDFExecutor>(*params[0], *params[1], result, (void*)udfFunc);
131 };
132 return execFunc;
133 }
134
135 template<typename RESULT_TYPE, typename... Args>
136 static function::scalar_func_exec_t createTernaryExecFunc(RESULT_TYPE (* /*udfFunc*/)(Args...),
137 const std::vector<common::LogicalTypeID>& /*parameterTypes*/) {
139 }
140
141 template<typename RESULT_TYPE, typename A_TYPE, typename B_TYPE, typename C_TYPE>
143 RESULT_TYPE (*udfFunc)(A_TYPE, B_TYPE, C_TYPE),
144 std::vector<common::LogicalTypeID> parameterTypes) {
145 if (parameterTypes.size() != 3) {
147 "Expected exactly three parameter types for ternary udf. Got: " +
148 std::to_string(parameterTypes.size()) + "."};
149 }
150 validateType<A_TYPE>(parameterTypes[0]);
151 validateType<B_TYPE>(parameterTypes[1]);
152 validateType<C_TYPE>(parameterTypes[2]);
154 [udfFunc](const std::vector<std::shared_ptr<common::ValueVector>>& params,
155 common::ValueVector& result, void* /*dataPtr*/ = nullptr) -> void {
156 KU_ASSERT(params.size() == 3);
157 TernaryFunctionExecutor::executeUDF<A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE,
158 TernaryUDFExecutor>(*params[0], *params[1], *params[2], result, (void*)udfFunc);
159 };
160 return execFunc;
161 }
162
163 template<typename TR, typename... Args>
164 static scalar_func_exec_t getScalarExecFunc(TR (*udfFunc)(Args...),
165 std::vector<common::LogicalTypeID> parameterTypes) {
166 constexpr auto numArgs = sizeof...(Args);
167 switch (numArgs) {
168 case 0:
169 return createEmptyParameterExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
170 case 1:
171 return createUnaryExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
172 case 2:
173 return createBinaryExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
174 case 3:
175 return createTernaryExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
176 default:
177 throw common::BinderException("UDF function only supported until ternary!");
178 }
179 }
180
181 template<typename T>
183 if (std::is_same<T, bool>()) {
185 } else if (std::is_same<T, int8_t>()) {
187 } else if (std::is_same<T, int16_t>()) {
189 } else if (std::is_same<T, int32_t>()) {
191 } else if (std::is_same<T, int64_t>()) {
193 } else if (std::is_same<T, common::int128_t>()) {
195 } else if (std::is_same<T, uint8_t>()) {
197 } else if (std::is_same<T, uint16_t>()) {
199 } else if (std::is_same<T, uint32_t>()) {
201 } else if (std::is_same<T, uint64_t>()) {
203 } else if (std::is_same<T, float>()) {
205 } else if (std::is_same<T, double>()) {
207 } else if (std::is_same<T, common::ku_string_t>()) {
209 } else {
211 }
212 }
213
214 template<typename TA>
215 static void getParameterTypesRecursive(std::vector<common::LogicalTypeID>& arguments) {
216 arguments.push_back(getParameterType<TA>());
217 }
218
219 template<typename TA, typename TB, typename... Args>
220 static void getParameterTypesRecursive(std::vector<common::LogicalTypeID>& arguments) {
221 arguments.push_back(getParameterType<TA>());
222 getParameterTypesRecursive<TB, Args...>(arguments);
223 }
224
225 template<typename... Args>
226 static std::vector<common::LogicalTypeID> getParameterTypes() {
227 std::vector<common::LogicalTypeID> parameterTypes;
228 if constexpr (sizeof...(Args) > 0) {
229 getParameterTypesRecursive<Args...>(parameterTypes);
230 }
231 return parameterTypes;
232 }
233
234 template<typename TR, typename... Args>
235 static function_set getFunction(std::string name, TR (*udfFunc)(Args...),
236 std::vector<common::LogicalTypeID> parameterTypes, common::LogicalTypeID returnType) {
237 function_set definitions;
238 if (returnType == common::LogicalTypeID::STRING) {
240 }
241 validateType<TR>(returnType);
242 scalar_func_exec_t scalarExecFunc = getScalarExecFunc<TR, Args...>(udfFunc, parameterTypes);
243 definitions.push_back(std::make_unique<function::ScalarFunction>(std::move(name),
244 std::move(parameterTypes), returnType, std::move(scalarExecFunc)));
245 return definitions;
246 }
247
248 template<typename TR, typename... Args>
249 static function_set getFunction(std::string name, TR (*udfFunc)(Args...)) {
250 return getFunction<TR, Args...>(std::move(name), udfFunc, getParameterTypes<Args...>(),
252 }
253
254 template<typename TR, typename... Args>
255 static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc) {
256 function_set definitions;
257 definitions.push_back(std::make_unique<function::ScalarFunction>(std::move(name),
258 getParameterTypes<Args...>(), getParameterType<TR>(), std::move(execFunc)));
259 return definitions;
260 }
261
262 static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc,
263 std::vector<common::LogicalTypeID> parameterTypes, common::LogicalTypeID returnType) {
264 function_set definitions;
265 definitions.push_back(std::make_unique<function::ScalarFunction>(std::move(name),
266 std::move(parameterTypes), returnType, std::move(execFunc)));
267 return definitions;
268 }
269};
270
271} // namespace function
272} // namespace kuzu
#define KU_ASSERT(condition)
Definition assert.h:19
#define KU_UNUSED(expr)
Definition assert.h:31
#define KU_UNREACHABLE
Definition assert.h:28
Definition binder.h:9
Definition catalog.h:9
Definition types.h:249
KUZU_API PhysicalTypeID getPhysicalType() const
Definition types.h:276
static auto visit(const LogicalType &dataType, Fs... funcs)
Definition type_utils.h:144
Definition value.h:26
Definition value_vector.h:21
LogicalTypeID
Definition types.h:170
std::vector< std::unique_ptr< Function > > function_set
Definition function.h:43
std::function< void( const std::vector< std::shared_ptr< common::ValueVector > > &, common::ValueVector &, void *)> scalar_func_exec_t
Definition scalar_function.h:18
Definition array_utils.h:7
static void executeUDF(common::ValueVector &left, common::ValueVector &right, common::ValueVector &result, void *dataPtr)
Definition binary_function_executor.h:242
Definition udf_function.h:21
static void operation(LEFT_TYPE &left, RIGHT_TYPE &right, RESULT_TYPE &result, void *udfFunc)
Definition udf_function.h:23
static void executeUDF(common::ValueVector &a, common::ValueVector &b, common::ValueVector &c, common::ValueVector &result, void *dataPtr)
Definition ternary_function_executor.h:444
Definition udf_function.h:31
static void operation(A_TYPE &a, B_TYPE &b, C_TYPE &c, RESULT_TYPE &result, void *udfFunc)
Definition udf_function.h:33
Definition udf_function.h:41
static function_set getFunction(std::string name, TR(*udfFunc)(Args...))
Definition udf_function.h:249
static function::scalar_func_exec_t createTernaryExecFunc(RESULT_TYPE(*udfFunc)(A_TYPE, B_TYPE, C_TYPE), std::vector< common::LogicalTypeID > parameterTypes)
Definition udf_function.h:142
static function::scalar_func_exec_t createEmptyParameterExecFunc(RESULT_TYPE(*)(Args...), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:62
static function::scalar_func_exec_t createUnaryExecFunc(RESULT_TYPE(*udfFunc)(OPERAND_TYPE), const std::vector< common::LogicalTypeID > &parameterTypes)
Definition udf_function.h:90
static scalar_func_exec_t getScalarExecFunc(TR(*udfFunc)(Args...), std::vector< common::LogicalTypeID > parameterTypes)
Definition udf_function.h:164
static void getParameterTypesRecursive(std::vector< common::LogicalTypeID > &arguments)
Definition udf_function.h:220
static function::scalar_func_exec_t createTernaryExecFunc(RESULT_TYPE(*)(Args...), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:136
static function::scalar_func_exec_t createUnaryExecFunc(RESULT_TYPE(*)(Args...), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:84
static void validateType(const common::LogicalTypeID &type)
Definition udf_function.h:54
static function_set getFunction(std::string name, TR(*udfFunc)(Args...), std::vector< common::LogicalTypeID > parameterTypes, common::LogicalTypeID returnType)
Definition udf_function.h:235
static void getParameterTypesRecursive(std::vector< common::LogicalTypeID > &arguments)
Definition udf_function.h:215
static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc, std::vector< common::LogicalTypeID > parameterTypes, common::LogicalTypeID returnType)
Definition udf_function.h:262
static function::scalar_func_exec_t createBinaryExecFunc(RESULT_TYPE(*)(Args...), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:109
static function::scalar_func_exec_t createEmptyParameterExecFunc(RESULT_TYPE(*udfFunc)(), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:68
static bool templateValidateType(const common::LogicalTypeID &type)
Definition udf_function.h:43
static std::vector< common::LogicalTypeID > getParameterTypes()
Definition udf_function.h:226
static function::scalar_func_exec_t createBinaryExecFunc(RESULT_TYPE(*udfFunc)(LEFT_TYPE, RIGHT_TYPE), const std::vector< common::LogicalTypeID > &parameterTypes)
Definition udf_function.h:115
static common::LogicalTypeID getParameterType()
Definition udf_function.h:182
static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc)
Definition udf_function.h:255
static void executeUDF(common::ValueVector &operand, common::ValueVector &result, void *dataPtr)
Definition unary_function_executor.h:167
Definition udf_function.h:12
static void operation(OPERAND_TYPE &input, RESULT_TYPE &result, void *udfFunc)
Definition udf_function.h:14