CREATE TYPE

CREATE TYPE-定义新的数据类型

Synopsis

CREATE TYPE name AS
    ( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )

CREATE TYPE name AS ENUM
    ( [ 'label' [, ... ] ] )

CREATE TYPE name AS RANGE (
    SUBTYPE = subtype
    [ , SUBTYPE_OPCLASS = subtype_operator_class ]
    [ , COLLATION = collation ]
    [ , CANONICAL = canonical_function ]
    [ , SUBTYPE_DIFF = subtype_diff_function ]
)

CREATE TYPE name (
    INPUT = input_function,
    OUTPUT = output_function
    [ , RECEIVE = receive_function ]
    [ , SEND = send_function ]
    [ , TYPMOD_IN = type_modifier_input_function ]
    [ , TYPMOD_OUT = type_modifier_output_function ]
    [ , ANALYZE = analyze_function ]
    [ , INTERNALLENGTH = { internallength | VARIABLE } ]
    [ , PASSEDBYVALUE ]
    [ , ALIGNMENT = alignment ]
    [ , STORAGE = storage ]
    [ , LIKE = like_type ]
    [ , CATEGORY = category ]
    [ , PREFERRED = preferred ]
    [ , DEFAULT = default ]
    [ , ELEMENT = element ]
    [ , DELIMITER = delimiter ]
    [ , COLLATABLE = collatable ]
)

CREATE TYPE name

Description

CREATE TYPE注册新的数据类型以在当前数据库中使用。定义类型的用户将成为其所有者。

如果指定了架构名称,则在指定的架构中创建类型。否则,它将在当前架构中创建。类型名称必须不同于同一模式中任何现有类型或域的名称。 (因为表具有关联的数据类型,所以类型名称还必须与同一模式中任何现有表的名称都不同.)

如上面的语法简介所示,CREATE TYPE有五种形式。它们分别创建复合类型枚举类型范围类型基本类型Shell 类型。下面依次讨论其中的前四个。壳类型只是用于稍后定义的类型的占位符;它是通过发出CREATE TYPE且不带参数(类型名称除外)创建的。如这些部分所述,在创建范围类型和基本类型时,需要使用 Shell 类型作为前向引用。

Composite Types

CREATE TYPE的第一种形式创建复合类型。组合类型由属性名称和数据类型的列表指定。如果属性的数据类型是可排序的,则也可以指定该属性的排序规则。复合类型与表的行类型基本相同,但是使用CREATE TYPE避免了在只需要定义类型时创建实际表的必要。独立的复合类型很有用,例如,用作函数的参数或返回类型。

为了能够创建复合类型,您必须对所有属性类型具有USAGE特权。

Enumerated Types

CREATE TYPE的第二种形式创建枚举(枚举)类型,如Section 8.7中所述。枚举类型带有一个带引号的标签列表,每个标签必须小于NAMEDATALEN字节长(标准 PostgreSQL 构建中为 64 字节)。 (可以使用零标签创建枚举类型,但是在使用ALTER TYPE添加至少一个标签之前,不能使用这种类型来保存值。)

Range Types

CREATE TYPE的第三种形式会创建新的范围类型,如Section 8.17中所述。

范围类型的* subtype 可以是具有关联的 b 树运算符类的任何类型(以确定范围类型的值的 Sequences)。通常,子类型的默认 b-tree 运算符类用于确定 Sequences。要使用非默认运算符类,请使用 subtype_opclass 指定其名称。如果子类型是可排序的,并且您要在范围的排序中使用非默认排序规则,请使用 collation *选项指定所需的排序规则。

可选的* canonical 函数必须采用一个已定义范围类型的参数,并返回相同类型的值。适用时,它用于将范围值转换为规范形式。有关更多信息,请参见Section 8.17.8。创建 canonical *函数有点棘手,因为必须先声明它,然后才能声明范围类型。为此,必须首先创建一个 Shell 类型,该 Shell 类型是一个占位符类型,除了名称和所有者外,没有任何属性。这是通过发出命令CREATE TYPE name来完成的,没有附加参数。然后可以使用 shell 类型作为参数和结果声明函数,最后可以使用相同的名称声明范围类型。这将自动用有效的范围类型替换 Shell 类型条目。

