首页 > 解决方案 > 如何使用数组编写 Postgres 用户定义类型

问题描述

我在 Postgres 中编写了一个名为 personname 的用户定义类型:

#define FLXIBLE_ARRAY_MEMBER 0

PG_MODULE_MAGIC;

typedef struct personname{
    int familyLen;
    int givenLen;
    int givenStart;
    char pname[FLXIBLE_ARRAY_MEMBER];
}personname;

我大致这样编写 personname_in 和 personname_out 函数:

PG_FUNCTION_INFO_V1(pname_in);

Datum
pname_in(PG_FUNCTION_ARGS){
    char* str = PG_GETARG_CSTRING(0);
    personname *name;
    ...
    name = (personname*) palloc(sizeof(personname) + strlen(str) + 1);
    name->familyLen = familyNameLen;
    name->givenLen = givenNameLen;
    name->givenStart = givenNameStart;

    strcpy(name->pname, str);

    PG_RETURN_POINTER(name);
}

PG_FUNCTION_INFO_V1(pname_out);

Datum
pname_out(PG_FUNCTION_ARGS){
    personname *name = (personname*) PG_GETARG_POINTER(0);

    char* family = getFamily(name);
    char* given = getGiven(name);
    char* nameStr;   
    nameStr = psprintf("%s,%s", family, given);

    pfree(family);
    pfree(given);

    PG_RETURN_CSTRING(nameStr);
}

我的sql是这样的:

CREATE FUNCTION pname_in(cstring)
   RETURNS personname
   AS '_OBJWD_/pname'
   LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION pname_out(personname)
   RETURNS cstring
   AS '_OBJWD_/pname'
   LANGUAGE C IMMUTABLE STRICT;

CREATE TYPE personname (
   internallength = 12,
   input = pname_in,
   output = pname_out
);

现在我的代码可以正确响应select "NAME" :: personname;,并且当我插入和选择时,它可以正确访问除 pname 数组之外的 personname 中的所有参数。

当我输入 select * from users 时,我创建了一个名为 users 的表,其中包含 pname 数组;它显示了这一点:

在此处输入图像描述

但是,当我将 personname_in 和 personname_out 代码复制并粘贴到另一个 c 文件中时,将 palloc 替换为 malloc 并使用来自终端的一些输入字符串对其进行测试,它可以打印正确的 pname 值。

有人可以告诉我我在哪里做错了,或者在 PostgreSQL 中使用数组创建新类型的正确方法是什么?

标签: cpostgresqluser-defined-types

解决方案


CREATE TYPE语句与代码不符,varlena缺少 4 字节标头。

Qoth文档

虽然新类型的内部表示的细节只有 I/O 函数和您创建以使用该类型的其他函数知道,但内部表示的几个属性必须向 PostgreSQL 声明。其中最重要的是internallength. 基本数据类型可以是固定长度的,在这种情况下internallength是一个正整数或可变长度,通过设置internallength来表示VARIABLE。(在内部,这通过设置typlen为 -1 来表示。)所有可变长度类型的内部表示必须以一个 4 字节整数开头,给出该类型值的总长度。(请注意,长度字段通常是编码的,如第 68.2 节所述;直接访问它是不明智的。)

您必须使用

INTERNALLENGTH = VARIABLE

并且结构必须以 4 字节整数开头。

我没有检查其他错误。


推荐阅读