3.1.2. 域类型
域是一种用户定义的数据类型,它基于另一种底层类型。根据需要,它可以有约束来限制其有效值为底层类型所允许值的一个子集。如果没有约束,它的行为就和底层类型一样 — 例如,任何适用于底层类型的操作符或函数都对该域类型有效。底层类型可以是任何内建或者用户定义的基础类型、枚举类型、数组类型、组合类型、范围类型或者另一个域。
例如,我们可以在整数之上创建一个域,它只接受正整数:
CREATE DOMAIN posint AS integer CHECK (VALUE > 0); CREATE TABLE mytable (id posint); INSERT INTO mytable VALUES(1); -- works INSERT INTO mytable VALUES(-1); -- fails
当底层类型的一个操作符或函数适用于一个域值时,域会被自动向下造型为底层类型。因此,mytable.id - 1
的结果会被认为是类型integer
而不是posint
。我们可以写成(mytable.id - 1)::posint
来把结果转换回posint
,这会导致域的约束被重新检查。在这种情况下,如果该表达式被应用于一个值为1的id
就会错误。把底层类型的值赋给域类型的一个字段或者变量不需要写显式的造型,但是域的约束将会被检查。
更多信息请参考 CREATE DOMAIN 。
3.1.2.1. 对象标识符类型
对象标识符(OID)被KingbaseES用来在内部作为多个系统表的主键。 类型oid
表示一个 对象标识符。也有多个oid
的别名类型:regproc
、 regprocedure
、regoper
、regoperator
、 regclass
、regtype
、regrole
、 regnamespace
、regconfig
和regdictionary
。 表20-1 显示了一个概览。
oid
类型目前被实现为一个无符号4字节整数。因此, 在大型数据库中它并不足以提供数据库范围内的唯一性, 甚至在一些大型的表中也无法提供表范围内的唯一性。
oid
类型本身除了比较之外只有很少的操作。不过,它可以被造型成整数,并且接着可以使用标准的整数操作符进行操纵(这样做时要注意有符号和无符号之间可能出现的混乱)。
OID的别名类型除了特定的输入和输出例程之外没有别的操作。这些例程可以接受并显示系统对象的符号名,而不是类型oid
使用的原始数字值。别名类型使查找对象的OID值变得简单。例如,要检查与一个表mytable
有关的sys_attribute
行,你可以写:
SELECT * FROM sys_attribute WHERE attrelid = 'mytable'::regclass;
而不是:
SELECT * FROM sys_attribute WHERE attrelid = (SELECT oid FROM sys_class WHERE relname = 'mytable');
虽然从它本身看起来并没有那么糟,它仍然被过度简化了。如果有多个名为mytable
的表存在于不同的模式中,就可能需要一个更复杂的子选择来选择右边的OID。regclass
输入转换器会根据模式路径设置处理表查找,并且因此它会自动地完成这种“右边的事情”。类似地,对于一个数字OID的符号化显示可以很方便地通过将表OID造型成regclass
来实现。
名字 | 引用 | 描述 | 值示例 |
---|---|---|---|
| 任意 | 数字形 式的对象标识符 |
|
|
| 函数名字 |
|
|
| 带 参数类型的函数 |
|
|
| 操作符名字 |
|
|
| 带参 数类型的操作符 |
|
|
| 关系名字 |
|
|
| 数据类型名字 |
|
|
| 角色名 |
|
|
| 名字空间名称 |
|
|
| 文本搜索配置 |
|
|
| 文本搜索字典 |
|
所有用于由名字空间组织的对象的 OID 别名类型都接受模式限定的名字,如果没有被限定的对象在当前搜索路径中无法找到时,将会在输出时显示模式限定的名字。regproc
和regoper
别名类型将只接受唯一的(非重载的)输入名字,因此它们的使用是受限的;对于大多数使用,regprocedure
或regoperator
更合适。对于regoperator
,通过使用NONE
来替代未使用的操作数可以标识一元操作符。
大部分 OID 别名类型的一个附加性质是依赖性的创建。如果这些类型之一的一个常量出现在一个存储的表达式(如一个列默认值表达式或视图)中,它会在被引用的对象上创建一个依赖。例如,如果一个列有一个默认值表达式nextval('my_seq'::regclass)
,KingbaseES会理解该默认值表达式是依赖于序列my_seq
的,在删除该默认值表达式之前系统将不允许删除该序列。regrole
是这个性质的唯一例外。这种类型的常量不允许出现在这类表达式中。
注意
OID别名类型不完全遵循事务隔离规则。规划器也把它们当做简单常量, 这可能会导致次优的规划。
另一种系统中使用的标识符类型是xid
,或者称为事务(简写为xact)标识符。这是系统列xmin
和xmax
使用的数据类型。事务标识符是32位量。
系统使用的第三种标识符类型是cid
,或者称为命令标识符。这是系统列cmin
和cmax
使用的数据类型。命令标识符也是32位量。
系统使用的最后一种标识符类型是tid
,或者称为元组标识符(行标识符)。这是系统列ctid
使用的数据类型。一个元组ID是一个(块号,块内元组索引)对,它标识了行在它的表中的物理位置。
(这些系统列在 系统列 中有进一步的解释)。
3.1.2.2. sys_lsn 类型
sys_lsn
数据类型可以被用来存储 LSN(日志序列号)数据,LSN 是一个指向WAL中的位置的指针。这个类型是XLogRecPtr
的一种表达并且是 KingbaseES的一种内部系统类型。
在内部,一个 LSN 是一个 64 位整数,表示在预写式日志流中的一个字节位置。它被打印成 两个最高 8 位的十六进制数,中间用斜线分隔,例如16/B374D848
。 sys_lsn
类型支持标准的比较操作符,如=
和 >
。两个 LSN 可以用-
操作符做减法, 结果将是分隔两个预写式日志位置的字节数。
3.1.2.3. 伪类型
KingbaseES类型系统包含了一些特殊目的的项,它们被统称为伪类型。一个伪类型不能被用作一个列的数据类型,但是它可以被用来定义一个函数的参数或者结果类型。每一种可用的伪类型都有其可以发挥作用的情况,这些情况的特点是一个函数的行为并不能符合于简单使用或者返回一种特定SQL数据类型的值。下表列出了现有的伪类型。
名字 | 描述 |
---|---|
| 表示一个函数可以接受任意输入数据类型。 |
| 表示一个函数可以接受任 意数据类型(参见 多态类型 )。 |
| 表示一个函数可以接受任意 数组数据类型(参见 多态类型) |
| 表示一个函数可以接受任意非数 组数据类型(参见 多态类型 )。 |
| 表示一个函数可以接受任意枚举数据 类型(参见 多态类型 和 类型 枚举类型 )。 |
| 表示一个函数可以接受任意范围数 据类型(参见 多态类型 和 范围类型 )。 |
| 表示 一个函数接受或者返回一个非空结尾的C字符串。 |
| 表 示一个函数接受或返回一个服务器内部数据类型。 |
| 一个被声明为返回 |
| 一个被声明为返回 |
| 一个被声明为返回 |
| 一个被声明为 返回 |
| 标 识一个接收或者返回一个未指定的行类型的函数。 |
| 一 个被声明为返回 |
| 一个被声明为 返回 |
| 标识一种对事件触发器可用的 DDL 命令的表达。 |
| 表示一个函数不返回值。 |
| 标识一种 还未被解析的类型,例如一个未修饰的字符文本。 |
| 一种已被废弃 的类型名称,以前它用于实现以上的很多种目的。 |
用C编写的函数(不管是内建的还是动态载入的)可以被声明为接受或返回这些为数据类型的任意一种。函数的作者应当保证当一个伪类型被用作一个参数类型时函数的行为是安全的。
用过程语言编写的函数只有在其实现语言允许的情况下才能使用伪类型。目前大部分过程语言都禁止使用伪类型作为一种参数类型,并且只允许使用void
和record
作为结果类型(如果函数被用于一个触发器或者事件触发器, trigger
或者event_trigger
也被允许作为结果类型)。某些过程语言也支持在多态函数中使用类型anyelement
、anyarray
、anynonarray
、anyenum
和anyrange
。
internal
伪类型用于定义只在数据库系统内部调用的函数,这些函数不会被SQL直接调用。如果一个函数拥有至少一个internal
类型的参数,则它不能从SQL中被调用。为了保持这种限制的类型安全性,遵循以下编码规则非常重要:不要创建任何被声明要返回internal
的函数,除非它有至少一个internal
参数。
notes:
对于这种目的,术语“值”包括数组元素,尽管 JSON 的术语有时认为数组元素与对象内的值不同。