MySQL UDF通过在返回的字符串后附加垃圾字符来响应

Adi*_*ngh 5 c mysql user-defined-functions

因此,我创建了一个接受2个字符串并将其合并的UDF。

我的UDF:// concat_kv.c

#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

typedef unsigned long ulong;

my_bool concat_kv_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    if(args->arg_count != 2 || args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT) {
        strcpy(message, "concat_kv(): Requires 2 string parameters: Key - Value.");
        return 1;
    }
    return 0;
}

char *concat_kv(UDF_INIT *initid, UDF_ARGS *args, char *result, ulong *length, char *is_null, char *error) {
    char *key = (char*)calloc(strlen(args->args[0]), sizeof(char));
    char *value = (char*)calloc(strlen(args->args[1]), sizeof(char));
    char *res = (char *)calloc(strlen(args->args[0]) + strlen(args->args[1]) + 2, sizeof(char));
    int len = strlen(args->args[0]) + strlen(args->args[1]) + 2;
    key = args->args[0];
    value = args->args[1];
    strcat(res, key);
    strcat(res, " ");
    strcat(res, value);
    res[len-1] = '\0'; // Terminating character...
    return res;
}

void concat_kv_deinit(UDF_INIT *initid) {
}
Run Code Online (Sandbox Code Playgroud)

将该文件编译为:

gcc $(mysql_config --cflags) -shared concat_kv.c -o concat_kv.so  
Run Code Online (Sandbox Code Playgroud)

concat_kv.so文件移到/usr/lib/mysql/plugins/

在mysql中创建的函数为:

CREATE FUNCTION concat_kv RETURNS STRING SONAME 'concat_kv.so';  
Run Code Online (Sandbox Code Playgroud)

然后做:

SELECT concat_kv("Aditya", "Singh") as conc;
Run Code Online (Sandbox Code Playgroud)

预期产量:

| conc |
--------
| "Aditya Singh" |
Run Code Online (Sandbox Code Playgroud)

但是获得意外的输出为:

mysql> SELECT concat_kv("Aditya", "Singh") as conc;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| conc 
|
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Aditya Singh            ?T 
|+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
Run Code Online (Sandbox Code Playgroud)

重复的字符串之后,我得到一些无法打印的内容。一些垃圾值附加在字符串之后。

Ste*_*cht 6

您的concat_kv函数应如下所示:

char *concat_kv(UDF_INIT *initid, UDF_ARGS *args, char *result, ulong *length, char *is_null, char *error) {
    char *key = args->args[0];
    char *value = args->args[1];
    strcpy(result, key);
    strcat(result, " ");
    strcat(result, value);
    *length = strlen(result);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

一些说明:

演示版

在Ubuntu上的MySQL中concat_kv

动态内存分配

如注释中已经指出的,如果超出了预分配缓冲区的大小,则存在缓冲区溢出的危险。

内存泄漏

如果要在concat_kv()中动态分配内存,则会导致内存泄漏,因为每次调用用户定义的函数时都会请求内存,并且不会再释放它。

解决方案是使用concat_kv_init()和concat_kv_deinit()函数,这些函数由MySQL在concat_kv()调用之前和之后直接调用。

这是MySQL文档的引文:

MySQL使用result参数将缓冲区传递给xxx()函数。该缓冲区足够长,可以容纳255个字符,可以是多字节字符。如果适合,xxx()函数可以将结果存储在此缓冲区中,在这种情况下,返回值应该是指向缓冲区的指针。如果函数将结果存储在另一个缓冲区中,则应返回一个指向该缓冲区的指针。

如果您的字符串函数不使用提供的缓冲区(例如,如果它需要返回长度超过255个字符的字符串),则必须在xxx_init()函数或xxx( )函数并在xxx_deinit()函数中将其释放。

参见https://dev.mysql.com/doc/refman/8.0/en/udf-return-values.html

动态内存分配示例

因此,如果我们不能保证结果的大小那么大,那么就需要预先分配缓冲区,我们需要在concat_kv_init()中分配内存,并在concat_kv_deinit()中释放它。

my_bool concat_kv_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    if(args->arg_count != 2 || args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT) {
        strcpy(message, "concat_kv(): Requires 2 string parameters: Key - Value.");
        return 1;
    }
    ulong length = strlen(args->args[0]) + strlen(args->args[1]) + 2;
    initid->ptr = (char *)malloc(length);
    return 0;
}

char *concat_kv(UDF_INIT *initid, UDF_ARGS *args, char *result, ulong *length, char *is_null, char *error) {
    char *key = args->args[0];
    char *value = args->args[1];
    strcpy(initid->ptr, key);
    strcat(initid->ptr, " ");
    strcat(initid->ptr, value);
    *length = strlen(initid->ptr);
    return initid->ptr;
}

void concat_kv_deinit(UDF_INIT *initid) {
    free(initid->ptr);
    initid->ptr = NULL;
}
Run Code Online (Sandbox Code Playgroud)