Golang 编写 MySQL UDF
一、MySQL UDF
这玩意全称 “MySQL user-definable function”, 从名字就可以看出来叫 “用户定义的方法”; 那么 UDF 到底是干啥的呢?
简单一句话说就是说: 你可以自己写点代码处理数据, 然后把这段代码编译成动态链接库(so), 最后在 MySQL 中动态加载后用户就可以用了.
二、解决方案
由于要检查数据库, 但是实际上审查并不会关注每个表甚至数据库细节; 所以想到最简单的方案就是在读取和写入时通过 UDF 定义一个 SM4 的加密算法把数据动态加密和解密, 关于其他细节这里不做详细说明, 本文主要阐述如何用 Go 搓一个简单的 UDF 并使用.
三、UDF 方法
由于 UDF 官方支持是 C/C++, 所以在 Go 中需要使用 CGO; 一个 UDF 实现通常包含两个 func:
1 |
|
其中 xxx_init
用于预检查, xxx
作为真正的逻辑实现; 当 xxx
方法被调用之前会先通过 xxx_init
方法做一次参数、内存分配等预处理.
注意: 从 MySQL 8.0.1 开始 xxx_init
的返回值从 my_bool
变更为 int
, 网上很多代码写 my_bool
的会导致无法通过编译; 具体参考 https://bugs.mysql.com/bug.php?id=85131
四、Go 实现 UDF
知道了方法签名以后, 就不多废话直接上代码实现:
1 |
|
xsm4_enc_init
方法做一下检查, 当前只支持单个字段参数, xsm4_enc
通过开源的 gmsm
库对传入的字段进行简单的 SM4 加密并返回; 在真实环境中需要调用加密机来实现相关加密, 这里只演示直接使用开源库+固定密码.
五、编译并加载
将上面的代码保存为 xsm4_enc.go
, 然后在安装有 MySQL 头文件的的服务器上使用以下命令编译:
1 |
|
如果没问题将会生成一个 xsm4_enc.so
文件, 如果提示 C.xxx
类型没找到等问题说明头文件没有加载, 自行检查或修改 -I/usr/include/mysql
位置.
生成好 so 文件以后将其复制到 MySQL 的插件目录(插件目录可通过 SHOW VARIABLES LIKE 'plugin_dir';
查询到):
1 |
|
最后在 MySQL 中创建 UDF:
1 |
|
六、UDF 使用
使用就简单了, 在查询的时候直接把你的 func 名称写上就行:
1 |
|
同理也可以创建一个解密 UDF, 当然这些 UDF 最终配合视图啥的做啥、怎么用就不做过多赘述了.