↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1 / 7.0 / 6.5 / 6.4
历史版本。 PostgreSQL 7.3 已结束支持。 请参阅 当前版本手册.

第 10 章 扩展 SQL:类型

如前所述,PostgreSQL中有两类类型:基本类型(用编程语言定义)和组合类型。本章描述如何定义新的基本类型。

本节中的示例可以在 tutorial 目录下的 complex.sql和complex.c中找到。组合类型的示例在funcs.sql中。

用户定义的类型必须始终具有输入和输出函数。这些函数决定该类型在字符串中如何表示(供用户输入和输出给用户)以及在内存中如何组织。输入函数接受一个以空字符结尾的字符串作为输入,并返回该类型的内部(内存中)表示。输出函数接受该类型的内部表示,并返回一个以空字符结尾的字符串。

假设我们想定义一个表示复数的 complex 类型。很自然,我们会选择用下面的C结构在内存中表示复数:

typedef struct Complex {
    double      x;
    double      y;
} Complex;

并选择形如(x,y)的字符串作为外部字符串表示。

这些函数通常不难编写,输出函数尤其如此。不过,有几点需要记住:

  • 在定义你的外部(字符串)表示时,请记住:你最终必须为该表示编写一个完整而健壮的解析器作为输入函数!

    例如:

    Complex *
    complex_in(char *str)
    {
        double x, y;
        Complex *result;
        if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) {
            elog(ERROR, "complex_in: error in parsing %s", str);
            return NULL;
        }
        result = (Complex *)palloc(sizeof(Complex));
        result->x = x;
        result->y = y;
        return (result);
    }

    输出函数可以简单地写成:

    char *
    complex_out(Complex *complex)
    {
        char *result;
        if (complex == NULL)
            return(NULL);
        result = (char *) palloc(60);
        sprintf(result, "(%g,%g)", complex->x, complex->y);
        return(result);
    }

  • 你应当尽量让输入和输出函数互为逆函数。否则,在你需要把数据转储到文件中再读回来时(比如读到另一台计算机上某人的数据库中),就会出现严重的问题。当涉及浮点数时,这是一个特别常见的问题。

要定义complex类型,我们需要在创建类型之前先创建 complex_in和complex_out 这两个用户定义的函数:

CREATE FUNCTION complex_in(cstring)
    RETURNS complex
    AS 'PGROOT/tutorial/complex'
    LANGUAGE C;

CREATE FUNCTION complex_out(complex)
    RETURNS cstring
    AS 'PGROOT/tutorial/complex'
    LANGUAGE C;

最后,我们可以声明该数据类型:

CREATE TYPE complex (
    internallength = 16,
    input = complex_in,
    output = complex_out
);

注意,输入和输出函数的声明必须引用尚未定义的类型。这是允许的,但会产生一些可以忽略的警告消息。

如前面所讨论的,PostgreSQL完全支持基本类型的数组。此外,PostgreSQL也支持用户定义类型的数组。当你定义一个类型时,PostgreSQL会自动提供对该类型数组的支持。由于历史原因,数组类型的名称与用户定义类型相同,只是在前面加上下划线字符_。

组合类型不需要在其上定义任何函数,因为系统已经知道它们内部是什么样子。

如果你的数据类型的值(内部形式)大小可能超过几百字节,就应当小心地把它们标记为支持 TOAST。为此,内部表示必须遵循变长数据的标准布局:前四个字节必须是一个int32,包含该 datum 的总字节长度(包括其自身)。然后,所有接受该类型值的函数都必须小心地对提供的值调用 pg_detoast_datum()——如果你的函数不是 strict 的,则要在检查该值不为 NULL 之后进行。最后,在给出 CREATE TYPE命令时选择合适的存储选项。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.