可选的* subtype_diff 函数必须将 subtype *类型的两个值用作参数,并返回double precision值,该值表示两个给定值之间的差。虽然这是可选的,但提供此选项可以使 range 类型的列上的 GiST 索引效率更高。有关更多信息,请参见Section 8.17.8

Base Types

CREATE TYPE的第四种形式创建新的基本类型(标量类型)。要创建新的基本类型,您必须是超级用户。 (之所以做出此限制,是因为错误的类型定义可能会使服务器混乱甚至崩溃.)

参数可以以任何 Sequences 出现,不仅是上面显示的 Sequences,而且大多数是可选的。在定义类型之前,您必须注册两个或多个函数(使用CREATE FUNCTION)。支持功能* input_function output_function 是必需的,而功能 receive_function send_function type_modifier_input_function type_modifier_output_function analyze_function *是可选的。通常,这些功能必须使用 C 或其他低级语言进行编码。

  • input_function *将类型的外部文本表示形式转换为为该类型定义的运算符和函数所使用的内部表示形式。 * output_function *执行反向转换。Importing 函数可以声明为采用cstring类型的一个参数,也可以声明为采用cstringoidinteger类型的三个参数。第一个参数是 C 字符串形式的 Importing 文本,第二个参数是类型自己的 OID(数组类型除外,数组类型接收其元素类型的 OID),第三个参数是目标列的typmod(如果知道的话-如果未通过,则将传递 1)。Importing 函数必须返回数据类型本身的值。通常,Importing 函数应声明为 STRICT;如果不是,则在读取 NULLImporting 值时将使用 NULL 第一个参数调用它。在这种情况下,该函数仍必须返回 NULL,除非它引发错误。 (这种情况主要是为了支持域 Importing 函数,可能需要拒绝 NULLImporting.)必须将输出函数声明为采用新数据类型的一个参数。输出函数必须返回类型cstring。不会为 NULL 值调用输出函数。

可选* receive_function 将类型的外部二进制表示形式转换为内部表示形式。如果未提供此功能,则该类型不能参与二进制 Importing。应该选择二进制表示形式,以便便宜地转换为内部形式,同时又具有合理的可移植性。 (例如,标准整数数据类型使用网络字节 Sequences 作为外部二进制表示,而内部表示则以计算机的本机字节 Sequences 表示.)receive 函数应进行适当的检查以确保该值有效。可以将接收函数声明为采用类型internal的一个参数,或者声明为采用类型internaloidinteger的三个参数。第一个参数是指向StringInfo缓冲区的指针,该缓冲区保存接收到的字节字符串。可选参数与文本 Importing 功能相同。接收函数必须返回数据类型本身的值。通常,接收函数应声明为 STRICT;如果不是,则在读取 NULLImporting 值时将使用 NULL 第一个参数调用它。在这种情况下,该函数仍必须返回 NULL,除非它引发错误。 (这种情况主要是为了支持域接收功能,可能需要拒绝 NULLImporting.)类似地,可选 send_function *从内部表示转换为外部二进制表示。如果未提供此功能,则该类型不能参与二进制输出。必须将 send 函数声明为采用新数据类型的一个参数。 send 函数必须返回bytea类型。不会为 NULL 值调用发送函数。

此时,您应该想知道如何在必须创建新类型之前将 Importing 和输出函数声明为具有新类型的结果或参数的情况。答案是,首先应将类型定义为* shell type *,这是一个占位符类型,除了名称和所有者外,没有其他属性。这是通过发出没有附加参数的命令CREATE TYPE name来完成的。然后可以参考 Shell 类型定义 C I/O 功能。最后,具有完整定义的CREATE TYPE将 Shell 条目替换为完整的有效类型定义,此后可以正常使用新类型。

如果类型支持修饰符,则需要可选的* type_modifier_input_function type_modifier_output_function * *,即附加到类型声明的可选约束,例如char(5)numeric(30,2)。 PostgreSQL 允许用户定义的类型将一个或多个简单的常量或标识符用作修饰符。但是,此信息必须能够打包为单个非负整数值,以存储在系统目录中。 * type_modifier_input_function cstring数组的形式传递声明的修饰符。它必须检查值的有效性(如果错误,则抛出错误),如果正确,则返回单个非负integer值,该值将存储为“ typmod”列。如果类型没有 type_modifier_input_function *,则类型修饰符将被拒绝。 * type_modifier_output_function 将内部整数 typmod 值转换回正确的格式以供用户显示。它必须返回一个cstring值,该值是要附加到类型名称后面的确切字符串。例如numeric的函数可能返回(30,2)。允许省略 type_modifier_output_function *,在这种情况下,默认显示格式只是括号内存储的 typmod 整数值。

