CREATE CAST (sourcetype AS targettype) WITH FUNCTION funcname (argtypes) [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (sourcetype AS targettype) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST 定义一个新的转换。一个转换说明如何在两个类型之间进行转换。比如:
SELECT CAST(42 AS text);
通过调用前面声明的一个函数,把整数常量 42 转换成 text 类型,在这个例子里是 text(int4)(如果没有预先定义好合适的转换,那么这个转换将会失败)。
两种类型可以是二进制兼容的,意思是它们之间可以"自由转换"而不用调用任何函数。这就需要两种类型使用同样的内部表现形式。比如,类型 text 和 varchar 是二进制兼容的。
缺省时,只有在明确要求转换的情况下才调用一个转换,也就是一个明确的 CAST(x AS typename) 或 x::typename 构造。
如果转换被标记为 AS ASSIGNMENT ,那么在给目标数据类型的字段赋值的时候,可以隐含调用它。比如,假设 foo.f1 是一个类型为 text 的字段,那么
INSERT INTO foo (f1) VALUES (42);
如果从 integer 类型到 text 类型的转换标记为 AS ASSIGNMENT ,上面的这句就被允许,否则就不允许。通常用术语赋值转换来描述这种转换。
如果转换被标记为 AS IMPLICIT ,那么它就可以在任何环境里调用,不管是赋值还是在表达式的内部。比如,因为 || 接受 text 操作数,
SELECT 'The time is ' || now();
将只有在类型 timestamp 到 text 的转换被标记为 AS IMPLICIT 的时候才允许。否则就必须明确书写转换,比如
SELECT 'The time is ' || CAST(now() AS text);
通常使用术语隐含转换来描述这种类型的转换。
在是否将转换标记为隐含的问题上保守一些是明智的。过于丰富的隐含转换路径会导致 PostgreSQL 选择让人奇怪的命令解析,或者是完全不能解析命令,因为存在多个可能的解析。一条好的拇指定律是,只有在同一个通用类型范畴里面的那些可以保留转换信息的类型之间才标记为可隐含调用转换。比如,从 int2 到 int4 可以合理地标记为隐含转换,但是从 float8 到 int4 也许应该标记为赋值转换。跨类型范畴的转换,比如 text 到 int4 ,最好只能明确地转换。
要想创建一个转换,你必须拥有源或目标数据类型。要创建一个二进制兼容的转换,你必须是超级用户。做这个限制是因为一种有问题的二进制兼容转换可以很容易摧毁服务器。
转换的源数据类型
转换的目标数据类型
用于执行转换的函数。这个函数名可以是用模式名修饰的。如果它没有用模式名修饰,那么该函数将从模式搜索路径中找出来。函数的结果数据类型必须匹配转换的目标类型。它的参数在下面讨论。
表示源数据类型和目标数据类型是二进制兼容的,所以不需要什么函数来执行转换。
表示转换可以在赋值环境里隐含调用
表示转换可以在任何环境里隐含调用
转换实现函数可以有一到三个参数。第一个参数类型必须和转换的源类型相同。如果有第二个参数,那么必须是 integer 类型;它接收与目标类型相关联的类型修饰词,如果没有,就是 -1 。如果有第三个参数,就必须是 boolean 类型;如果这个转换是一个明确的转换,那么它收到 true ,否则收到 false 。不过,很奇怪的是,SQL 规范在某些场合下要求不同的明确和隐含转换的行为。这个参数提供给那些必须实现这种行为的转换函数。不过不建议你设计此类函数。
正常情况下,类型转换必须有不同的源类型和目标数据类型。不过只要它有多个参数的类型转换实现函数,就允许声明一个源类型和目标类型相同的转换。这个函数用于在系统表里表示类型相关的长度转换函数。此命名函数用于转换一个该类型的数值为其第二个参数给出的带类型修饰词的值。因为目前语法只允许某些内置的数据类型拥有类型修饰词,因此这个特性对用户定义的目标类型没有什么用,提到它只是为了完整。
如果一个类型转换的源类型和目标类型不同,并且接收多于一个参数,它就表示从一种类型转换成另外一种类型只用一个步骤,并且同时实施长度转换。如果没有这样的项可用,那么转换成一个使用了类型修饰词的类型将涉及两个步骤,一个是在数据类型之间转换,另外一个是施加修饰词。
用 DROP CAST 删除用户定义的转换。
请注意,如果希望能双向转换类型,那么你需要明确地定义两个方向的转换。
在 PostgreSQL 7.3 之前,如果一个函数的名字和一个数据类型相同,并且返回该种数据类型,而且还接受另外一种类型的参数自动就是一个转换函数。这个传统随着模式的引入以及为了能在系统表种表示二进制兼容的转换现在已经被废弃了。内置的转换函数仍然遵循这个命名规则,但是它们现在同时也在系统表 pg_cast 里显示为转换。
虽然不是必须的,但是还是建议你遵循旧的命名类型转换实现函数的习惯,也就是说,函数名和目标数据类型同名。许多用户习惯于使用函数风格的表示法(typename(x))来做数据类型转换。这种表示法恰好就是调用类型转换实现函数,这样并不会被当作一种类型转换而被特殊看待。如果你的转换函数没有按照这种传统命名,那么你就会让用户很奇怪。因为 PostgreSQL 允许同名不同参数的函数重载,因此同时存在多个从不同类型向同样类型转换的同名转换函数一点问题都没有。
【注意】前面的段落撒了一个小小的谎:仍然有一种情况下,系统将要使用 pg_cast 来解析一个明显的函数调用的含义。如果函数调用 name(x) 并不匹配任何实际函数,但 name 是一个数据类型的名字并且 pg_cast 显示了它是从类型 x 到这种类型的一个二进制兼容的转换,那么该调用将被构造成一个明确的转换。存在这个例外就可以让二进制兼容的类型转换使用函数风格的语法调用,即使他们缺少函数也可以。