要使UDF机制工作,函数必须用C或c++编写,而且操作系统必须支持动态加载。MySQL源发行版包含一个文件sql / udf_example.cc
它定义了五个UDF函数。参考这个文件,了解UDF调用约定是如何工作的。的包括/ mysql_com.h
头文件定义了udf相关的符号和数据结构,尽管你不需要直接包括这个头文件;它包含在mysql.h
.
UDF包含成为正在运行的服务器一部分的代码,因此当您编写UDF时,您将受到应用于编写服务器代码的任何和所有约束的约束。方法中的函数可能会出现问题libstdc + +
图书馆。这些约束在服务器的未来版本中可能会发生变化,因此服务器升级可能需要对最初为旧服务器编写的udf进行修订。有关这些约束的信息,请参见MySQL源配置选项,处理编译MySQL时的问题.
为了能够使用udf,您必须链接mysqld动态。如果您想使用UDF,需要访问符号从mysqld(例如,变音位
函数sql / udf_example.cc
使用default_charset_info
),您必须将该程序与-rdynamic
(见男人dlopen
).
对于希望在SQL语句中使用的每个函数,应该定义相应的C(或c++)函数。在下面的讨论中,名称”xxx”用于示例函数名。为了区分SQL和C/ c++的用法,XXX ()
(大写)表示SQL函数调用,和xxx ()
(小写)表示C/ c++函数调用。
当使用c++时,将你的C函数封装在这个构造中:
extern "C"{…}
这确保了c++函数名在完成的UDF中保持可读。
下面的列表描述了编写这些C/ c++函数来实现名为
XXX ()
.的主要功能,xxx ()
,是必需的。此外,UDF至少需要这里描述的其他函数中的一个,原因在xxx ()
的主要功能。这是计算函数结果的地方。SQL函数数据类型和C/ c++函数的返回类型之间的对应关系显示在这里。
也可以声明一个
小数
函数,但是返回的值是一个字符串,因此您应该将UDF编写成好像它是字符串
函数。行
函数没有实现。xxx_init ()
的初始化函数。
xxx ()
.如果存在,它可以用于以下目的:来检查参数的数量
XXX ()
.验证实参是必需的类型,或者告诉MySQL在调用main函数时强制实参为必需的类型。
分配主函数所需的任何内存。
指定结果的最大长度。
指定(
真正的
函数)的结果中小数点后的最大位数。指定结果是否可以
零
.
xxx_deinit ()
的去初始化函数
xxx ()
.如果存在,它应该释放由初始化函数分配的所有内存。
当SQL语句调用时XXX ()
, MySQL调用初始化函数xxx_init ()
让它执行任何必需的设置,例如参数检查或内存分配。如果xxx_init ()
返回一个错误,MySQL终止SQL语句并返回一个错误消息,并且不调用main函数或去初始化函数。否则,MySQL调用main函数xxx ()
每一行一次。在处理完所有行之后,MySQL调用去初始化函数xxx_deinit ()
这样它就可以执行任何需要的清理。
对于聚合函数,就像SUM ()
,你必须同时提供以下功能:
xxx_clear ()
重置当前聚合值,但不插入参数作为新组的初始聚合值。
xxx_add ()
将参数添加到当前聚合值。
MySQL处理聚合udf的方式如下:
调用
xxx_init ()
让聚合函数分配存储结果所需的任何内存。根据表的
集团
表达式。调用
xxx_clear ()
对于每个新组的第一行。调用
xxx_add ()
对于属于同一组的每一行。调用
xxx ()
在组更改时或在处理最后一行之后获取聚合的结果。重复步骤3至5,直到处理完所有行
调用
xxx_deinit ()
让UDF释放它所分配的所有内存。
所有函数都必须是线程安全的。这不仅包括主函数,还包括初始化和反初始化函数,以及聚合函数所需的附加函数。这一要求的结果是,您不允许分配任何全局或静态变量的变化!如果你需要内存,你必须把它装进去xxx_init ()
把它释放出来xxx_deinit ()
.
本节描述创建简单UDF必须定义的不同函数。有关MySQL调用这些函数的顺序,请参见xxx ()函数的声明应如本节所示。注意,根据是否声明SQL函数,返回类型和参数不同XXX ()
返回字符串
,整数
,或真正的
在创建函数
声明:
为字符串
功能:
char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
为整数
功能:
long long xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);
为真正的
功能:
double xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);
小数
函数返回字符串值,其声明方式与字符串
功能。行
函数没有实现。
像这样声明初始化和去初始化函数:
my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);空白xxx_deinit (UDF_INIT * initid);
的initid
参数传递给所有三个函数。它指向一个UDF_INIT
结构,用于在函数之间通信信息。的UDF_INIT
结构成员。初始化函数应该填充它希望更改的任何成员。(要对成员使用默认值,请保持不变。)
my_bool maybe_null
xxx_init ()
应该设定maybe_null
来1
如果xxx ()
可以返回零
.默认值为1
如果声明了任何参数maybe_null
.unsigned int小数
小数点右边的小数位数。默认值是传递给main函数的参数的最大十进制位数。例如,如果传递了函数
1.34
,1.345
,1.3
,默认值为3,因为1.345
有3位十进制数字。对于没有固定小数数的实参,则
小数
值设置为31,该值比允许的最大小数数多1小数
,浮动
,双
数据类型。这个值可以作为常量使用NOT_FIXED_DEC
在mysql_com.h
头文件。一个
小数
值31用于诸如a浮动
或双
列声明时没有显式小数(例如,浮动
而不是浮动(10,3)
)和浮点常数,如1345 e - 3
.它也用于可能在函数内转换为数字形式的字符串和其他非数字参数。的值
小数
成员是否初始化只是一个默认值。可以在函数内更改它,以反映实际执行的计算。默认情况下,将使用参数的最大小数数。如果小数的个数是NOT_FIXED_DEC
对于其中一个实参,那就是用于的值小数
.unsigned int max_length
结果的最大长度。默认的
max_length
值根据函数的结果类型而不同。对于字符串函数,默认值是最长参数的长度。对于整型函数,默认值是21位。对于实函数,默认值是13加上表示的十进制位数initid - >小数
.(对于数值函数,长度包括任何符号或小数点字符。)如果你想返回一个blob值,你可以设置
max_length
至65KB或16MB。不分配此内存,但是如果需要临时存储数据,则使用该值来决定使用哪种数据类型。char * ptr
一个指针,函数可以使用它自己的目的。例如,函数可以使用
initid - > ptr
在它们之间通信已分配的内存。xxx_init ()
应该分配内存并将其分配给这个指针:initid - > ptr = allocated_memory;
在
xxx ()
而且xxx_deinit ()
,请参考initid - > ptr
使用或释放内存。my_bool const_item
xxx_init ()
应该设定const_item
来1
如果xxx ()
总是返回相同的值和0
否则。
的xxx ()
函数的声明方式应该与非聚合UDF的声明方式相同。看到xxx ()处理完组中的所有行之后,函数。你通常不应该访问它UDF_ARGS
参数,而是返回一个基于内部摘要变量的值。
中的返回值处理xxx ()
应该与处理非聚合UDF的方法相同。看到xxx_reset ()而且xxx_add ()
函数处理他们UDF_ARGS
参数的方法与非聚合udf的函数相同。看到is_null而且错误
所有的呼叫都是一样的吗xxx_reset ()
,xxx_clear ()
,xxx_add ()
而且xxx ()
.你可以用它来记住你得到了一个错误或者是否xxx ()
函数应该返回零
.不应该将字符串存储到*误差
!错误
指向单字节变量,而不是字符串缓冲区。
* is_null
是否为每个组重置(在调用xxx_clear ()
).*误差
永远不会重置。
如果* is_null
或*误差
设置时xxx ()
回报,MySQL的回报零
作为组函数的结果。
的arg游戏
参数指向UDF_ARGS
结构,其成员列在这里:
unsigned int arg_count
参数的数量。如果需要用特定数量的参数调用函数,请在初始化函数中检查此值。例如:
if (args->arg_count != 2) {strcpy(消息,"XXX()需要两个参数");返回1;}
为其他
UDF_ARGS
数组成员值,数组引用是从零开始的。也就是说,使用从0到的索引值引用数组成员参数- > arg_count
−1。enum Item_result * arg_type
一个指向数组的指针,该数组包含每个参数的类型。可能的类型值为
STRING_RESULT
,INT_RESULT
,REAL_RESULT
,DECIMAL_RESULT
.要确保实参是给定类型的,如果不是则返回错误,请检查
arg_type
数组在初始化函数中。例如:if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != INT_RESULT) {strcpy(消息,"XXX()需要一个字符串和一个整数");返回1;}
参数的类型
DECIMAL_RESULT
都作为字符串传递,因此处理它们的方法与STRING_RESULT
值。作为要求函数的参数为特定类型的替代方法,您可以使用初始化函数来设置
arg_type
元素转换为所需的类型。这导致MySQL在每次调用时将参数强制为这些类型xxx ()
.例如,要指定前两个参数应该分别强制为字符串和整数,请执行以下操作xxx_init ()
:参数- > arg_type [0] = STRING_RESULT;参数- > arg_type [1] = INT_RESULT;
精确值的十进制参数,例如
1.3
或小数
的类型传递列值DECIMAL_RESULT
.但是,值是作为字符串传递的。要接收一个数字,使用初始化函数指定实参应该强制为aREAL_RESULT
值:参数- > arg_type [2] = REAL_RESULT;
char * * args
参数- >参数
将有关传递给函数的参数的一般性质的信息传递给初始化函数。对于一个持续的争论我
,参数- >参数[我]
指向实参值。(关于如何正确访问该值,请参阅后面的说明。)对于一个非常数参数,参数- >参数[我]
是0
.常量实参是只使用常量的表达式,例如3.
或4 * 7 - 2
或罪(3.14)
.非常量实参是引用可能在行与行之间变化的值的表达式,例如用非常量实参调用的列名或函数。对于主函数的每次调用,
参数- >参数
包含为当前正在处理的行传递的实际参数。如果参数
我
代表零
,参数- >参数[我]
是空指针(0)。如果参数不是零
,函数可以引用如下:类型的实参
STRING_RESULT
以字符串指针加上长度的形式给出,以支持处理二进制数据或任意长度的数据。字符串内容可用为参数- >参数[我]
弦的长度是参数- >长度(我)
.不要假设字符串是以空结束的。对于类型的实参
INT_RESULT
,你必须投参数- >参数[我]
到一个很久很久
值:长长的int_val;Int_val = *((long long*) args->args[i]);
对于类型的实参
REAL_RESULT
,你必须投参数- >参数[我]
到一个双
值:双real_val;Real_val = *((double*) args->args[i]);
对于类型的实参
DECIMAL_RESULT
,该值作为字符串传递,应该像处理STRING_RESULT
价值。ROW_RESULT
参数不被实现。
无符号长*长度
对于初始化函数,
长度
数组表示每个参数的最大字符串长度。你不应该改变这些。对于主函数的每次调用,长度
包含为当前正在处理的行传递的任何字符串参数的实际长度。对于类型的实参INT_RESULT
或REAL_RESULT
,长度
仍然包含参数的最大长度(与初始化函数一样)。char * maybe_null
对于初始化函数,
maybe_null
Array为每个参数指示参数值是否可能为空(否为0,是为1)。char * *属性
参数- >属性
传递关于UDF参数名称的信息。为参数我
中的字符串形式提供属性名[我]参数- >属性
属性长度是参数- > attribute_lengths[我]
.不要假设字符串是以空结束的。默认情况下,UDF参数的名称是用于指定参数的表达式的文本。对于udf,参数也可以有一个可选参数
[,]
子句,在这种情况下,参数名为alias_name
alias_name
.的属性
因此,每个参数的值取决于是否给出了别名。假设一个UDF
my_udf ()
调用方式如下:SELECT my_udf(expr1, expr2 AS alias1, expr3 alias2);
在这种情况下,
属性
而且attribute_lengths
数组将有这些值:Args ->attributes[0] = "expr1" Args ->attribute_length [0] = 5 Args ->attributes[1] = "alias1" Args ->attribute_length [1] = 6 Args ->attributes[2] = "alias2" Args ->attribute_length [2] = 6
无符号长* attribute_lengths
的
attribute_lengths
数组表示每个参数名的长度。
初始化函数应该返回0
如果没有发生错误,则1
否则。如果发生错误,xxx_init ()
应该将以空结束的错误消息存储在消息
参数。消息返回给客户端。消息缓冲区为MYSQL_ERRMSG_SIZE
字符长。尽量将消息控制在80个字符以内,以适应标准终端屏幕的宽度。
main函数的返回值xxx ()
函数值是,for很久很久
而且双
功能。字符串函数应该返回一个指向结果和集合的指针*长度
返回值的长度(以字节为单位)。例如:
Memcpy (result, "result string", 13);*长度= 13;
MySQL将一个缓冲区传递给xxx ()
函数使用结果
参数。这个缓冲区足够长,可以容纳255个字符,可以是多字节字符。的xxx ()
函数可以将适合的结果存储在这个缓冲区中,在这种情况下,返回值应该是一个指向缓冲区的指针。如果函数将结果存储在不同的缓冲区中,则应该返回指向该缓冲区的指针。
如果你的string函数没有使用提供的缓冲区(例如,如果它需要返回一个长于255个字符的字符串),你必须为你自己的缓冲区分配空间malloc ()
在xxx_init ()
函数或xxx ()
功能和释放它在你xxx_deinit ()
函数。可以将分配的内存存储在ptr
槽的UDF_INIT
供将来重用的结构xxx ()
调用。看到零在主函数中,设置* is_null
来1
:
* is_null = 1;
要在main函数中指示错误返回,请设置*误差
来1
:
*误差= 1;
如果xxx ()
集*误差
来1
对于任意行,函数值为零
语句处理的当前行和任何后续行XXX ()
被调用。(xxx ()
对于后续的行甚至不调用。)
必须在服务器运行的主机上编译和安装实现udf的文件。这里描述了示例UDF文件的过程sql / udf_example.cc
它包含在MySQL源代码发行版中。有关UDF安装的更多信息,请参见安装和卸载自定义函数.
如果将在复制到副本的语句中引用UDF,则必须确保每个副本也有可用的函数。否则,当副本试图调用该函数时,复制会在副本上失败。
的udf_example.cc
File包含以下函数:
metaphon ()
返回字符串参数的变径字符串。这有点像soundex字符串,但更适合于英语。myfunc_double ()
返回参数中字符的ASCII值的和,除以参数长度的和。myfunc_int ()
返回其参数长度的和。序列((const int))
返回从给定数字开始的序列,如果没有给定数字则返回1。查询()
返回主机名的IP地址。reverse_lookup ()
返回IP地址的主机名。该函数可以用该形式的单个字符串参数调用“xxx.xxx.xxx.xxx”
或者四个数字。avgcost ()
返回平均成本。这是一个聚合函数。
在Unix和类Unix系统上,使用以下过程编译用户定义函数:
一个动态加载的文件应该被编译成一个共享库文件,使用如下命令:
GCC -shared -o udf_example。所以udf_example.cc
如果你正在使用海湾合作委员会与CMake(这就是MySQL本身的配置方式),您应该能够创建udf_example.so
用一个更简单的命令:
使udf_example
编译一个包含udf的共享对象后,必须安装它并告知MySQL。编译共享对象udf_example.cc
使用海湾合作委员会直接生成一个名为udf_example.so
.将共享对象复制到服务器的插件目录并命名它udf_example.so
.的值给出该目录plugin_dir
系统变量。
在某些系统上,ldconfig配置动态链接器的程序不识别共享对象,除非其名称以自由
.在这种情况下,您应该将文件重命名为udf_example.so
来libudf_example.so
.
在Windows环境下,编译自定义函数的步骤如下:
获取MySQL源代码发行版。看到如何获取MySQL.
获得CMake构建实用程序(如果需要的话)http://www.cmake.org.(需要版本2.6或更高版本)。
在源树中,查看
sql
文件名的目录udf_example.def
而且udf_example.cc
.将此目录中的两个文件复制到您的工作目录。创建一个CMake
makefile
(CMakeLists.txt
),内容如下:项目(udf_example) # MySQL include目录INCLUDE_DIRECTORIES("c:/ MySQL /include") ADD_DEFINITIONS("-DHAVE_DLOPEN") ADD_LIBRARY(udf_example模块udf_example. txt)TARGET_LINK_LIBRARIES(udf_example wsock32)
创建VC项目和解决方案文件,替换一个合适的
发电机
值:cmake - g”发电机"
调用cmake——帮助显示有效生成器的列表。
创建
udf_example.dll
:devenv udf_example。sln /构建版本
在所有平台上,将共享库文件复制到plugin_dir
目录,通知mysqld用以下语句介绍新函数。每个平台的文件名后缀不同(例如,所以
对于Unix和类Unix系统,. dll
对于Windows),因此调整所以
根据需要为平台添加后缀。
返回STRING SONAME 'udf_example.so';创建函数myfunc_double返回实SONAME 'udf_example.so';创建函数myfunc_int返回整数SONAME 'udf_example.so';创建函数序列返回整数SONAME 'udf_example.so';创建函数查询返回STRING SONAME 'udf_example.so';返回SONAME 'udf_example.so';创建聚合函数avgcost返回真正的SONAME 'udf_example.so';
函数一旦安装,将保持安装状态,直到卸载为止。
要删除函数,使用删除函数
:
下降函数metaphon;下降函数myfunc_double;下降函数myfunc_int;下降函数序列;下降函数查找;下降函数reverse_lookup;下降函数avgcost;
的创建函数
而且删除函数
报表更新mysql.func
作为UDF注册表的系统表。这些陈述要求插入
而且删除
特权,分别为mysql
数据库。
在正常启动顺序中,服务器加载在mysql.func
表格参数启动服务器——skip-grant-tables
选项,在表中注册的udf将不会被加载并且不可用。
MySQL采取了一些措施来防止用户定义函数的滥用。
UDF库文件不能放置在任意目录中。它们必须位于服务器的插件目录中。的值给出该目录plugin_dir
系统变量。
使用创建函数
或删除函数
,你必须有插入
或删除
特权,分别为mysql
数据库。这是必要的,因为这些语句从mysql.func
表格
的符号之外,udf应该至少有一个定义的符号xxx
与主相对应的符号xxx ()
函数。这些辅助符号对应于xxx_init ()
,xxx_deinit ()
,xxx_reset ()
,xxx_clear ()
,xxx_add ()
功能。mysqld还支持一个——allow-suspicious-udfs
选项,该选项控制udf是否只有xxx
符号可以加载。默认情况下,该选项是禁用的,以防止试图从包含合法udf以外的共享库文件加载函数。如果您的旧udf只包含xxx
符号,且不能重新编译以包含辅助符号时,可能需要指定——allow-suspicious-udfs
选择。否则,您应该避免启用它。