可选* analyze_function *对数据类型的列执行特定于类型的统计信息收集。默认情况下,如果该类型有默认的 b-tree 运算符类,则ANALYZE将尝试使用该类型的“等于”和“小于”运算符来收集统计信息。对于非标量类型,此行为可能是不合适的,因此可以通过指定自定义分析函数来覆盖它。必须声明分析函数采用internal类型的单个参数,并返回boolean结果。分析功能的详细 API 出现在src/include/commands/vacuum.h中。

虽然新类型的内部表示的详细信息仅由 I/O 函数和您创建的与该类型一起使用的其他函数才知道,但是内部表示的一些属性必须声明给 PostgreSQL。其中最重要的是* internallength 。基本数据类型可以是固定长度的,在这种情况下 internallength 是正整数,也可以是可变长度,可以通过将 internallength *设置为VARIABLE来表示。 (内部,这是通过将typlen设置为-1 来表示的.)所有可变长度类型的内部表示必须以 4 字节整数开头,并给出该类型值的总长度。 (请注意,长度字段通常按照Section 66.2中的说明进行编码;直接访问它是不明智的。)

可选标志PASSEDBYVALUE指示此数据类型的值是通过值而不是通过引用传递的。按值传递的类型必须为固定长度,并且其内部表示形式不能大于Datum类型的大小(某些机器上为 4 个字节,其他机器上为 8 个字节)。

  • alignment *参数指定数据类型所需的存储对齐方式。允许的值等于在 1、2、4 或 8 字节边界上对齐。请注意,可变长度类型必须具有至少 4 的对齐方式,因为它们必须包含int4作为其第一分量。

  • storage *参数允许选择可变长度数据类型的存储策略。 (定长类型只允许使用plain.)plain指定该类型的数据将始终以内联方式存储而不进行压缩。 extended指定系统将首先尝试压缩长数据值,如果该值仍然太长,则会将其移出主表行。 external允许将值移出主表,但系统不会尝试对其进行压缩。 main允许压缩,但不鼓励将值移出主表。 (如果没有其他方法使行适合,则具有此存储策略的数据项可能仍会移出主表,但与extendedexternal项相比,它们将优先保留在主表中.)

plain之外的所有* storage 值都表示该数据类型的函数可以处理已烤*的值,如Section 66.2Section 37.11.1中所述。给定的其他特定值仅确定可烘烤数据类型的列的默认 TOAST 存储策略;用户可以使用ALTER TABLE SET STORAGE为其他列选择其他策略。

  • like_type *参数提供了一种用于指定数据类型的基本表示形式属性的替代方法:从某些现有类型中复制它们。 * internallength passedbyvalue alignment storage *的值是从命名类型中复制的。 (虽然通常是不希望的,但可以通过将它们与LIKE子句一起指定来覆盖其中的一些值.)当在一些时尚。

  • category preferred *参数可用于帮助控制在模棱两可的情况下将应用哪种隐式强制转换。每种数据类型均属于以单个 ASCII 字符命名的类别,并且每种类型均为“首选”或不在其类别内。当此规则有助于解决重载的函数或运算符时,解析器将更喜欢强制转换为首选类型(但只能从同一类别中的其他类型)。有关更多详细信息,请参见Chapter 10。对于没有隐式转换为其他类型或从任何其他类型隐式转换的类型,将这些设置保留为默认值就足够了。但是,对于一组具有隐式强制类型转换的相关类型,将它们全部标记为属于一个类别并选择一个或两个“最一般”类型作为该类别中的首选类型通常是有帮助的。 * category *参数在将用户定义的类型添加到现有内置类别(例如数字或字符串类型)时特别有用。但是,也可以创建新的完全由用户定义的类型类别。选择除大写字母以外的任何 ASCII 字符以命名此类。

如果用户希望数据类型的列默认为空值以外的其他值,则可以指定一个默认值。使用DEFAULT关键字指定默认值。 (这种默认值可以由附加到特定列的显式DEFAULT子句覆盖.)

