MySQL C UDF多行执行结果截断问题求助
解决MySQL C UDF多行执行结果截断问题
你的问题根源在于未在UDF的初始化函数中指定返回字符串的最大长度,MySQL会基于第一行调用时的结果长度分配缓冲区,后续行复用该缓冲区时,长度被限制导致截断。
修复步骤
- 在
int_to_string_init函数中设置initid->max_length,明确返回字符串的最大可能长度。64位有符号long的最大值是9223372036854775807(19位),加上分隔符:,两个数值拼接后的最大长度为19+1+19=39,预留冗余设为40即可。 - 替换
sprintf为snprintf,避免缓冲区溢出风险。
修改后的完整代码
#include <stdio.h> #include <stdlib.h> #include <mysql.h> #include <string.h> my_bool int_to_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message); void int_to_string_deinit(UDF_INIT *initid); char *int_to_string(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error); my_bool int_to_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { if (args->arg_count != 2 || args->arg_type[0] != INT_RESULT || args->arg_type[1] != INT_RESULT) { strcpy(message, "This function takes two long arguments"); return 1; } // 设置返回字符串的最大长度,避免缓冲区不足导致截断 initid->max_length = 40; return 0; } void int_to_string_deinit(UDF_INIT *initid) { } char *int_to_string(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) { long a = *((long *) args->args[0]); long b = *((long *) args->args[1]); // 使用snprintf确保不会溢出缓冲区 int ret = snprintf(result, initid->max_length, "%ld:%ld", a, b); *length = ret > 0 ? ret : 0; return result; }
重新编译与测试
- 重新编译UDF:
gcc -o int_to_string.so -shared int_to_string.c `mysql_config --include` -fPIC
- 重新创建函数(若已存在需先删除):
DROP FUNCTION IF EXISTS int_to_string; CREATE FUNCTION int_to_string RETURNS STRING SONAME 'int_to_string.so';
- 执行多行查询验证:
SELECT int_to_string(21474836474,9134545) UNION ALL SELECT int_to_string(100,8) UNION ALL SELECT int_to_string(100,91)
此时所有行的结果都会完整返回,不会出现截断。
原理说明
MySQL对于字符串型UDF,会根据initid->max_length的值分配足够的缓冲区,供所有行的函数调用复用。如果未设置该值,MySQL会根据第一行调用时返回的*length确定缓冲区大小,后续行的结果若超过这个长度就会被截断。设置max_length后,MySQL会提前分配足够大的缓冲区,确保所有行的结果都能完整存储。
内容的提问来源于stack exchange,提问作者Cihan Uygun
相关产品推荐
相关产品推荐

