我正在尝试使用 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;
就像你的字符串的空终止符丢失了一样。
虽然这可行,但开头仍然会缺少字符。
由于 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 字符串返回。