CREATE TYPE typename ( INPUT = input_function, OUTPUT = output_function , INTERNALLENGTH = { internallength | VARIABLE } [ , DEFAULT = default ] [ , ELEMENT = element ] [ , DELIMITER = delimiter ] [ , PASSEDBYVALUE ] [ , ALIGNMENT = alignment ] [ , STORAGE = storage ] ) CREATE TYPE typename AS ( column_name data_type [, ... ] )
将要创建的类型名(可以有大纲修饰).
一个文本串,说明新类型的内部长度.
一个函数的名称,由 CREATE FUNCTION创建, 将数据从外部类型转换成内部类型.
一个函数的名称,由 CREATE FUNCTION创建, 将数据从内部格式转换成适于显示的形式.
被创建的类型是数组;这个声明数组元素的类型.
将用做数组的数据元素之间分隔符的字符.
该类型的缺省值.通常是省略它的,所以缺省是 NULL.
该数据类型的存储对齐要求.如果声明了,必须是 char, int2, int4 或 double; 缺省是 int4.
该数据类型的存储技术.如果声明了,必须是 plain,external, extended,或 main; 缺省是 plain.
复合类型字段的名字。
现存数据类型的名字。
CREATE TYPE 允许用户在PostgreSQL 当前数据库里创建一个新的用户数据类型. 定义该类型的用户成为其所有者.
如果给出大纲名,那么该类型是在指定大纲中创建. 否则它是在当前大纲中创建(在搜索路径前面的那个; 参阅 CURRENT_SCHEMA()). 类型名必需和同一大纲中任何现有的类型或者域不同. (因为表和数据类型有联系,类型名不能和同大纲中的表名字冲突.)
第一种形式的CREATE TYPE创建一种新的基本类型 (标量类型)。 它要求要在定义类型之前先注册两个函数(用 CREATE FUNCTION 命令). 新的基本类型的形式由 input_function决定, 它将该类型的外部形式转换成可以被对该类型操作的操作符和函数识别的形式. 自然, output_function 用做相反用途. 输入函数可以声明为接受一个类型为 c_string 的参数,或者接受三个类型分别为 c_string,OID,int4 的参数. (第一个参数是 C 字串形式的输入文本,第二个是在该类型为数组类型时 其元素的类型,第三个是目标字段的typmod,如果已知的话.) 它应该返回一个该数据类型本身的数值。 输出函数可以声明为接受一个类型为新数据类型的参数, 或者接受两个类型,第二个参数的类型是 OID. (第二个参数也是用于数组类型的数组元素类型.)
这个时候你应该觉得奇怪,就是输入和输出函数怎么可以声明为返回新类型 的结果或者是接受新类型的输入,而且是在新类型创建之前就需要创建它们。 答案是输入函数必须先创建,然后是输出函数,最后是数据类型。 PostgreSQL 将首先把新数据类型的名字看作 输入函数的返回类型。它将创建一个"shell"类型,这个类型只是在 pg_type里面的一个占位符,然后把输入函数定义和这个壳类型 连接起来。类似的是输出函数将连接到(现在已经存在)的壳类型。最后, CREATE TYPE 把这个壳类型替换成完整的类型定义,这样就 可以使用新类型了。
注意: 在 PostgreSQL 版本 7.3 之前, 我们习惯用一个伪类型 OPAQUE 占位符代替函数对类型名的前向 引用来避免创建壳类型。输入的 cstring 和结果在 7.3 之前同 样必须是 OPAQUE。为了支持从旧的转储文件中装载, CREATE TYPE 还将接受声明为使用 opaque 的函数声明, 但是它将发出一条 NOTICE 并且把函数的声明修改成使用正确的类型。
新的基本数据类型可定义成为定长,这时 internallength 是一个正整数,也可以是变长的,通过把 internallength 设置为 VARIABLE 表示.(在内部,这个状态 是通过将typlen设置为 -1 实现的.)所有变长类型的内部形式 都必须以一个整数开头,这个整数给出此类型这个数值的全长.
要表示一个类型是数组,用 ELEMENT 关键字声明数组元素的 类型.比如,要定义一个 4 字节整数("int4")的数组,声明
ELEMENT = int4
有关数组类型的更多细节在下面描述.
要声明用于这种类型数组的外部形式的数值之间的分隔符,可用 delimiter 声明指定分隔符.缺省的分隔符是逗号(','). 请注意分隔符是和数组元素类型相关联,而不是数组类型本身.
如果用户希望字段的数据类型缺省时不是 NULL,而是其它什么东西, 那么你可以声明一个缺省值. 在 DEFAULT 关键字里面声明缺省值. (这样的缺省可以被附着在特定字段上的明确的 DEFAULT 子句覆盖.)
可选的标签 PASSEDBYVALUE 表明该数据类型是通过传值传递的而不是传引用. 请注意你不能对那些内部形式超过 Datum 类型宽度 (大多数机器上是四字节,有少数机器上是八字节.) 的类型进行传值.
alignment 关键字 声明该数据类型要求的对齐存储方式.允许的数值等效于按照 1,2, 4,或者 8 字节边界对齐.请注意变长类型必须有至少 4 字节的对齐, 因为它们必须包含一个 int4 作为它们的第一个成份.
storage 关键字 允许为变长数据类型选择 TOAST 存储方法 (定长类型只允许使用 plain). plain 为该数据类型关闭 TOAST:它将 总是用内联的方式而不是压缩的方式存储. extended 是 TOAST 完全兼容的:系统将首先试图压缩 一个长的数据值,然后如果它仍然太长的话就将它的值移出主表的行. external 允许将值移出主表的行,但系统将不会压缩它. main 允许压缩,但是不赞成把数值移动出主表. (用这种存储方法的数据项可能仍将移动出主表,如果不能放在一行里的话, 但是它们将比 extended 和 external 项更愿意呆在主表里.)
CREATE TYPE 的第二种形式创建一个复合类型。 复合类型是用一个字段名和数据类型的列表来声明的。 它实际上和一个表的行类型相同,但是如果我们只是想定义一个类型, 那么使用 CREATE TYPE 避免了创建一个实际的表。 一个独立的复合类型是很有用的函数返回类型。
在创建用户定义数据类型的时候,PostgreSQL 自动创建一个与之关联的数组类型,其名字由该基本类型的名字前缀一个 下划线组成.分析器理解这个命名传统,并且把对类型为 foo[] 的字段的请求转换成对类型为 _foo 的字段的请求.这个隐含创建的数组类型是变长并且 使用内建的输入和输出函数 array_in 和 array_out.
你很可能会问"如果系统自动制作正确的数组类型,那为什么有个 ELEMENT选项?"使用 ELEMENT 有用的唯一 的场合是在你制作的定长类型碰巧在内部是一个 N 个相同事物的数组, 而你又想允许这 N 个事物可以通过脚标直接关联,以及那些你准备 把该类型当做整体进行的操作.比如,类型 name 就允许其 构成 char 用这种方法关联.一个二维的 point 类型也可以允许其两个构成浮点型按照类似 point[0] 和 point[1] 的方法关联. 请注意这个功能只适用与那些内部形式完全是 N 个相等定长字段的定长类型. 一个可以脚标化的变长类型必须有被 array_in 和 array_out 使用的一般化的 内部表现形式.出于历史原因(也就是说,那些明显错误但补救来得太迟的 问题),定长数组类型的脚标从零开始,而不是象变长类型那样的从一开始.
类型名不能以下划线("_") 开头而且只能有 62 个字符长.(或者通常是 NAMEDATALEN-2, 而不是其它名字那样的可以有 NAMEDATALEN-1 个字符). 以下划线开头的类型名被解析成内部创建的数组类型名.
这个命令创建box数据类型,并且将这种类型用于一个表定义:
CREATE TYPE box (INTERNALLENGTH = 16, INPUT = my_procedure_1, OUTPUT = my_procedure_2); CREATE TABLE myboxes (id INT4, description box);
如果 box 的内部结构是一个四个 float4 的数组,我们可以说
CREATE TYPE box (INTERNALLENGTH = 16, INPUT = my_procedure_1, OUTPUT = my_procedure_2, ELEMENT = float4);
它允许一个 box 的数值成分 float 可以用脚标关联. 否则该类型和前面的行为一样.
这条命令创建一个大对象类型并将其用于一个表定义:
CREATE TYPE bigobj (INPUT = lo_filein, OUTPUT = lo_fileout, INTERNALLENGTH = VARIABLE); CREATE TABLE big_objs (id int4, obj bigobj);
这个例子创建一个复合类型并且在一个表函数定义中使用它:
CREATE TYPE compfoo AS (f1 int, f2 text); CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, fooname FROM foo' LANGUAGE SQL;