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)

相关推荐
身如柳絮随风扬1 分钟前
什么是左匹配规则?
数据库·sql·mysql
jiankeljx24 分钟前
mysql之如何获知版本
数据库·mysql
小李来了!1 小时前
数据库DDL、DML、DQL、DCL详解
数据库·mysql
我科绝伦(Huanhuan Zhou)2 小时前
【生产案例】MySQL InnoDB 数据损坏崩溃修复
数据库·mysql·adb
海棠蚀omo2 小时前
从零敲开 MySQL 的大门:库与表的基础操作实战(保姆级入门指南)
数据库·mysql
廋到被风吹走3 小时前
【MySql】超时问题分析
java·数据库·mysql
y = xⁿ3 小时前
重生之我创作出了小红书:对象存储模块,用户资料模块
后端·mysql·intellij-idea
Y001112363 小时前
Day10-MySQL-事物
数据库·sql·mysql
轩情吖3 小时前
MySQL之用户管理
数据库·c++·后端·mysql·权限管理·用户管理
wenlonglanying3 小时前
mysql之联合索引
数据库·mysql