postgresql Postgres的自定义用户定义类型不适用于可变长度文本

yhxst69z  于 2023-05-17  发布在  PostgreSQL
关注(0)|答案(1)|浏览(145)

概述

我尝试使用C为postgres创建一个简单的自定义用户定义类型;但是,每当我使用自定义类型查询表时,数据似乎被截断(或者存在对齐问题)。我相信我在处理输入的变量性质时做错了什么。

下面是我的代码:

PG_FUNCTION_INFO_V1(hierarchy_in);
PG_FUNCTION_INFO_V1(hierarchy_out);

typedef struct Hierarchy
{
    int32 length;
    char path[FLEXIBLE_ARRAY_MEMBER];
} Hierarchy;

Datum
hierarchy_in(PG_FUNCTION_ARGS)
{
    char *input_str = PG_GETARG_CSTRING(0);
    int32 input_len = strlen(input_str);
    Hierarchy *result;

    result = (Hierarchy *)palloc(VARHDRSZ + input_len);
    SET_VARSIZE(result, VARHDRSZ + input_len);
    strncpy(result->path, input_str, input_len);

    PG_RETURN_POINTER(result);
}

Datum
hierarchy_out(PG_FUNCTION_ARGS)
{
    Hierarchy *input = (Hierarchy *)PG_GETARG_POINTER(0);
    char *result;
    int32 input_len = VARSIZE(input) - VARHDRSZ;

    result = pnstrdup(input->path, input_len);

    PG_RETURN_CSTRING(result);
}

下面是我的测试用例:

DROP TABLE TESTING;
DROP EXTENSION hierarchy CASCADE;

CREATE EXTENSION hierarchy;

CREATE TABLE TESTING (
    id SERIAL PRIMARY KEY,
    position hierarchy 
);

INSERT INTO TESTING (position) VALUES ('0123456789');
INSERT INTO TESTING (position) VALUES ('Hello World');

SELECT * FROM TESTING;

输出如下:

vuktfyat

vuktfyat1#

这就像你的字符串的空终止丢失了。
虽然这样可以工作,但在开始时仍然会有缺失的字符。
由于PostgreSQL data type期望第一个字节存储可变长度数据的长度,因此代码需要为:

typedef struct Hierarchy
{
    int32 length;
    char path[FLEXIBLE_ARRAY_MEMBER];
} Hierarchy;

Datum
hierarchy_in(PG_FUNCTION_ARGS)
{
    char *input_str = PG_GETARG_CSTRING(0);
    int32 input_len = strlen(input_str);
    Hierarchy *result;

    result = (Hierarchy *)palloc(VARHDRSZ + sizeof(int32) + input_len); // Allocate space for length field
    SET_VARSIZE(result, VARHDRSZ + sizeof(int32) + input_len);
    result->length = input_len;
    memcpy(result->path, input_str, input_len); // Use memcpy without copying the null-terminator

    PG_RETURN_POINTER(result);
}

Datum
hierarchy_out(PG_FUNCTION_ARGS)
{
    Hierarchy *input = (Hierarchy *)PG_GETARG_POINTER(0);
    char *result;
    int32 input_len = input->length;

    result = (char *)palloc(input_len + 1); // Allocate memory for the string plus the null-terminator
    memcpy(result, input->path, input_len); // Copy the data without the null-terminator
    result[input_len] = '\0'; // Manually add the null-terminator

    PG_RETURN_CSTRING(result);
}

从“User-Defined Types”开始,PostgreSQL提供的VARSIZESET_VARSIZE宏用于处理头部分。
hierarchy_in()函数已经读取了没有空终止符的输入字符串,将字符串的长度存储在Hierarchy结构体的length字段中,并使用memcpy将没有空终止符的输入字符串复制到result->path
但是,hierarchy_out()函数会从提取的数据创建一个新的以null结尾的C字符串,并将其作为C字符串返回。
这应该可以让你打印出C-String,包括所有预期的字符。

相关问题