0
点赞
收藏
分享

微信扫一扫

MySQL函数开发记录

云卷云舒xj 2022-04-17 阅读 11

MySQL函数开发目录

第一章 MySQL函数开发


MySQL函数开发


前言

随着参加工作的时间日渐增加,本人觉得有必要记录一些开发过程中遇见的问题以及解决方案,以便督促自己持续进步!


一、MySQL基本函数开发

简介:
MySQL普通函数的开发比较容易,简单来说就是将某一段业务中的需求抽象出来然后封装好供开发人员调用。

基础语法:

CREATE FUNCTION 
	function_name(param01 varchar(32), param02 int)
RETURNS varchar(32) CHARSET utf8
	DETERMINISTIC
BEGIN
/*
多行注释示例:
在这创建一个函数名为function_name;入参为param01 和param02;返回值类型为varchar(32) 的函数
*/
	[function_body] -- 函数体-具体的实现逻辑
END

函数开发实例:

CREATE FUNCTION f_nvl(i_type varchar(2) , i_source_field varchar(64))
RETURNS varchar(64) CHARSET utf8
deterministic
begin
/*********************************************************************
* 函数名称:  f_east_nvl
* 功能说明:  空值默认值处理函数
* 返  回  值:  处理过后的值
* 编写日期:  2021/03/21
* 编写说明:  适用Mysql数据库,
* a)当字段为空时根据空值类型返回不同的默认值
* 01-字符类型——默认值设为空
* 02-日期类型——默认值设为99991231
* 03-年月类型——默认值设为999912
* 04-时间类型——默认值设为000000
* 05-数字类型——默认值设为0
* 开发人员: 小马爱祖国
* 修改说明:
*********************************************************************/	
	-- 定义出参
	declare o_value varchar(64);
	-- 判断
	if i_source_field is null || length(i_source_field)=0 then 
		select case 
		when i_type = '01' then ''
		when i_type = '02' then '99991231'
		when i_type = '03' then '999912'
		when i_type = '04' then '000000'
		when i_type = '05' then 0
		end into o_value;
	else 
		set o_value = i_source_field;
	end if;
	-- 返回处理好的值
	return o_value;
	
END

二、MySQL进阶函数(UDF)开发

简介:
1)UDF(user define function) 是MySQL留给用户的扩展接口,相对于上述的普通函数开发回更加复杂,但是能实现的功能同时也会更丰富。
2)MySQL UDF使用c语言开发,在编译之后就能满足需要实现的业务逻辑

2.1 MySQL UDF特性

  • 函数能够返回多种类型(字符串、整形、实数)
  • 可以定义简单函数也可以定义聚合函数
  • 可以定义函数抛出的错误

2.2.1 编写UDF

编写udf可以使用c 也可以使用c++

  1. 如何编写UDF
UDF的API包括
name_init():在执行SQL之前会被调用,主要做一些初始化的工作,比如分配后续用到的内存、初始化变量、检查参数是否合法等。
name_deinit():在执行完SQL后调用,大多用于内存清理等工作。init和deinit这两个函数都是可选的
name(): UDF的主要处理函数,当为单次调用型时,可以处理每一行的数据;当为聚集函数时,则返回Group by后的聚集结果。
name_add(): 在每个分组中每行调用
name_clear():在每个分组之后调用

案例:MySQL实现sm3加密函数

/*
* sm3.c
*/
#include <stdio.h>
#include <memory.h>
#include "sm3.h"
 
/*
* 判断运行环境是否为小端
*/
static const int endianTest = 1;
#define IsLittleEndian() (*(char *)&endianTest == 1)
 
/*
* 向左循环移位
*/
#define LeftRotate(word, bits) ( (word) << (bits) | (word) >> (32 - (bits)) )
 
/*
* 反转四字节整型字节序
*/
unsigned int *ReverseWord(unsigned int *word)
{
	unsigned char *byte, temp;
 
	byte = (unsigned char *)word;
	temp = byte[0];
	byte[0] = byte[3];
	byte[3] = temp;
 
	temp = byte[1];
	byte[1] = byte[2];
	byte[2] = temp;
	return word;
}
 
/*
* T
*/
unsigned int T(int i)
{
	if (i >= 0 && i <= 15)
		return 0x79CC4519;
	else if (i >= 16 && i <= 63)
		return 0x7A879D8A;
	else
		return 0;
}
 
