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

问题描述 投票:0回答:1

概览

我正在尝试使用 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;

这是我的输出:

c postgresql types user-defined-types
1个回答
3
投票

就像你的字符串的空终止符丢失了一样。
虽然这可行,但开头仍然会缺少字符。
由于 PostgreSQL 数据类型 期望第一个字节存储可变长度数据的长度,因此代码需要是:

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提供的

VARSIZE
SET_VARSIZE
宏来处理header部分

hierarchy_in()
函数已经读取了不带空终止符的输入字符串,将字符串的长度存储在
Hierarchy
结构的长度字段中,并使用
memcpy
将不带空终止符的输入字符串复制到
result->path
.

但是,

hierarchy_out()
函数从提取的数据中创建一个新的以 null 结尾的 C 字符串,并将其作为 C 字符串返回。
这应该使您能够打印所述 C 字符串及其所有预期字符。

© www.soinside.com 2019 - 2024. All rights reserved.