pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
CREATE TYPE — 定义一种新的数据类型
CREATE TYPEnameAS (attribute_namedata_type[, ... ] ) CREATE TYPEname( INPUT =input_function, OUTPUT =output_function[ , RECEIVE =receive_function] [ , SEND =send_function] [ , ANALYZE =analyze_function] [ , INTERNALLENGTH = {internallength| VARIABLE } ] [ , PASSEDBYVALUE ] [ , ALIGNMENT =alignment] [ , STORAGE =storage] [ , DEFAULT =default] [ , ELEMENT =element] [ , DELIMITER =delimiter] )
CREATE TYPE在当前数据库中注册一种新的数据 类型。定义该类型的用户将成为其拥有者。
如果给出了模式名,则该类型会在指定模式中创建;否则会在当前模式中 创建。类型名必须不同于同一模式中任何现有类型或域的名称。(由于表 也具有关联的数据类型,类型名还必须不同于同一模式中任何现有表的名 称。)
第一种形式的CREATE TYPE创建一个复合类型。复合类型由属性名和数据类型的列表指定。它本质上与表的行类型相同,但如果想要的只是定义一种类型,使用CREATE TYPE可以避免创建一个实际的表。独立的复合类型可用作函数的参数类型或返回类型。
第二种形式的CREATE TYPE创建一种新的基础类 型(标量类型)。这些参数可以按任意顺序出现,不必局限于上面展示的顺序,而且大多数 都是可选的。在定义该类型之前,必须先注册两个或更多函数(使用 CREATE FUNCTION)。支持函数 input_function和 output_function是必 需的;receive_function、 send_function和 analyze_function则 是可选的。通常这些函数必须用 C 或其他低级语言编写。
input_function将 类型的外部文本表示转换为该类型的操作符和函数所使用的内部表 示。output_function 执行相反的转换。输入函数可以声明为接受一个cstring 参数,或者接受三个参数,类型分别为cstring、 oid、integer。第一个参数是以 C 字符 串表示的输入文本,第二个参数是该类型自身的 OID(数组类型例外,此 时传入的是其元素类型的 OID),第三个参数是在已知情况下目标列的 typmod(未知则传入 -1)。输入函数必须返回该 数据类型本身的值。输出函数必须声明为接受一个新数据类型参数,并且必须返回cstring类型。
可选的receive_function 把类型的外部二进制表示转换为内部表示。如果未提供此函数,该类型就 不能参与二进制输入。外部二进制表示应选择为既能低成本转换为内部形 式,又具有合理可移植性。(例如,标准整数数据类型把网络字节序用作 外部二进制表示,而内部表示则使用机器的本地字节序。) 接收函数 应进行充分检查以确保值有效。它可以声明为接受一个 internal参数,或者接受三个参数,类型分别为 internal、oid、integer。 第一个参数是指向保存已接收字节串的StringInfo缓冲区 的指针;其余可选参数与文本输入函数相同。接收函数必须返回该数据类 型本身的值。类似地,可选的 send_function把内 部表示转换为外部二进制表示。如果未提供此函数,该类型就不能参与二 进制输出。发送函数必须声明为接受一个新数据类型参数,并且必须返回 bytea类型。
读到这里,你可能会问:既然输入和输出函数必须在新类型创建之前创建, 它们怎么能声明为返回或接受这个新类型呢?答案是,必须先创建输入函 数,然后创建输出函数(以及二进制 I/O 函数,如果需要的话),最后 才创建数据类型。PostgreSQL最初会把新 数据类型的名称看作输入函数的返回类型。它会创建一个“shell” 类型,这实际上只是系统目录中的一个占位条目,并把输入函数的定义链 接到该 shell 类型。类似地,其他函数也会链接到(此时已经存在的) shell 类型。最后,CREATE TYPE用完整的类型定义 替换 shell 条目,之后新类型就可以使用了。
可选的analyze_function 为该数据类型的列执行类型专用的统计信息收集。默认情况下,如果该类 型有默认的 B-树操作符类,ANALYZE将尝试使用 该类型的“equals”和“less-than”操作符收 集统计信息。对于非标量类型,这种行为很可能不合适,因此可以通过指 定自定义分析函数来覆盖。分析函数必须声明为接受一个 internal参数并返回boolean结果。分 析函数的详细 API 见src/include/commands/vacuum.h。
虽然新类型内部表示的细节只有 I/O 函数以及你为该类型编写的其他函 数才知道,但仍有若干内部表示属性必须向 PostgreSQL声明。其中最重要的是 internallength。 基础类型可以是定长的,此时internallength为正整数;也可 以是变长的,此时将internallength设为 VARIABLE。(在内部,这通过把 typlen设为 -1 表示。)所有变长类型的内部表 示都必须以一个 4 字节整数开头,用来给出该类型该值的总长度。
可选标志PASSEDBYVALUE表示该数据类型的值按值 传递,而不是按引用传递。内部表示大于Datum类型大小 (多数机器上为 4 字节,少数为 8 字节)的类型不能按值传递。
alignment参数指定该 数据类型所需的存储对齐方式。允许的值分别对应按 1、2、4 或 8 字节 边界对齐。注意,变长类型的对齐至少必须为 4,因为它们的第一个组成 部分必然是一个int4。
storage参数允许为 变长数据类型选择存储策略。(定长类型只允许 plain。)plain表示该类型 数据始终内联存储且不压缩。extended表示系统 会先尝试压缩较长的数据值,如果仍然过长,就把该值移出主表行。 external允许把值移出主表,但系统不会尝试压缩 它。main允许压缩,但不鼓励把值移出主表。(采 用这种存储策略的数据项在没有其他办法让一行适配时仍可能被移出主 表,但与extended和external 数据项相比,它们会被优先保留在主表中。)
如果用户希望该数据类型列的默认值不是空值,可以指定默认值。用 DEFAULT关键字指定默认值。(该默认值可以被附 加到具体列上的显式DEFAULT子句覆盖。)
若要表明一种类型是数组类型,可用ELEMENT 关键字指定数组元素的类型。例如,要定义由 4 字节整数 (int4)构成的数组,可指定 ELEMENT = int4。更多关于数组类型的细节见下文。
若要指定该类型数组在外部表示中用于分隔各值的分隔符,可把 delimiter设为特定 字符。默认分隔符是逗号(,)。注意,这个分隔 符关联的是数组元素类型,而不是数组类型本身。
每当创建用户定义类型时,PostgreSQL 都会自动创建一个关联的数组类型,其名称由元素类型名前加一个下划线 组成。解析器理解这一命名约定,会把对 foo[] 类型列 的请求转换为对 _foo 类型的请求。这种隐式创建的 数组类型是变长的,并使用内置输入/输出函数 array_in和array_out。
如果系统会自动创建正确的数组类型,你可能会合理地问,为什么还需 要ELEMENT选项。ELEMENT唯一有用的情况是:你正在创建一种定长类型,而它在内部恰好是若干相同元素 组成的数组,并且除了为整个类型提供的操作之外,你还希望允许通过下 标直接访问这些元素。例如,类型name允许按这种方式访问其 组成的char元素。一个二维point类型可以 允许其两个分量数字像point[0]和 point[1]那样被访问。注意,这种机制只适用于内部形 式恰好是一串相同定长字段的定长类型。可用下标访问的变长类型必须采用array_in和array_out使用的通用内部表示。由于历史原因(也就是说这显然 不对,但现在改已经太晚了),定长数组类型的下标从零开始,而变长数 组则从一开始。
name要创建的类型名称(可选地带有模式限定)。
attribute_name复合类型的一个属性(列)的名称。
data_type将成为复合类型一列的现有数据类型名称。
input_function将数据从类型的外部文本形式转换为内部形式的函数名。
output_function将数据从类型的内部形式转换为外部文本形式的函数名。
receive_function将数据从类型的外部二进制形式转换成内部形式的函数名。
send_function将数据从类型的内部形式转换为外部二进制形式的函数名。
analyze_function为该数据类型执行统计分析的函数名。
internallength一个数字常量,用于指定新类型内部表示的字节长度。默认假定它是变 长的。
alignment该数据类型的存储对齐需求。如果被指定,它必须是 char、int2、 int4或者double。默认是 int4。
storage该数据类型的存储策略。如果被指定,必须是 plain、external、 extended或者main。 默认是plain。
default该数据类型的默认值。若省略,默认值为 null。
element正在创建的类型是数组;该参数指定数组元素类型。
delimiter在由该类型构成的数组中各值之间使用的分隔符字符。
用户定义类型的名称不能以下划线字符(_)开头, 而且最长只能是 62 个字符(一般来说是 NAMEDATALEN - 2, 而不是其他名称所允许的 NAMEDATALEN - 1 个字符)。 以下划线开头的类型名保留给内部创建的数组类型名使用。
在PostgreSQL 7.3 以前的版本中,通常完全不创建 shell 类型,而是将函数中对类型名的前向引用替换为占位伪类型 opaque。在 7.3 以前,cstring参数和结果也必须声明为opaque。为了支持载入旧转储文件,CREATE TYPE会接受使用opaque声明的函数,但会发出通知,并修改函数的声明以使用正确的类型。
这个示例创建一种复合类型,并在函数定义中使用它:
CREATE TYPE compfoo AS (f1 int, f2 text);
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;
这个示例创建基础类型box,然后在表定义中使用它:
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
);
这样就能通过下标访问 box 值的各个分量。除此之外,该类型的行为与 前例相同。
这个示例创建一种大对象类型,并在表定义中使用它:
CREATE TYPE bigobj (
INPUT = lo_filein, OUTPUT = lo_fileout,
INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
id integer,
obj bigobj
);
更多示例(包括配套的输入和输出函数)请见第 32.11 节。
这里的CREATE TYPE命令是一个PostgreSQL扩展。SQL标准中也有一个CREATE TYPE语句,但细节上相当不同。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。