/*
* FF
*/
unsigned int FF(unsigned int X, unsigned int Y, unsigned int Z, int i)
{
	if (i >= 0 && i <= 15)
		return X ^ Y ^ Z;
	else if (i >= 16 && i <= 63)
		return (X & Y) | (X & Z) | (Y & Z);
	else
		return 0;
}
 
/*
* GG
*/
unsigned int GG(unsigned int X, unsigned int Y, unsigned int Z, int i)
{
	if (i >= 0 && i <= 15)
		return X ^ Y ^ Z;
	else if (i >= 16 && i <= 63)
		return (X & Y) | (~X & Z);
	else
		return 0;
}
 
/*
* P0
*/
unsigned int P0(unsigned int X)
{
	return X ^ LeftRotate(X, 9) ^ LeftRotate(X, 17);
}
 
/*
* P1
*/
unsigned int P1(unsigned int X)
{
	return X ^ LeftRotate(X, 15) ^ LeftRotate(X, 23);
}
 
/*
* 初始化函数
*/
void SM3Init(SM3Context *context)
{
	context->intermediateHash[0] = 0x7380166F;
	context->intermediateHash[1] = 0x4914B2B9;
	context->intermediateHash[2] = 0x172442D7;
	context->intermediateHash[3] = 0xDA8A0600;
	context->intermediateHash[4] = 0xA96F30BC;
	context->intermediateHash[5] = 0x163138AA;
	context->intermediateHash[6] = 0xE38DEE4D;
	context->intermediateHash[7] = 0xB0FB0E4E;
}
 
/*
* 处理消息块
*/
void SM3ProcessMessageBlock(SM3Context *context)
{
	int i;
	unsigned int W[68];
	unsigned int W_[64];
	unsigned int A, B, C, D, E, F, G, H, SS1, SS2, TT1, TT2;
 
	/* 消息扩展 */
	for (i = 0; i < 16; i++)
	{
		W[i] = *(unsigned int *)(context->messageBlock + i * 4);
		if (IsLittleEndian())
			ReverseWord(W + i);
		//printf("%d: %x\n", i, W[i]);    
	}
	for (i = 16; i < 68; i++)
	{
		W[i] = P1(W[i - 16] ^ W[i - 9] ^ LeftRotate(W[i - 3], 15))
			^ LeftRotate(W[i - 13], 7)
			^ W[i - 6];
		//printf("%d: %x\n", i, W[i]);    
	}
	for (i = 0; i < 64; i++)
	{
		W_[i] = W[i] ^ W[i + 4];
		//printf("%d: %x\n", i, W_[i]);    
	}
 
	/* 消息压缩 */
	A = context->intermediateHash[0];
	B = context->intermediateHash[1];
	C = context->intermediateHash[2];
	D = context->intermediateHash[3];
	E = context->intermediateHash[4];
	F = context->intermediateHash[5];
	G = context->intermediateHash[6];
	H = context->intermediateHash[7];
	for (i = 0; i < 64; i++)
	{
		SS1 = LeftRotate((LeftRotate(A, 12) + E + LeftRotate(T(i), i)), 7);
		SS2 = SS1 ^ LeftRotate(A, 12);
		TT1 = FF(A, B, C, i) + D + SS2 + W_[i];
		TT2 = GG(E, F, G, i) + H + SS1 + W[i];
		D = C;
		C = LeftRotate(B, 9);
		B = A;
		A = TT1;
		H = G;
		G = LeftRotate(F, 19);
		F = E;
		E = P0(TT2);
	}
	context->intermediateHash[0] ^= A;
	context->intermediateHash[1] ^= B;
	context->intermediateHash[2] ^= C;
	context->intermediateHash[3] ^= D;
	context->intermediateHash[4] ^= E;
	context->intermediateHash[5] ^= F;
	context->intermediateHash[6] ^= G;
	context->intermediateHash[7] ^= H;
}
 
