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; } }
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;