版权声明: 转载请注明出处!本文采用 知识共享 署名-非商业性使用-禁止演绎 4.0 国际许可协议
前言
一开始接触到UDF是在目前开发的项目中,在项目的存储过程中接触到了这样一条sql语句:
CREATE FUNCTION XXXXX RETURNS INTEGER SONAME "YYYYY.so";
复制
存储过程的名字叫做CreateUDF
,当时看到这条语句很迷惑,根本不知道是做什么用的,只能在项目资源中查找YYYYY.so
这个库文件,结果却什么也没有找到,一番努力之后我断定,项目中调用CreateUDF
之后并没有产生任何效果。
可是什么是UDF呢?既然存储过程的名字是CreateUDF
,那么这条sql语句肯定和UDF有关,于是我开始广泛搜索UDF相关的条目,一开始看得我一头雾水,因为这三个字母组合在一起的意思太多了,根本找不到我想要的解释,最后在角落里发现了一条mysql与UDF相关的条目,这才弄懂什么是UDF。
关于UDF详细的解释和使用方法请参照MYSQL官方文档:Adding a New User-Defined Function
这里只做一个简单的解释:UDF全称是User defined function, 属于mysql的一个拓展接口,一般翻译为用户自定义函数,这个是用来拓展mysql的技术手段。
我们知道mysql本身提供了大量的函数,并且也支持定义函数,为什么我们还需要UDF呢?这主要看到了他的优点:UDF本身的兼容性很好,并且比存储方法具有更高的执行效率,同时支持聚集函数,相比修改原代码增加函数,更加方便简单,但是UDF也处于mysqld的内存空间中,不谨慎的内存使用很容易导致mysql的服务挂掉。
既然明白了什么是UDF,并且知道了它的作用,那么接下来我们写一个小例子测试一下,看看mysql是怎样调用外部函数的。
测试环境
操作系统:Microsoft Windows 7 旗舰版 (64位/Service Pack 1)
开发环境:Microsoft Visual Studio 2008
mysql版本: 5.1.53-community MySQL Community Server (GPL)
一开始本来想在linux测试一下使用.so文件中的函数,但是无奈linux服务器上没有mysql的开发环境,换句话说就是我没有找到mysql/include这个文件夹,只能在windows上测试一下,原理都一样,只不过在windows上就需要把.so文件换成.dll文件罢了。
具体方法
-
新建项目:打开VS2008新建项目,选择“Win32控制台用用程序”,输入项目名称mysql_udf_c++,点击确定进入下一步。
-
继续操作:直接选择下一步。
-
选择程序类型:选择DLL按钮,勾选控项目复选框,点击完成。
-
右键单击项目添加文件:选择C++文件,输入文件名udf_demo,点击添加按钮。
-
右键单击项目选择属性:在常规选项卡中的“附加包含目录”中选择mysql开发目录,也就是包含mysql.h的那个目录,安装mysql的时候会让你选择。
-
设置完成后开始写代码,在文件udf_demo.cpp中输入以下代码:
#include <winsock.h>
#include <mysql.h>
extern "C" {
__declspec(dllexport) long long udf_add(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error)
{
long long a = *((long long *)args->args[0]);
long long b = *((long long *)args->args[1]);
return a + b;
}
__declspec(dllexport) my_bool udf_add_init(UDF_INIT *initid, UDF_ARGS *args,
char *message)
{
return 0;
}
}
复制
-
编译代码生成dll,将mysql_udf_c++.dll放到mysql的扩展目录”bin\plugin”或者系统目录“System32”,只要让mysql.exe能够找到它就可以。
-
使用udf,打开mysql客户端,输入
CREATE FUNCTION udf_add RETURNS INTEGER SONAME "mysql_udf_c++.dll
,创建一个自定义函数,然后输入select udf_add(520, 1314)
,就会得到如图所示的结果。
总结
按照上面的步骤来做,一个简单的udf小例子就实现了,不过我在实现的过程中也遇到了一些问题。
-
想要给mysql使用的函数必须要添加
__declspec(dllexport)
来导出,否则mysql客户端无法找到函数,网上有一些例子是不加这个参数的,但是去掉这个参数无法实现。 -
使用C的方式编译
extern "C" { ... }
也是必须加上的,否则编译出的函数符号前面有其他的标识,导致创建函数的时候找不到,无法创建成功。 -
functionname_init
和functionname_deinit
网上的教程一般说是可选的,但是在我的例子中,如果两个都不写,会编译报错,所以我写了udf_add_init
函数。 -
返回值问题需要注意,这个做加法的函数,在一开始创建的时候我写成了
CREATE FUNCTION udf_add RETURNS STRING SONAME "mysql_udf_c++.dll"
,返回值写成了字符串,结果一运行就崩溃,mysqld直接挂掉了,后来修改后才正常。
附注
mysql udf demo 源码 在此,有兴趣的小伙伴尽管拿去测试!有什么问题可以及时反馈给我哟!