/*
* SM3算法主函数
*/
unsigned char *SM3Calc(const unsigned char *message,
	unsigned int messageLen, unsigned char digest[SM3_HASH_SIZE])
{
	SM3Context context;
	unsigned int i, remainder, bitLen;
 
	/* 初始化上下文 */
	SM3Init(&context);
 
	/* 对前面的消息分组进行处理 */
	for (i = 0; i < messageLen / 64; i++)
	{
		memcpy(context.messageBlock, message + i * 64, 64);
		SM3ProcessMessageBlock(&context);
	}
 
	/* 填充消息分组,并处理 */
	bitLen = messageLen * 8;
	if (IsLittleEndian())
		ReverseWord(&bitLen);
	remainder = messageLen % 64;
	memcpy(context.messageBlock, message + i * 64, remainder);
	context.messageBlock[remainder] = 0x80;
	if (remainder <= 55)
	{
		/* 长度按照大端法占8个字节,该程序只考虑长度在 2**32 - 1(单位:比特)以内的情况,
		* 故将高 4 个字节赋为 0 。*/
		memset(context.messageBlock + remainder + 1, 0, 64 - remainder - 1 - 8 + 4);
		memcpy(context.messageBlock + 64 - 4, &bitLen, 4);
		SM3ProcessMessageBlock(&context);
	}
	else
	{
		memset(context.messageBlock + remainder + 1, 0, 64 - remainder - 1);
		SM3ProcessMessageBlock(&context);
		/* 长度按照大端法占8个字节,该程序只考虑长度在 2**32 - 1(单位:比特)以内的情况,
		* 故将高 4 个字节赋为 0 。*/
		memset(context.messageBlock, 0, 64 - 4);
		memcpy(context.messageBlock + 64 - 4, &bitLen, 4);
		SM3ProcessMessageBlock(&context);
	}
 
	/* 返回结果 */
	if (IsLittleEndian())
	for (i = 0; i < 8; i++)
		ReverseWord(context.intermediateHash + i);
	memcpy(digest, context.intermediateHash, SM3_HASH_SIZE);
 
	return digest;
}



my_bool SM3_init( UDF_INIT *initid, UDF_ARGS *args, char *message )
{
    if ( args->arg_count != 1 )
    {
        strcpy( message, "SM3 need 1 argument." );
        return(1);
    }
	else if( args->arg_count == 1 )
	{
		strcpy( message, "SM3 gain argument." );
		return(0);
	}
    return(0);
}


char *SM3( UDF_INIT *initid __attribute__( (unused) ), UDF_ARGS *args __attribute__( (unused) ),
            char *result, unsigned long *length, char *is_null, char *error __attribute__( (unused) ) )
{
	unsigned char output[32];
	char *str = args->args[0];
	int ilen = strlen(str);
	SM3Calc(str, ilen, output);
	sprintf(result,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", output[0],output[1],output[2],output[3], output[4],output[5],output[6],output[7], output[8],output[9],output[10],output[11], output[12],output[13],output[14],output[15], output[16],output[17],output[18],output[19], output[20],output[21],output[22],output[23], output[24],output[25],output[26],output[27], output[28],output[29],output[30],output[31]);
	*length = strlen( result );	
	return result;
}
/*
* sm3.h
*
* 为使此算法兼容32位、64位下Linux或Windows系统,
* 选择 int 来表示 32 位整数。
* 消息长度最大限定为 2**32 - 1(单位:比特),
* 且为 8 的倍数(消息的最小单元为字节)。
*/
#ifndef _SM3_H_
#define _SM3_H_

/*引入mysql udf需要的包*/
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
/*
* SM3算法产生的哈希值大小(单位:字节)
*/
#define SM3_HASH_SIZE 32 
 
/*
* SM3上下文
*/
typedef struct SM3Context
{
	unsigned int intermediateHash[SM3_HASH_SIZE / 4];
	unsigned char messageBlock[64];
} SM3Context;
 
/*
* SM3计算函数
*/
unsigned char *SM3Calc(const unsigned char *message,
	unsigned int messageLen, unsigned char digest[SM3_HASH_SIZE]);
 
#endif // _SM3_H_

编译以及创建对应的自定义函数

# 编译c程序为mysql对应的.so文件
gcc -fPIC -Wall -O3 -I/usr/include/mysql -shared -o sm3.so sm3.c
# 登录mysql
mysql -u root -h 127.0.0.1 -p
# 查询mysql数据库中的udf
select * from mysql.func;
# 创建mysql自定义函数
CREATE FUNCTION SM3 RETURNS STRING SONAME 'sm3.so';

举报

相关推荐

0 条评论