要指示类型是数组,请使用ELEMENT关键字指定数组元素的类型。例如,要定义一个 4 字节整数(int4)的数组,请指定ELEMENT = int4。有关数组类型的更多详细信息显示在下面。

为了指示在此类型的数组的外部表示形式中的值之间使用定界符,可以将* delimiter *设置为特定字符。默认的分隔符是逗号(,)。请注意,分隔符与数组元素类型相关联,而不与数组类型本身相关联。

如果可选的布尔参数* collatable *为 true,则类型的列定义和表达式可以通过使用COLLATE子句来携带排序规则信息。实际使用归类信息取决于在类型上操作的功能的实现。仅通过标记可协作的类型,这不会自动发生。

Array Types

每当创建用户定义的类型时,PostgreSQL 都会自动创建一个关联的数组类型,其名称由元素类型的名称组成,该名称前面带有下划线,并在必要时将其截断以使其长度小于NAMEDATALEN字节。 (如果这样生成的名称与现有类型名称冲突,则重复该过程,直到找到一个非冲突名称为止.)此隐式创建的数组类型为可变长度,并使用内置的 Importing 和输出函数array_inarray_out。数组类型跟踪其元素类型的所有者或架构中的所有更改,如果元素类型为,则将其删除。

您可能会合理地问,如果系统自动生成正确的数组类型,为什么会有ELEMENT选项。使用ELEMENT唯一有用的情况是,当您创建一个固定长度的类型,该类型在内部恰好是由许多相同的东西组成的数组时,除了允许通过下标直接访问这些东西之外,还希望这些东西您计划为整个类型提供的任何操作。例如,类型point仅表示为两个浮点数,可以使用point[0]point[1]对其进行访问。请注意,此功能仅适用于内部格式完全相同的固定长度字段序列的固定长度类型。可下标的可变长度类型必须具有array_inarray_out使用的通用内部表示形式。出于历史原因(即,这显然是错误的,但是更改它为时已晚),固定长度数组类型的下标从零开始,而不是可变长度数组的下标。

Parameters

  • name

    • 要创建的类型的名称(可选的模式限定)。
  • attribute_name

    • 复合类型的属性(列)的名称。
  • data_type

    • 要成为复合类型的列的现有数据类型的名称。
  • collation

    • 与复合类型的列或范围类型关联的现有排序规则的名称。
  • label

    • 字符串 Literals,表示与枚举类型的一个值相关联的文本标签。
  • subtype

    • 范围类型将代表其范围的元素类型的名称。
  • subtype_operator_class

    • 子类型的 b 树运算符类的名称。
  • canonical_function

    • 范围类型的规范化函数的名称。
  • subtype_diff_function

    • 子类型的差异函数的名称。
  • input_function

    • 将数据从类型的外部文本形式转换为内部形式的函数的名称。
  • output_function

    • 将数据从类型的内部形式转换为外部文本形式的函数的名称。
  • receive_function

    • 将数据从类型的外部二进制形式转换为内部形式的函数的名称。
  • send_function

    • 将数据从类型的内部形式转换为其外部二进制形式的函数的名称。
  • type_modifier_input_function

    • 将类型的修饰符数组转换为内部形式的函数的名称。
  • type_modifier_output_function

    • 将类型修饰符的内部形式转换为外部文本形式的函数的名称。
  • analyze_function

    • 对数据类型执行统计分析的函数的名称。
  • internallength

    • 一个数字常量,指定新类型的内部表示形式的长度(以字节为单位)。默认假设是可变长度。
  • alignment

    • 数据类型的存储对齐要求。如果指定,则必须为charint2int4double;默认值为int4
  • storage

    • 数据类型的存储策略。如果指定,则必须为plainexternalextendedmain;默认值为plain
  • like_type

    • 新类型将具有相同表示形式的现有数据类型的名称。 * internallength passedbyvalue alignment storage *的值是从该类型复制的,除非此CREATE TYPE命令中其他位置的明确说明覆盖了该值。
  • category

    • 此类型的类别代码(单个 ASCII 字符)。 “用户定义的类型”的默认值为'U'。其他标准类别代码可在Table 51.63中找到。您也可以选择其他 ASCII 字符以创建自定义类别。
  • preferred

    • 如果此类型是其类型类别中的首选类型,则为 true,否则为 false。默认为 false。在现有类型类别中创建新的首选类型时要非常小心,因为这可能会导致行为方面的惊人变化。
  • default

    • 数据类型的默认值。如果省略,则默认为 null。
  • element

    • 创建的类型是一个数组;这指定了数组元素的类型。
  • delimiter

    • 在此类型的数组中的值之间使用定界符。
  • collatable

    • 如果此类型的操作可以使用排序规则信息,则为 true。默认为 false。

