打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Mysql UDF

1. 简介

MySQL的UDF(User Defined Function)类似于一种API, 用户根据一定的规范用C/C++(或采用C调用规范的语言)编写一组函数(UDF),然后编译成动态链接库,通过CREATE FUNCTIONDROP FUNCTION语句来加载和卸载UDF。UDF被加载后可以像调用MySQL的内置函数一样来调用它,并且服务器在启动时会自动加载原来存在的UDF。

2. 特性

  • UDF的参数和返回值的类型可以为字符串,整数或实型。
  • UDF分为简单UDF和聚合UDF。
  • 服务器会向UDF提供相应的信息以便UDF检查实参的数量、类型和名称。
  • UDF也可以强制服务器在调用UDF前检查实参类型。
  • UDF可以指明返回值为NULL或发生了错误。

3. CREATE FUNCTION的语法

CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|INTEGER|REAL|DECIMAL} SONAME shared_library_name

function_name 为函数名RETURNS子句表明UDF的返回值类型,目前DECIMALSTRING类型是等价的

shared_library_name是UDF所在的动态链接库的名称(不含路径),该文件需放在可被系统搜索到的目录中。

在MySQL 5.1中,动态链接库需要放在由plugin_dir变量所指定的插件目录中。

4. DROP FUNCTION的语法

DROP FUNCTION function_name

5. 编写UDF

对于每个UDF,需要编写若干相关C/C++函数,下面用XXX()代表在SQL语句中调用UDF,xxx()代表相应的C/C++函数调用,实际使用时,两者应相同。

  • xxx()  ——  必须,主函数,该函数的返回值即为UDF的返回值。返回值类型与SQL数据类型的对应关系如下:
SQL类型 C/C++类型
STRING/DECIMAL  char *
INTEGER  long long
REAL double

  •  xxx_init()  ——  可选,xxx()的初始化函数,它可被用来
    • 检查XXX()的实参个数和类型,或强制由服务器来检查。
    • 为主函数分配内存。
    • 指明UDF返回值的最大长度或精度,以及返回值是否可能为NULL.
  •  xxx_deinit() ——  可选,xxx()的清理函数,用来释放在xxx_init()中分配的内存

对于聚合UDF, 还需要另外两个函数。

  • xxx_clear()  ——  必须(MySQL5.1),重置当前聚合值。
  • xxx_add() ——  必须,将参数加到当前聚合值中去。
  • xxx_reset() —— 必须(MySQL 5.1以下版本),重置当前聚合值,并将参数作为初始聚合值。

所以函数必须是线程安全的。可以参考《MySQL参考手册》第30章第3节以获得更详细的说明。此外,在MySQL源代码包中有编写UDF的示例,位置为sql/udf_example.c.

6. 简单UDF的调用顺序

当SQL语句调用XXX()时,服务器首先调用xxx_init()进行参数检查或内存分配,若xxx_init()出错,则SQL语句被终止,主函数和清理函数将不会被调用。然后,服务器对每一行记录调用一次主函数,最后清理函数xxx_deinit()被调用。

7. 聚合UDF的调用顺序

  1. 调用xxx_init()进行初始化。
  2. 根据GROUP BY表达式对表进行排序。
  3. 对每个新组调用xxx_clear()重置聚合值。
  4. 对组中每一行记录调用xxx_add().
  5. 当该组数据处理完后,调用xxx()计算聚合值.
  6. 重复步骤3-5直到所有数据处理完毕。
  7. 调用xxx_deinit()进行清理。

8. 编译和安装UDF

用类似的命令来编译UDF:

shell> gcc -shared -o udf_example.so udf_example.c

将经过编译得到的动态链接库(.so文件)放到系统可以找到并加载该文件的目录中。然后通过CREATE FUNCTION语句让服务器加载动态链接库中的函数。

9. 示例

udf_test.c

#include <mysql.h>#include <time.h>#include <string.h>
my_bool datetime_now_init(UDF_INIT *initid, UDF_ARGS *args, char *message){if (args->arg_count){strcpy(message, "datetime_now() does not need any argument.");return 1;}return 0;}
char *datetime_now(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args __attribute__((unused)),char *result, unsigned long *length, char *is_null, char *error __attribute__((unused))){const time_t now_time = time(NULL);strftime(result, 255, "%Y/%m/%d %I:%M:%S %p %Z %z", localtime(&now_time));*length = strlen(result);return result;}

编译

shell> gcc -fPIC -Wall -O3 -I/usr/local/mysql/include -shared -o udf_test.so udf_test.c

安装

mysql> CREATE FUNCTION datetime_now RETURNS STRING SONAME 'udf_test.so';Query OK, 0 rows affected (0.00 sec)

使用

mysql> SELECT datetime_now();+----------------------------------+| datetime_now()                   |+----------------------------------+| 2008/06/27 05:27:03 PM CST +0800 |+----------------------------------+1 row in set (0.00 sec)

10. 与存储过程函数的区别

存储过程中的函数是一组SQL语句的集合,其能力受限于SQL的表达能力,它还要受限于MySQL自身的一些限制。它主要用于较高层次的数据处理。

UDF的限制相对来说要小很多,与编写服务器代码时的限制相同,只要符合相应的约定即可。它的定位偏向于底层,主要用于提供一些基础的数据处理功能。另外要注意的是,UDF一旦出错,会导致服务器崩溃!

11. 参考资料

ItemToDoForm
TopicClassification? ItemDone?
ToDoBy? ZhengYi
DueDate? 2008/06/30
Priority Low
Type 其他
Intro 研究如何编写和使用MySQL UDF
Plan 阅读官方文档
ResearchMethod? 阅读官方文档
WorkProducts? 本Wiki和Sample
Summary 实用性不是很大
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
mySql的UDF是什么
MySQL UDF
Hackfing in Mysql5
详详详解MySQL UDF执行命令
通过UDF使mysql主动刷新redis缓存
提权,以MySQL之名_安全教程_脚本之家
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服