#外置UDF
YashanDB支持在PL中调用外部Java方法或者外部C函数,实现数据库中的外置UDF功能。分布式部署中不可使用此功能。
# 环境要求
使用外置UDF(Java)要求数据库服务器已安装JDK(1.8及其以上版本),并配置如下环境变量:
# 如下路径需更换为实际的jdk安装路径
$ export LD_LIBRARY_PATH=/etc/jdk-18.0.2/lib/server:$LD_LIBRARY_PATH
# 创建自定义库
使用外置UDF首先需要将外置UDF所需要的自定义库创建到数据库中。
Java语言的外置UDF,YashanDB支持创建包含自定义Java函数的.class文件或者jar包的自定义库。
C语言的外置UDF,YashanDB支持创建包含C函数的.dll(Windows)和.so(Linux)动态库文件。
YashanDB通过CREATE LIBRARY中的CREATE LIBRARY语句创建自定义库。
创建自定义库时不检查库文件是否存在,在执行外置UDF时才检查并加载库文件。
示例(单机、共享集群部署)
--创建Java语言的自定义库
CREATE OR REPLACE LIBRARY ya_java_lib IS
'/home/yasdb/example/UDFexample.class';
/
UDFexample.class对应UDFexample.java文件内容如下:
package example;
public class UDFexample {
public static String execJdbcexample(int ctrls) {
switch (ctrls) {
case 1:return "Hello";
case 2:return "World";
default:return "!";
}
}
public static void main(String[] args) {
String a = execJdbcexample(1);
}
}
--创建C语言的自定义库
CREATE OR REPLACE LIBRARY ya_c_lib IS
'/home/yasdb/example/libUDFexample.so';
/
libUDFexample.so对应的UDFexample.c文件内容如下:
#include "string.h"
#include "yacli.h"
YacResult udfExample(YacHandle hProc)
{
YacInt32 id;
YacChar buf[1024];
YAC_CALL(yepGetInt32(hProc, 0, &id, NULL));
(YacVoid)snprintf(buf, 1024, "Hello World, id: %d", id);
YAC_CALL(yepReturnString(hProc, buf));
return YAC_SUCCESS;
}
当class文件、jar包、so文件或dll文件内容发生变化时,需重新生成自定义库。
# 定义Java语言的外置UDF
通过创建一个函数,实现对Java语言的外置UDF的定义,语法如下:
其中,为实现向外置UDF传递参数和获得返回值,对函数定义的参数和返回值应与java_method里的参数和返回值一致,此处一致的具体含义为:
- 参数个数及顺序一致。
- 数据类型兼容,即显式地满足YashanDB和java数据类型对应关系,或者通过隐式转换后满足对应关系,对应关系见下面描述。
# LANGUAGE
指定外置UDF所用的语言,这里为JAVA。
# NAME
指定需引用的java函数的函数签名,java_package.java_class部分长度需小于128字节,其格式为:
java_package.java_class.java_method(argu1_datatype,argu2_datatype...) [return return_datatype]
此处引用的java函数必须为static的java方法,且该方法的参数和返回类型必须在如下列示的java数据类型范围内:
- bool:对应YashanDB的BOOLEAN
- byte:对应YashanDB的TINYINT
- char:对应YashanDB的INT(取值范围[0,65535],即0-16位无符号整数)
- short:对应YashanDB的SMALLINT
- int:对应YashanDB的INT
- long:对应YashanDB的BIGINT
- float:对应YashanDB的FLOAT
- double:对应YashanDB的DOUBLE
- string:对应YashanDB的VARCHAR
# library_name
指定已经创建的自定义库名称。
# library_path
方式一:创建function时,指定library为已创建成功的library名称。
方式二:创建function时,指定library为通过执行DBMS_STANDARD.LOADJAVA方法加载的自定义库路径(此方式不建议使用)。
示例(单机、共享集群部署)
-- 方式一
CREATE OR REPLACE FUNCTION udf_func_java(argu INT) RETURN VARCHAR IS
LANGUAGE java
NAME 'example.UDFexample.execJdbcexample(int) return string'
LIBRARY ya_java_lib;
/
-- 方式二
call DBMS_STANDARD.LOADJAVA('/home/yasdb/example/UDFexample.class');
CREATE OR REPLACE FUNCTION udf_func_java(argu INT) RETURN VARCHAR IS
LANGUAGE java
NAME 'example.UDFexample.execJdbcexample(int) return string'
LIBRARY '/home/yasdb/example/UDFexample.class';
/
# 定义C语言的外置UDF
通过创建一个函数,实现对C语言的外置UDF的定义,语法如下:
call_spec::=
# language
指定外置UDF所用的语言,这里为C。
# external
指定为C语言的外置UDF(建议使用LANGUAGE指定外置UDF所使用的语言)。
# name
通过c_string_literal_name指定需引用的C函数的函数名,默认转为全大写,如需保留大小写,请使用双引号包围,如果省略NAME,默认使用外置UDF的名称。
c_string_literal_name需要为合法的标识符,其最大长度为64字节。
# library_name
指定已经创建的自定义库名称。
示例(单机、共享集群部署)
CREATE OR REPLACE FUNCTION udf_func_c(argu INT) RETURN VARCHAR IS
LANGUAGE C
NAME "udfExample"
LIBRARY ya_c_lib;
/
# 编写c语言外置udf指导
C语言外置UDF是调用C语言编写的函数,将C语言文件编译为动态库文件后,在创建为自定义库被数据库调用。
C函数有唯一参数hProc,不可修改其值。通过YashanDB提供的一系列yepGet、yepOutPut、yepReturn接口实现获取入参、设置出参、设置返回值功能。
使用yepGet接口时,需根据入参类型调用相同类型或可以隐式转换类型的yepGet接口。
使用yepOutPut接口时,需根据入参类型调用相同类型的yepOutPut接口。
使用yepReturn接口时,需根据返回值类型调用相同类型或者可以隐式转换类型的yepReturn接口,且自定义函数必须调用yepReturn接口设置返回值。
接口参数id为函数定义的参数序号,起始值为0。
接口参数lenOrInd用于获取入参长度或是否为NULL值,若其值返回YAC_NULL_DATA,则说明入参为NULL,否则返回入参的字节长度。lenOrInd可为NULL。
YashanDB提供给编写C语言动态库的接口如下:
接口名称 | 接口函数声明 | 接口使用说明 |
---|---|---|
yepGetCharsetId | YacResult yepGetCharsetId(YacHandle hProc, YacUint16* charsetId) | 获取数据库的字符集编号,赋值给charsetId。 |
yepGetBool | YacResult yepGetBool(YacHandle hProc, YacInt32 id, YacBool* v, YacInt32* lenOrInd) | 获取第id个BOOLEAN类型入参的值,赋值给v。 |
yepGetInt8 | YacResult yepGetInt8(YacHandle hProc, YacInt32 id, YacInt8* v, YacInt32* lenOrInd) | 获取第id个TINYINT类型入参的值,赋值给v。 |
yepGetInt16 | YacResult yepGetInt16(YacHandle hProc, YacInt32 id, YacInt16* v, YacInt32* lenOrInd) | 获取第id个SMALLINT类型入参的值,赋值给v。 |
yepGetInt32 | YacResult yepGetInt32(YacHandle hProc, YacInt32 id, YacInt32* v, YacInt32* lenOrInd) | 获取第id个INT类型入参的值,赋值给v。 |
yepGetInt64 | YacResult yepGetInt64(YacHandle hProc, YacInt32 id, YacInt64* v, YacInt32* lenOrInd) | 获取第id个BIGINT类型入参的值,赋值给v。 |
yepGetFloat | YacResult yepGetFloat(YacHandle hProc, YacInt32 id, YacFloat* v, YacInt32* lenOrInd) | 获取第id个FLOAT类型入参的值,赋值给v。 |
yepGetDouble | YacResult yepGetDouble(YacHandle hProc, YacInt32 id, YacDouble* v, YacInt32* lenOrInd) | 获取第id个DOUBLE类型入参的值,赋值给v。 |
yepGetNumber | YacResult yepGetNumber(YacHandle hProc, YacInt32 id, YacNumber* v, YacInt32* lenOrInd) | 获取第id个NUMBER类型入参的值,赋值给v。 |
yepGetDate | YacResult yepGetDate(YacHandle hProc, YacInt32 id, YacDate* v, YacInt32* lenOrInd) | 获取第id个DATE类型入参的值,赋值给v。 |
yepGetTimestamp | YacResult yepGetTimestamp(YacHandle hProc, YacInt32 id, YacTimestamp* v, YacInt32* lenOrInd) | 获取第id个TIMESTAMP类型入参的值,赋值给v。 |
yepGetYMInterval | YacResult yepGetYMInterval(YacHandle hProc, YacInt32 id, YacYMInterval* v, YacInt32* lenOrInd) | 获取第id个INTERVAL YEAR TO MONTH类型入参的值,赋值给v。 |
yepGetDSInterval | YacResult yepGetDSInterval(YacHandle hProc, YacInt32 id, YacDSInterval* v, YacInt32* lenOrInd) | 获取第id个INTERVAL DAY TO SECOND类型入参的值,赋值给v。 |
yepGetString | YacResult yepGetString(YacHandle hProc, YacInt32 id, YacChar* str, YacUint32 bufSize, YacInt32* lenOrInd) | 获取第id个字符串类型(CHAR、VARCHAR)入参的值,需要提前分配内存,传入指针str和bufSize。 |
yepGetBytes | YacResult yepGetBytes(YacHandle hProc, YacInt32 id, YacUint8* bytes, YacUint32 bufSize, YacInt32* lenOrInd) | 获取第id个RAW类型入参的值,需要提前分配内存,传入指针bytes和bufSize。 |
yepOutputNull | YacResult yepOutputNull(YacHandle hProc, YacInt32 id) | 将第id个出参设置为NULL。 |
yepOutputBool | YacResult yepOutputBool(YacHandle hProc, YacInt32 id, YacBool v) | 将第id个BOOLEAN类型出参的值设置为v。 |
yepOutputInt8 | YacResult yepOutputInt8(YacHandle hProc, YacInt32 id, YacInt8 v) | 将第id个TINYINT类型出参的值设置为v。 |
yepOutputInt16 | YacResult yepOutputInt16(YacHandle hProc, YacInt32 id, YacInt16 v) | 将第id个SMALLINT类型出参的值设置为v。 |
yepOutputInt32 | YacResult yepOutputInt32(YacHandle hProc, YacInt32 id, YacInt32 v) | 将第id个INT类型出参的值设置为v。 |
yepOutputInt64 | YacResult yepOutputInt64(YacHandle hProc, YacInt32 id, YacInt64 v) | 将第id个BIGINT类型出参的值设置为v。 |
yepOutputFloat | YacResult yepOutputFloat(YacHandle hProc, YacInt32 id, YacFloat v) | 将第id个FLOAT类型出参的值设置为v。 |
yepOutputDouble | YacResult yepOutputDouble(YacHandle hProc, YacInt32 id, YacDouble v) | 将第id个DOUBLE类型出参的值设置为v。 |
yepOutputNumber | YacResult yepOutputNumber(YacHandle hProc, YacInt32 id, YacNumber* v) | 将第id个NUMBER类型出参的值设置为v。 |
yepOutputDate | YacResult yepOutputDate(YacHandle hProc, YacInt32 id, YacDate v) | 将第id个DATE类型出参的值设置为v。 |
yepOutputTimestamp | YacResult yepOutputTimestamp(YacHandle hProc, YacInt32 id, YacTimestamp* v) | 将第id个TIMESTAMP类型出参的值设置为v。 |
yepOutputYMInterval | YacResult yepOutputYMInterval(YacHandle hProc, YacInt32 id, YacYMInterval v) | 将第id个INTERVAL YEAR TO MONTH类型出参的值设置为v。 |
yepOutputDSInterval | YacResult yepOutputDSInterval(YacHandle hProc, YacInt32 id, YacDSInterval v) | 将第id个INTERVAL DAY TO SECOND类型出参的值设置为v。 |
yepOutputString | YacResult yepOutputString(YacHandle hProc, YacInt32 id, YacChar* str) | 将第id个字符串类型(CHAR、VARCHAR)类型出参的值设置为str指向的字符串。 |
yepOutputBytes | YacResult yepOutputBytes(YacHandle hProc, YacInt32 id, YacUint8* bytes, YacUint32 size) | 将第id个RAW类型出参的值设置为bytes指向的字节,大小为size。 |
yepReturnNull | #define yepReturnNull(hProc) yepOutputNull(hProc, YEP_RETURN) | 将返回值设置为NULL。 |
yepReturnBool | #define yepReturnBool(hProc, value) yepOutputBool(hProc, YEP_RETURN, value) | 将返回值设置为BOOLEAN类型,值为value。 |
yepReturnInt8 | #define yepReturnInt8(hProc, value) yepOutputInt8(hProc, YEP_RETURN, value) | 将返回值设置为TINYINT类型,值为value。 |
yepReturnInt16 | #define yepReturnInt16(hProc, value) yepOutputInt16(hProc, YEP_RETURN, value) | 将返回值设置为SMALLINT类型,值为value。 |
yepReturnInt32 | #define yepReturnInt32(hProc, value) yepOutputInt32(hProc, YEP_RETURN, value) | 将返回值设置为INT类型,值为value。 |
yepReturnInt64 | #define yepReturnInt64(hProc, value) yepOutputInt64(hProc, YEP_RETURN, value) | 将返回值设置为BIGINT类型,值为value。 |
yepReturnFloat | #define yepReturnFloat(hProc, value) yepOutputFloat(hProc, YEP_RETURN, value) | 将返回值设置为FLOAT类型,值为value。 |
yepReturnDouble | #define yepReturnDouble(hProc, value) yepOutputDouble(hProc, YEP_RETURN, value) | 将返回值设置为DOUBLE类型,值为value。 |
yepReturnNumber | #define yepReturnNumber(hProc, value) yepOutputNumber(hProc, YEP_RETURN, value) | 将返回值设置为NUMBER类型,值为value。 |
yepReturnDate | #define yepReturnDate(hProc, value) yepOutputDate(hProc, YEP_RETURN, value) | 将返回值设置为DATE类型,值为value。 |
yepReturnTimestamp | #define yepReturnTimestamp(hProc, value) yepOutputTimestamp(hProc, YEP_RETURN, value) | 将返回值设置为TIMESTAMP类型,值为value。 |
yepReturnYMInterval | #define yepReturnYMInterval(hProc, value) yepOutputYMInterval(hProc, YEP_RETURN, value) | 将返回值设置为INTERVAL YEAR TO MONTH类型,值为value。 |
yepReturnDSInterval | #define yepReturnDSInterval(hProc, value) yepOutputDSInterval(hProc, YEP_RETURN, value) | 将返回值设置为INTERVAL DAY TO SECOND类型,值为value。 |
yepReturnString | #define yepReturnString(hProc, value) yepOutputString(hProc, YEP_RETURN, value) | 将返回值设置为VARCHAR类型,值为value指向的字符串。 |
yepReturnBytes | #define yepReturnBytes(hProc, value, size) yepOutputBytes(hProc, YEP_RETURN, value, size) | 将返回值设置为RAW类型,值为bytes指向的字节,大小为size。 |
# 运行外置udf
对于已成功定义的外置UDF,其调用方法与函数一致。
示例(单机、共享集群部署)
SELECT udf_func_java(1) FROM dual;
UDF_FUNC_JAVA(1)
----------------------------------------------------------------
Hello
SELECT udf_func_java(2) FROM dual;
UDF_FUNC_JAVA(2)
----------------------------------------------------------------
World
SELECT udf_func_c(1) FROM dual;
UDF_FUNC_C(1)
----------------------------------------------------------------
Hello World, id: 1
# 删除外置udf
删除定义了某个外置UDF的函数,即实现对这个外置UDF的删除。
# 删除自定义库
确认外置UDF使用的自定义库不再使用时,可对其进行删除,使用DROP_LIBRARY语句删除自定义库。