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;