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

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;


你可能感兴趣的:(编写MYSQL插件(UDF)使其实现Split函数)