您的位置:首页 > 数据库 > MySQL

编写MYSQL插件(UDF)使其实现Split函数

2016-01-19 16:12 495 查看
MYSQL UDF插件好像不能返回结果集

MFC DLL工程, 静态库链接, UNICODE字符编码

新建cpp, 代码如下

#include "stdafx.h"
#include "tokenize.h"
#include "mysql/mysql.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

void UCS2_TO_UTF8(std::string &dst, const std::wstring &src)
{
size_t l, i;

l = src.length();
for (i = 0; i < l; i++)
{
wchar_t t;

t = src[i];
if (t <= 0x7F)
{
dst.push_back(t & 0x7F);
}
else if (t <= 0x7FF)
{
dst.push_back((6 << 5) | (t >> 11));
dst.push_back((2 << 6) | (t & 0x3F));
}
else
{
dst.push_back((14 << 4) | (t >> 12));
dst.push_back((2 << 6)  | ((t >> 6) & 0x3F));
dst.push_back((2 << 6)  | (t & 0x3F));
}
}
return;
}

void UTF8_TO_UCS2(std::wstring &dst, const std::string &src)
{
size_t l, i;

i = 0;
l = src.length();
while (i < l)
{
char t;
long n;

n = 0;
t = src[i];
while (t & 0x80)
{
n++;
t = t << 1;
}
switch (n)
{
case 0:
{
dst.push_back(src[i] & 0x7F);
i += 1;
}
break;
case 2:
{
if (i + 1 >= l)
return;
dst.push_back(((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F));
i += 2;
}
break;
case 3:
{
if (i + 2 >= l)
return;
dst.push_back(((src[i] & 0x1F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F));
i += 3;
}
break;
default:
return;
}
}
return;
}

VOID SplitStringToArray(LPCTSTR lpString, LPCTSTR lpToken, CStringArray &EleList)
{
int nPos = 0;
CString Src(lpString);

while (TRUE)
{
CString szToken = Src.Tokenize(lpToken, nPos);
if (szToken.IsEmpty())
break;
EleList.Add(szToken);
}
}

using namespace std;
#define MAX_RESULT_LENGTH	128
#define UDFAPI extern "C" __declspec(dllexport)

UDFAPI my_bool tokenize_init(UDF_INIT *init, UDF_ARGS *args, char *msg)
{
if ((args->arg_count >= 3)
&& (args->arg_type[0] == STRING_RESULT)
&& (args->arg_type[1] == STRING_RESULT)
&& (args->arg_type[2] == INT_RESULT)
&& (args->lengths[0] > 0)
&& (args->lengths[1] > 0))
{
// 是否会返回null值
init->maybe_null = 1;
// 结果最大多少字节
init->max_length = MAX_RESULT_LENGTH;
return 0;// init ok
}
else
{
lstrcpynA(msg, "Invalid parameter.", MYSQL_ERRMSG_SIZE);
return 1;// init fail
}
}

UDFAPI void tokenize_deinit(UDF_INIT *init)
{

}

// only vaild for string function
UDFAPI char* tokenize(UDF_INIT *init, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
string p0, p1;
long long  p2;

p0.append(args->args[0], args->lengths[0]);
p1.append(args->args[1], args->lengths[1]);
p2 = *(LONGLONG*)args->args[2];
wstring wp0, wp1;
LONG EleIndex = (p2 & 0x7FFFFFFF);
CStringArray SplitResult;

UTF8_TO_UCS2(wp0, p0);
UTF8_TO_UCS2(wp1, p1);
SplitStringToArray(wp0.c_str(), wp1.c_str(), SplitResult);
if (EleIndex < SplitResult.GetCount())
{
string utf8;

UCS2_TO_UTF8(utf8, SplitResult.ElementAt(EleIndex).GetBuffer(0));
lstrcpynA(result, utf8.c_str(), MAX_RESULT_LENGTH);
*length = lstrlenA(result);
return result;
}
else
{
*is_null = 1;
*length = 0;
return NULL;
}
}


注册函数(文件需要放到mysql的lib/plugin目录下)

CREATE FUNCTION tokenize RETURNS STRING SONAME 'xxx.dll';


测试代码

SELECT tokenize("123|1", "|", 0);


删除函数

DROP FUNCTION tokenize;


函数参数说明:

第一个参数: 待处理字符串

第二个参数:分隔符, 支持多个(用MFC的好处)

第三个参数:取结果的第几个

返回值: 分割后的结果, 若无结果(下标越界), 返回NULL

------

配合一个存储过程, 实现类似Split函数, 返回表

DROP PROCEDURE IF EXISTS `split`;

CREATE DEFINER = `root`@`localhost` PROCEDURE `split`(IN `p_text` text,IN `p_delim` text)
BEGIN
DECLARE e VARCHAR(128);
DECLARE i INT DEFAULT(0);
CREATE TEMPORARY TABLE IF NOT EXISTS __split_tmpTable(`element` VARCHAR(128), PRIMARY KEY(`element`));
TRUNCATE __split_tmpTable;

SELECT tokenize(p_text, p_delim, i) INTO e;
SET i = i + 1;
WHILE NOT ISNULL(e) DO
INSERT INTO __split_tmpTable VALUES(e);
SELECT tokenize(p_text, p_delim, i) INTO e;
SET i = i + 1;
END WHILE;
SELECT * FROM __split_tmpTable;
END;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: