Kuzu 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](
72 [[maybe_unused]] const std::vector<std::shared_ptr<common::ValueVector>>& params,
73 [[maybe_unused]] const std::vector<common::SelectionVector*>& paramSelVectors,
74 common::ValueVector& result, common::SelectionVector* resultSelVector,
75 void* /*dataPtr*/ = nullptr) -> void {
76 KU_ASSERT(params.empty() && paramSelVectors.empty());
77 for (auto i = 0u; i < resultSelVector->getSelSize(); ++i) {
78 auto resultPos = (*resultSelVector)[i];
79 result.copyFromValue(resultPos, common::Value(udfFunc()));
80 }
81 };
82 }
83
84 template<typename RESULT_TYPE, typename... Args>
85 static function::scalar_func_exec_t createUnaryExecFunc(RESULT_TYPE (* /*udfFunc*/)(Args...),
86 const std::vector<common::LogicalTypeID>& /*parameterTypes*/) {
88 }
89
90 template<typename RESULT_TYPE, typename OPERAND_TYPE>
91 static function::scalar_func_exec_t createUnaryExecFunc(RESULT_TYPE (*udfFunc)(OPERAND_TYPE),
92 const std::vector<common::LogicalTypeID>& parameterTypes) {
93 if (parameterTypes.size() != 1) {
95 "Expected exactly one parameter type for unary udf. Got: " +
96 std::to_string(parameterTypes.size()) + "."};
97 }
98 validateType<OPERAND_TYPE>(parameterTypes[0]);
100 [udfFunc](const std::vector<std::shared_ptr<common::ValueVector>>& params,
101 const std::vector<common::SelectionVector*>& paramSelVectors,
102 common::ValueVector& result, common::SelectionVector* resultSelVector,
103 void* /*dataPtr*/ = nullptr) -> void {
104 KU_ASSERT(params.size() == 1);
106 UnaryUDFFunctionWrapper>(*params[0], paramSelVectors[0], result, resultSelVector,
107 (void*)udfFunc);
108 };
109 return execFunc;
110 }
111
112 template<typename RESULT_TYPE, typename... Args>
113 static function::scalar_func_exec_t createBinaryExecFunc(RESULT_TYPE (* /*udfFunc*/)(Args...),
114 const std::vector<common::LogicalTypeID>& /*parameterTypes*/) {
116 }
117
118 template<typename RESULT_TYPE, typename LEFT_TYPE, typename RIGHT_TYPE>
120 RESULT_TYPE (*udfFunc)(LEFT_TYPE, RIGHT_TYPE),
121 const std::vector<common::LogicalTypeID>& parameterTypes) {
122 if (parameterTypes.size() != 2) {
124 "Expected exactly two parameter types for binary udf. Got: " +
125 std::to_string(parameterTypes.size()) + "."};
126 }
127 validateType<LEFT_TYPE>(parameterTypes[0]);
128 validateType<RIGHT_TYPE>(parameterTypes[1]);
130 [udfFunc](const std::vector<std::shared_ptr<common::ValueVector>>& params,
131 const std::vector<common::SelectionVector*>& paramSelVectors,
132 common::ValueVector& result, common::SelectionVector* resultSelVector,
133 void* /*dataPtr*/ = nullptr) -> void {
134 KU_ASSERT(params.size() == 2);
135 BinaryFunctionExecutor::executeSwitch<LEFT_TYPE, RIGHT_TYPE, RESULT_TYPE,
136 BinaryUDFExecutor, BinaryUDFFunctionWrapper>(*params[0], paramSelVectors[0],
137 *params[1], paramSelVectors[1], result, resultSelVector, (void*)udfFunc);
138 };
139 return execFunc;
140 }
141
142 template<typename RESULT_TYPE, typename... Args>
143 static function::scalar_func_exec_t createTernaryExecFunc(RESULT_TYPE (* /*udfFunc*/)(Args...),
144 const std::vector<common::LogicalTypeID>& /*parameterTypes*/) {
146 }
147
148 template<typename RESULT_TYPE, typename A_TYPE, typename B_TYPE, typename C_TYPE>
150 RESULT_TYPE (*udfFunc)(A_TYPE, B_TYPE, C_TYPE),
151 std::vector<common::LogicalTypeID> parameterTypes) {
152 if (parameterTypes.size() != 3) {
154 "Expected exactly three parameter types for ternary udf. Got: " +
155 std::to_string(parameterTypes.size()) + "."};
156 }
157 validateType<A_TYPE>(parameterTypes[0]);
158 validateType<B_TYPE>(parameterTypes[1]);
159 validateType<C_TYPE>(parameterTypes[2]);
161 [udfFunc](const std::vector<std::shared_ptr<common::ValueVector>>& params,
162 const std::vector<common::SelectionVector*>& paramSelVectors,
163 common::ValueVector& result, common::SelectionVector* resultSelVector,
164 void* /*dataPtr*/ = nullptr) -> void {
165 KU_ASSERT(params.size() == 3);
166 TernaryFunctionExecutor::executeSwitch<A_TYPE, B_TYPE, C_TYPE, RESULT_TYPE,
167 TernaryUDFExecutor, TernaryUDFFunctionWrapper>(*params[0], paramSelVectors[0],
168 *params[1], paramSelVectors[1], *params[2], paramSelVectors[2], result,
169 resultSelVector, (void*)udfFunc);
170 };
171 return execFunc;
172 }
173
174 template<typename TR, typename... Args>
175 static scalar_func_exec_t getScalarExecFunc(TR (*udfFunc)(Args...),
176 std::vector<common::LogicalTypeID> parameterTypes) {
177 constexpr auto numArgs = sizeof...(Args);
178 switch (numArgs) {
179 case 0:
180 return createEmptyParameterExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
181 case 1:
182 return createUnaryExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
183 case 2:
184 return createBinaryExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
185 case 3:
186 return createTernaryExecFunc<TR, Args...>(udfFunc, std::move(parameterTypes));
187 default:
188 throw common::BinderException("UDF function only supported until ternary!");
189 }
190 }
191
192 template<typename T>
194 if (std::is_same<T, bool>()) {
196 } else if (std::is_same<T, int8_t>()) {
198 } else if (std::is_same<T, int16_t>()) {
200 } else if (std::is_same<T, int32_t>()) {
202 } else if (std::is_same<T, int64_t>()) {
204 } else if (std::is_same<T, common::int128_t>()) {
206 } else if (std::is_same<T, uint8_t>()) {
208 } else if (std::is_same<T, uint16_t>()) {
210 } else if (std::is_same<T, uint32_t>()) {
212 } else if (std::is_same<T, uint64_t>()) {
214 } else if (std::is_same<T, float>()) {
216 } else if (std::is_same<T, double>()) {
218 } else if (std::is_same<T, common::ku_string_t>()) {
220 } else {
222 }
223 }
224
225 template<typename TA>
226 static void getParameterTypesRecursive(std::vector<common::LogicalTypeID>& arguments) {
227 arguments.push_back(getParameterType<TA>());
228 }
229
230 template<typename TA, typename TB, typename... Args>
231 static void getParameterTypesRecursive(std::vector<common::LogicalTypeID>& arguments) {
232 arguments.push_back(getParameterType<TA>());
233 getParameterTypesRecursive<TB, Args...>(arguments);
234 }
235
236 template<typename... Args>
237 static std::vector<common::LogicalTypeID> getParameterTypes() {
238 std::vector<common::LogicalTypeID> parameterTypes;
239 if constexpr (sizeof...(Args) > 0) {
240 getParameterTypesRecursive<Args...>(parameterTypes);
241 }
242 return parameterTypes;
243 }
244
245 template<typename TR, typename... Args>
246 static function_set getFunction(std::string name, TR (*udfFunc)(Args...),
247 std::vector<common::LogicalTypeID> parameterTypes, common::LogicalTypeID returnType) {
248 function_set definitions;
249 if (returnType == common::LogicalTypeID::STRING) {
251 }
252 validateType<TR>(returnType);
253 scalar_func_exec_t scalarExecFunc = getScalarExecFunc<TR, Args...>(udfFunc, parameterTypes);
254 definitions.push_back(std::make_unique<function::ScalarFunction>(std::move(name),
255 std::move(parameterTypes), returnType, std::move(scalarExecFunc)));
256 return definitions;
257 }
258
259 template<typename TR, typename... Args>
260 static function_set getFunction(std::string name, TR (*udfFunc)(Args...)) {
261 return getFunction<TR, Args...>(std::move(name), udfFunc, getParameterTypes<Args...>(),
263 }
264
265 template<typename TR, typename... Args>
266 static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc) {
267 function_set definitions;
268 definitions.push_back(std::make_unique<function::ScalarFunction>(std::move(name),
269 getParameterTypes<Args...>(), getParameterType<TR>(), std::move(execFunc)));
270 return definitions;
271 }
272
273 static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc,
274 std::vector<common::LogicalTypeID> parameterTypes, common::LogicalTypeID returnType) {
275 function_set definitions;
276 definitions.push_back(std::make_unique<function::ScalarFunction>(std::move(name),
277 std::move(parameterTypes), returnType, std::move(execFunc)));
278 return definitions;
279 }
280};
281
282} // namespace function
283} // 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:256
KUZU_API PhysicalTypeID getPhysicalType() const
Definition types.h:283
Definition sel_vector.h:98
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:177
@ UINT32
Definition types.h:192
@ UINT16
Definition types.h:193
@ INT64
Definition types.h:187
@ INT16
Definition types.h:189
@ STRING
Definition types.h:208
@ INT32
Definition types.h:188
@ UINT64
Definition types.h:191
@ BOOL
Definition types.h:186
@ INT128
Definition types.h:195
@ FLOAT
Definition types.h:197
@ UINT8
Definition types.h:194
@ INT8
Definition types.h:190
@ DOUBLE
Definition types.h:196
Definition binary_function_executor.h:6
std::vector< std::unique_ptr< Function > > function_set
Definition function.h:44
std::function< void(const std::vector< std::shared_ptr< common::ValueVector > > &, const std::vector< common::SelectionVector * > &, common::ValueVector &, common::SelectionVector *, void *)> scalar_func_exec_t
Definition scalar_function.h:18
Definition array_utils.h:7
static void executeSwitch(common::ValueVector &left, common::SelectionVector *leftSelVector, common::ValueVector &right, common::SelectionVector *rightSelVector, common::ValueVector &result, common::SelectionVector *resultSelVector, void *dataPtr)
Definition binary_function_executor.h:152
Definition udf_function.h:21
static void operation(LEFT_TYPE &left, RIGHT_TYPE &right, RESULT_TYPE &result, void *udfFunc)
Definition udf_function.h:23
Definition binary_function_executor.h:69
static void executeSwitch(common::ValueVector &a, common::SelectionVector *aSelVector, common::ValueVector &b, common::SelectionVector *bSelVector, common::ValueVector &c, common::SelectionVector *cSelVector, common::ValueVector &result, common::SelectionVector *resultSelVector, void *dataPtr)
Definition ternary_function_executor.h:392
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 ternary_function_executor.h:41
Definition udf_function.h:41
static function_set getFunction(std::string name, TR(*udfFunc)(Args...))
Definition udf_function.h:260
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:149
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:91
static scalar_func_exec_t getScalarExecFunc(TR(*udfFunc)(Args...), std::vector< common::LogicalTypeID > parameterTypes)
Definition udf_function.h:175
static void getParameterTypesRecursive(std::vector< common::LogicalTypeID > &arguments)
Definition udf_function.h:231
static function::scalar_func_exec_t createTernaryExecFunc(RESULT_TYPE(*)(Args...), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:143
static function::scalar_func_exec_t createUnaryExecFunc(RESULT_TYPE(*)(Args...), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:85
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:246
static void getParameterTypesRecursive(std::vector< common::LogicalTypeID > &arguments)
Definition udf_function.h:226
static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc, std::vector< common::LogicalTypeID > parameterTypes, common::LogicalTypeID returnType)
Definition udf_function.h:273
static function::scalar_func_exec_t createBinaryExecFunc(RESULT_TYPE(*)(Args...), const std::vector< common::LogicalTypeID > &)
Definition udf_function.h:113
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:237
static function::scalar_func_exec_t createBinaryExecFunc(RESULT_TYPE(*udfFunc)(LEFT_TYPE, RIGHT_TYPE), const std::vector< common::LogicalTypeID > &parameterTypes)
Definition udf_function.h:119
static common::LogicalTypeID getParameterType()
Definition udf_function.h:193
static function_set getVectorizedFunction(std::string name, scalar_func_exec_t execFunc)
Definition udf_function.h:266
static void executeSwitch(common::ValueVector &operand, common::SelectionVector *operandSelVector, common::ValueVector &result, common::SelectionVector *resultSelVector, void *dataPtr)
Definition unary_function_executor.h:148
Definition udf_function.h:12
static void operation(OPERAND_TYPE &input, RESULT_TYPE &result, void *udfFunc)
Definition udf_function.h:14
Definition unary_function_executor.h:91