1616
1717内置C++函数的参数类型限定为:BOOL类型,数值类型,时间戳日期类型和字符串类型。C++类型SQL类型对应关系如下:
1818
19- | SQL类型 | C/C++ 类型 |
20- | :-------- | :----------------- |
21- | BOOL | ` bool ` |
22- | SMALLINT | ` int16_t ` |
23- | INT | ` int32_t ` |
24- | BIGINT | ` int64_t ` |
25- | FLOAT | ` float ` |
26- | DOUBLE | ` double ` |
19+ | SQL类型 | C/C++ 类型 |
20+ | :-------- | :---------- |
21+ | BOOL | ` bool ` |
22+ | SMALLINT | ` int16_t ` |
23+ | INT | ` int32_t ` |
24+ | BIGINT | ` int64_t ` |
25+ | FLOAT | ` float ` |
26+ | DOUBLE | ` double ` |
2727| STRING | ` StringRef ` |
2828| TIMESTAMP | ` Timestamp ` |
2929| DATE | ` Date ` |
4444 };
4545 ```
4646
47+ - 如果参数声明为nullable的,那么所有参数都是nullable的,每一个输入参数其后需要添加bool参数(通常命名为is_null),其顺序为` arg1, arg1_is_null, arg2, arg2_is_null, ... ` 。不可以随意调整参数顺序。
48+ - 如果返回值声明为nullable的,那么通过参数来返回,并且添加bool参数(通常命名为is_null)来表示返回值是否为null
49+
50+ 例如,函数sum有俩个参数,如果参数和返回值设置为nullable的话,单行函数原型如下:
51+ ``` c++
52+ extern "C"
53+ void sum (::openmldb::base::UDFContext* ctx, int64_t input1, bool input1_is_null, int64_t input2, bool input2_is_null, int64_t* output, bool* is_null) {
54+ ```
55+
4756函数声明:
4857* 函数必须用extern "C"来声明
4958
5766 ```
5867- 一次分配空间的最大长度不能超过2M字节
5968
60- ** 注** :
61-
62- - 如果参数声明为nullable的,那么所有参数都是nullable的,每一个输入参数都添加is_null参数
63- - 如果返回值声明为nullable的,那么通过参数来返回,并且添加is_null的参数来表示返回值是否为null
64-
65- 如函数sum有俩个参数,如果参数和返回值设置为nullable的话,单行函数原型如下:
66- ``` c++
67- extern "C"
68- void sum (::openmldb::base::UDFContext* ctx, int64_t input1, bool is_null, int64_t input2, bool is_null, int64_t* output, bool* is_null) {
69- ```
70-
7169#### 单行函数开发
7270
7371单行函数(scalar function)对单行数据进行处理,返回单个值,比如 `abs`, `sin`, `cos`, `date`, `year` 等。
@@ -95,6 +93,8 @@ void cut2(::openmldb::base::UDFContext* ctx, ::openmldb::base::StringRef* input,
9593}
9694```
9795
96+ 因为返回值是string类型,所以此处需要通过函数最后一个参数返回。如果返回值是基本类型,通过函数返回值返回,可参考[ test_udf.cc] ( https://github.com/4paradigm/OpenMLDB/blob/main/src/examples/test_udf.cc ) 中的strlength。
97+
9898#### 聚合函数开发
9999
100100聚合函数(aggregate function)对一个数据集(比如一列数据)执行计算,返回单个值,比如 ` sum ` , ` avg ` , ` max ` , ` min ` , ` count ` 等。
@@ -141,9 +141,75 @@ int64_t special_sum_output(::openmldb::base::UDFContext* ctx) {
141141 return * (reinterpret_cast<int64_t* >(ctx->ptr)) + 5;
142142}
143143
144+ // Get the third non-null value of all values
145+ extern "C"
146+ ::openmldb::base::UDFContext* third_init(::openmldb::base::UDFContext* ctx) {
147+ ctx->ptr = reinterpret_cast<void* >(new std::vector<int64_t>());
148+ return ctx;
149+ }
150+
151+ extern "C"
152+ ::openmldb::base::UDFContext* third_update(::openmldb::base::UDFContext* ctx, int64_t input, bool is_null) {
153+ auto vec = reinterpret_cast< std::vector<int64_t > * >(ctx->ptr);
154+ if (!is_null && vec->size() < 3) {
155+ vec->push_back(input);
156+ }
157+ return ctx;
158+ }
159+
160+ extern "C"
161+ void third_output(::openmldb::base::UDFContext* ctx, int64_t* output, bool* is_null) {
162+ auto vec = reinterpret_cast< std::vector<int64_t > * >(ctx->ptr);
163+ if (vec->size() != 3) {
164+ * is_null = true;
165+ } else {
166+ * is_null = false;
167+ * output = vec->at(2);
168+ }
169+ // free the memory allocated in init function with new/malloc
170+ delete vec;
171+ }
172+
173+ // Get the first non-null value >= threshold
174+ extern "C"
175+ ::openmldb::base::UDFContext* first_ge_init(::openmldb::base::UDFContext* ctx) {
176+ // threshold init in update
177+ // threshold, thresh_flag, first_ge, first_ge_flag
178+ ctx->ptr = reinterpret_cast<void* >(new std::vector<int64_t>(4, 0));
179+ return ctx;
180+ }
181+
182+ extern "C"
183+ ::openmldb::base::UDFContext* first_ge_update(::openmldb::base::UDFContext* ctx, int64_t input, bool is_null, int64_t threshold, bool threshold_is_null) {
184+ auto pair = reinterpret_cast< std::vector<int64_t > * >(ctx->ptr);
185+ if (!threshold_is_null && pair->at(1) == 0) {
186+ pair->at(0) = threshold;
187+ pair->at(1) = 1;
188+ }
189+ if (!is_null && pair->at(3) == 0 && input >= pair->at(0)) {
190+ pair->at(2) = input;
191+ pair->at(3) = 1;
192+ }
193+ return ctx;
194+ }
195+
196+ extern "C"
197+ void first_ge_output(::openmldb::base::UDFContext* ctx, int64_t* output, bool* is_null) {
198+ auto pair = reinterpret_cast< std::vector<int64_t > * >(ctx->ptr);
199+ // threshold is null or no value >= threshold
200+ if (pair->at(1) == 0 || pair->at(3) == 0) {
201+ * is_null = true;
202+ } else {
203+ * is_null = false;
204+ * output = pair->at(2);
205+ }
206+ // * is_null = true;
207+ // free the memory allocated in init function with new/malloc
208+ delete pair;
209+ }
144210```
145211
146- 更多udf/udaf实现参考[这里](../../../src/examples/test_udf.cc)。
212+ 如上所示,聚合函数init函数仅单参数,无论是几个参数的聚合函数,init中都只有一个参数UDFContext。update函数参数个数和类型,与聚合函数的参数个数和类型一致。同样的,如果想要聚合函数nullable,每个参数都需要添加一个bool参数,表示该参数是否为null。output函数只会有一个输出参数或返回值,nullable同理。 更多udf/udaf实现参考[这里](../../../src/examples/test_udf.cc)。
147213
148214### 编译动态库
149215- 拷贝include目录 `https://github.com/4paradigm/OpenMLDB/tree/main/include` 到某个路径下,下一步编译会用到。如/work/OpenMLDB/
@@ -185,15 +251,15 @@ g++ -shared -o libtest_udf.so examples/test_udf.cc -I /work/OpenMLDB/include -st
185251### 注册、删除和查看函数
186252注册函数使用[ CREATE FUNCTION] ( ../openmldb_sql/ddl/CREATE_FUNCTION.md )
187253
188- 注册单行函数
254+ 注册单行函数,cut2函数将字符串的前两个字符返回:
189255``` sql
190256CREATE FUNCTION cut2 (x STRING) RETURNS STRING OPTIONS (FILE= ' libtest_udf.so' );
191257```
192- 注册聚合函数
258+ 注册聚合函数,special_sum函数初始为10,再将输入的值累加,并且最后加上5返回(演示函数,无特殊意义):
193259``` sql
194260CREATE AGGREGATE FUNCTION special_sum(x BIGINT ) RETURNS BIGINT OPTIONS (FILE= ' libtest_udf.so' );
195261```
196- 注册聚合函数,并且输入参数和返回值都支持null
262+ 注册聚合函数,并且输入参数和返回值都支持null,third函数返回第三个非null的值,如果非null的值不足3个,返回null:
197263``` sql
198264CREATE AGGREGATE FUNCTION third(x BIGINT ) RETURNS BIGINT OPTIONS (FILE= ' libtest_udf.so' , ARG_NULLABLE= true, RETURN_NULLABLE= true);
199265```
@@ -212,3 +278,9 @@ SHOW FUNCTIONS;
212278```
213279DROP FUNCTION cut2;
214280```
281+
282+ ``` {warning}
283+ 同一个udf so如果注册了多个函数,只删除一个函数时,该so不会从Tablet Server内存中删除。此时替换so文件是无用的,并且如果此时增删udf,有一定危险影响Tablet Server运行。
284+
285+ 建议:**删除所有udf后,替换udf so文件**。
286+ ```
0 commit comments