Notes

因为一旦创建数据类型就没有使用限制,所以创建基本类型或范围类型无异于授予对类型定义中提到的函数的公共执行权限。对于类型定义中有用的各种函数来说,这通常不是问题。但是在设计一种类型时,您可能需要三思而后行,这种方式要求在将其转换为外部形式或从外部形式转换时使用“Secret”信息。

在 PostgreSQL 8.3 之前的版本中,生成的数组类型的名称始终与元素类型的名称完全相同,并带有一个下划线字符(_)。 (因此,类型名称的长度不得超过其他名称一个字符.)虽然通常仍是这种情况,但在最大长度名称或与以下划线开头的用户类型名称冲突的情况下,数组类型名称可能与此有所不同。 。因此,不赞成依赖此约定编写代码。而是使用pg_typetyparray查找与给定类型关联的数组类型。

建议避免使用下划线开头的类型和表名。尽管服务器将更改生成的数组类型名称以避免与用户提供的名称冲突,但是仍然存在混淆的风险,特别是对于旧的 Client 端软件,后者可能会假定下划线开头的类型名称始终代表数组。

在 PostgreSQL 8.2 版之前,shell 类型创建语法CREATE TYPE name不存在。创建新基本类型的方法是先创建其 Importing 函数。通过这种方法,PostgreSQL 首先会看到新数据类型的名称作为 Importing 函数的返回类型。在这种情况下将隐式创建 shell 类型,然后可以在其余 I/O 函数的定义中引用它。该方法仍然有效,但已被弃用,并且在将来的某些发行版中可能不允许使用。另外,为避免由于函数定义中的简单拼写错误而导致 shell 类型的目录混乱,仅当 Importing 函数用 C 编写时,才通过这种方式创建 shell 类型。

在 7.3 之前的 PostgreSQL 版本中,习惯上完全避免创建 Shell 类型,方法是使用占位符伪类型opaque替换函数对类型名称的前向引用。在 7.3 之前,还必须将cstring参数和结果声明为opaque。为了支持加载旧的转储文件,CREATE TYPE将接受使用opaque声明的 I/O 函数,但它将发出通知并更改函数声明以使用正确的类型。

Examples

本示例创建一个复合类型并将其用于函数定义中:

CREATE TYPE compfoo AS (f1 int, f2 text);

CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
    SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;

本示例创建一个枚举类型并在表定义中使用它:

CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');

CREATE TABLE bug (
    id serial,
    description text,
    status bug_status
);

本示例创建一个范围类型:

CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);

本示例创建基础数据类型box,然后在表定义中使用该类型:

CREATE TYPE box;

CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;
CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = my_box_in_function,
    OUTPUT = my_box_out_function
);

CREATE TABLE myboxes (
    id integer,
    description box
);

如果box的内部结构是由四个float4元素组成的数组,则可以改用:

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = my_box_in_function,
    OUTPUT = my_box_out_function,
    ELEMENT = float4
);

这将允许通过下标访问框值的组件号。否则类型的行为与以前相同。

本示例创建一个大型对象类型,并在表定义中使用它:

CREATE TYPE bigobj (
    INPUT = lo_filein, OUTPUT = lo_fileout,
    INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
    id integer,
    obj bigobj
);

Section 37.11中提供了更多示例,包括合适的 Importing 和输出功能。

Compatibility

CREATE TYPE命令的第一种形式(创建复合类型)符合 SQL 标准。其他形式是 PostgreSQL 扩展。 SQL 标准中的CREATE TYPE语句还定义了 PostgreSQL 中未实现的其他形式。

创建具有零属性的复合类型的能力是 PostgreSQL 特定于标准的偏差(类似于CREATE TABLE中的相同情况)。

See Also

ALTER TYPE, CREATE DOMAIN, CREATE FUNCTION, DROP TYPE