MySQL UDF 一例

目录

[1. 功能](#1. 功能)

[2. des_encrypt.cc 代码](#2. des_encrypt.cc 代码)

[3. 使用动态库编译](#3. 使用动态库编译)

[4. 复制到 MySQL 插件目录](#4. 复制到 MySQL 插件目录)

[5. 创建函数并调用执行](#5. 创建函数并调用执行)

[6. UDF 的性能](#6. UDF 的性能)


1. 功能

在 MySQL 中实现 DES/ECB/PKCS5Padding 加密算法。

2. des_encrypt.cc 代码

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>
#include <openssl/des.h>
#include <openssl/md5.h>

#ifndef my_bool
#define my_bool unsigned char
#endif

extern "C" {
    my_bool direct_checksum_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
    void direct_checksum_deinit(UDF_INIT *initid);
    char *direct_checksum(UDF_INIT *initid, UDF_ARGS *args, char *result, 
                         unsigned long *length, char *is_null, char *error);
}

my_bool direct_checksum_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    if (args->arg_count != 4) {
        strcpy(message, "需要4个参数: userID, diamondCount, updateTime, key");
        return 1;
    }
    initid->max_length = 32;
    return 0;
}

void direct_checksum_deinit(UDF_INIT *initid) {}

char *direct_checksum(UDF_INIT *initid, UDF_ARGS *args, char *result, 
                     unsigned long *length, char *is_null, char *error) {
    if (!args->args[0] || !args->args[1] || !args->args[2] || !args->args[3]) {
        *is_null = 1;
        return NULL;
    }
    
    // 获取参数
    long long userID = *((long long*)args->args[0]);
    long long diamondCount = *((long long*)args->args[1]);
    long long updateTime = *((long long*)args->args[2]);
    char *key = args->args[3];
    
    // 1. 构建字符串
    char plaintext[256];
    snprintf(plaintext, sizeof(plaintext), "%lld,%lld,%lld", userID, diamondCount, updateTime);
    
    // 2. DES加密
    DES_key_schedule schedule;
    DES_cblock key_block;
    memset(&key_block, 0, sizeof(key_block));
    strncpy((char*)&key_block, key, 8);
    
    DES_set_key_unchecked(&key_block, &schedule);
    
    int text_len = (int)strlen(plaintext);
    int pad_len = 8 - (text_len % 8);
    if (pad_len == 0) pad_len = 8;
    int total_len = text_len + pad_len;
    
    // 分配内存
    unsigned char *padded_input = (unsigned char*)malloc(total_len);
    unsigned char *des_output = (unsigned char*)malloc(total_len);
    
    memcpy(padded_input, plaintext, text_len);
    for (int i = 0; i < pad_len; i++) {
        padded_input[text_len + i] = (unsigned char)pad_len;
    }
    
    // ECB模式加密
    for (int i = 0; i < total_len; i += 8) {
        DES_ecb_encrypt((DES_cblock*)(padded_input + i), 
                       (DES_cblock*)(des_output + i), 
                       &schedule, DES_ENCRYPT);
    }
    
    // 3. 转16进制字符串
    char hex_str[1024];
    for (int i = 0; i < total_len; i++) {
        sprintf(hex_str + i * 2, "%02x", des_output[i]);
    }
    hex_str[total_len * 2] = '\0';
    
    // 4. MD5加密
    MD5_CTX md5_ctx;
    unsigned char md5_digest[16];
    
    MD5_Init(&md5_ctx);
    MD5_Update(&md5_ctx, hex_str, (unsigned long)strlen(hex_str));
    MD5_Final(md5_digest, &md5_ctx);
    
    // 5. 关键:直接写入result缓冲区作为字符串
    for (int i = 0; i < 16; i++) {
        sprintf(result + i * 2, "%02x", md5_digest[i]);
    }
    result[32] = '\0';  // null终止
    
    // 6. 告诉MySQL这是32个字符的字符串
    *length = 32;
    
    // 清理内存
    free(padded_input);
    free(des_output);
    
    return result;
}

3. 使用动态库编译

bash 复制代码
g++ -fPIC -shared -o des_encrypt.so des_encrypt.cc \
    -I/home/mysql/mysql-8.0.22/include \
    -I/usr/include/openssl \
    -L/home/mysql/mysql-8.0.22/lib \
    -Wl,-rpath,/home/mysql/mysql-8.0.22/lib \
    -lmysqlclient -lssl -lcrypto

4. 复制到 MySQL 插件目录

bash 复制代码
cp des_encrypt.so /home/mysql/mysql-8.0.22/lib/plugin/
chmod 755 /home/mysql/mysql-8.0.22/lib/plugin/des_encrypt.so

5. 创建函数并调用执行

sql 复制代码
use test;
create function direct_checksum returns string soname 'des_encrypt.so';
select UserID,DiamCount,UpdateTimeJava,
       cast(direct_checksum(UserID,DiamondCount,UpdateTimeJava, 'gnbihUyr') as char) CheckSum 
  from t1 limit 20;

6. UDF 的性能

  • 接近原生性能:C/C++ 编写的函数直接编译为机器码。
  • 无解释开销:不像存储过程需要 SQL 引擎解释执行。
  • 直接内存访问:可以优化数据处理,避免中间转换。
  • 利用系统特性:可以使用 SIMD(Single Instruction, Multiple Data,单指令多数据)、多线程等底层优化。

在本例环境中,生成 16 万个 checksum 用时不到一秒:163735 rows in set (0.93 sec)

相关推荐
爱学英语的程序员8 小时前
面试官:你了解过哪些数据库?
java·数据库·spring boot·sql·mysql·mybatis
·云扬·9 小时前
MySQL Redo Log落盘机制深度解析
数据库·mysql
码界筑梦坊9 小时前
330-基于Python的社交媒体舆情监控系统
python·mysql·信息可视化·数据分析·django·毕业设计·echarts
千寻技术帮10 小时前
10327_基于SpringBoot的视频剪辑咨询网站
mysql·源码·springboot·代码·视频咨询
洛豳枭薰11 小时前
MySQL 梳理
数据库·mysql
剩下了什么19 小时前
MySQL JSON_SET() 函数
数据库·mysql·json
java搬砖工-苤-初心不变20 小时前
MySQL 主从复制配置完全指南:从原理到实践
数据库·mysql
WangYaolove13141 天前
基于python的在线水果销售系统(源码+文档)
python·mysql·django·毕业设计·源码
霖霖总总1 天前
[小技巧66]当自增主键耗尽:MySQL 主键溢出问题深度解析与雪花算法替代方案
mysql·算法
海奥华21 天前
mysql索引
数据库·mysql