CREATE CAST (source_type AS target_type) WITH FUNCTION function_name (argument_type [, ...]) [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type AS target_type) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type AS target_type) WITH INOUT [ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST定义一个新的转换。一个转换说明如何在两个类型之间进行转换。比如:
SELECT CAST(42 AS float8);
通过调用前面指定的函数将整数常量42转化为float8类型,即float8(int4)的形式。 (如果没有定义合适的转换, 转换将失败。)
两种形式是二进制可强制转换的,这意味转换可以在不调用函数的情况下自由执行。 这要求相应的值使用相同的内部表示。例如,text和varchar形式都是二进制可强制转换的两种类型。 二进制可可强制转换未必是一个对称的关系。例如: xml到text的转换可以在当前的处理中可直接执行。 但相反的方向的转换需要一个函数来执行,至少一个语法检查。(两种二进制可强制转换的形式也被称为二进制兼容。)
您可以定义一个转换为使用WITH INOUT语法的I/O conversion cast转化转换。 一个I/O转化转换通过调用原数据库类型的输出函数来执行,并将结果传给目标数据类型的输入函数。
缺省时,只有在明确要求转换的情况下才调用一个转换,也就是一个明确的CAST(x AS typename)或x::typename转换要求。
如果转换被标记为AS ASSIGNMENT,那么在给目标数据类型的字段赋值的时候,可以隐含调用它。 比如,假设foo.f1是一个类型为text的字段, 那么:
INSERT INTO foo (f1) VALUES (42);
如果从integer类型到text类型的转换标记为AS ASSIGNMENT,上面的这句就被允许,否则就不允许。 (通常用术语assignment cast来描述这种转换。)
如果转换标记了AS IMPLICIT,那么可以在任何环境下调用,不管是作业还是在一个内部表达式中。 (我们通常使用术语implicit cast来描述这种转换。 ) 例如,考虑下面这个查询:
SELECT 2 + 4.0;
解析器初始时标记常量分别为integer和numeric。 在系统目录中没有integer + numeric的操作符, 但是有一个numeric + numeric操作符。 若integer到numeric的转换是可以执行的并且标记为 AS IMPLICIT — 则该查询将会成功执行。 解析器将使用隐性的转换并按所写的查询生成结果:
SELECT CAST ( 2 AS numeric ) + 4.0;
现在,目录提供了一个从numeric到integer的转换。 如果那个转换标记了AS IMPLICIT —而它并不是— 然后解析器会面临对选择上面的解释还是选择numeric常量到integer的转换, 然后应用integer + integer操作符。 缺乏选择哪一种处理方式的足够信息,系统会放弃执行并返回查询是模棱两可的信息。 两种转换中仅有一个是缺省的方式正是我们设计的方式,我们让解析器更偏向于将numeric-和-integer的混合表达式的结果视作numeric; 没有关于那方面的内置信息。
在是否将转换标记为隐性的问题上保守一些是明智的。 过于丰富的隐含转换路径 会导致PostgreSQL选择让人奇怪的命令解析,或者是完全不能解析命令,因为存在多个可能的解析。 一个好的规则是,只有在同一个通用类型范畴里面的那些可以保留转换信息的类型之间才标记为可隐含调用转换。 比如,从int2到int4可以合理地标记为隐含转换,但是从float8到int4也许应该标记为赋值转换。 跨类型范围的转换,比如text到int4,只能明确地转换。
注意: 有时,有必要为了可用性和标准支持的原因在一组类型中提供多个隐含转换,导致上述无法避免的模棱两可的问题。 解析器有一个基于type categories和preferred types的启发式函数回调功能,有助于在这种情况下提供所期望的行为。 参阅CREATE TYPE获取更多详细信息。
为了能够创建一个转换,您必须是源或者目标数据类型的所有者。 为了创建一个强制二进制的转换,您必须是超级用户。 (做这个约束的原因是错误的二进制可强迫转换转换可以很容易让服务器崩溃。)
转换的源数据类型。
转换的目标数据类型。
用于执行转换的函数。 这个函数名可以是用模式名修饰的。 如果它没有用模式名修饰, 那么该函数将从模式搜索路径中找出来。 函数的结果数据类型必须匹配转换的目标类型。 它的参数在下面讨论。
表明源类型是对目标类型是二进制可强制转换的,所以没有函数需要执行此转换。
表明转换是I/O转换,通过调用源数据类型的输出函数来执行,并将结果传给目标数据类型的输入函数。
表示转换可以在赋值模式下隐含调用。
表示转换可以在任何环境里隐含调用。
转换实现函数可以有一到三个参数。 第一个参数的类型必须与转换的源类型相同的,或可以从转换的源类型二进制可强制转换的。 第二个参数,如果存在,必须是integer类型;它接收这些与目标类型相关联的类型修饰符,或者若什么都没有则是-1。 第三个参数,如果存在,必须是boolean类型;若转换是一个显式类型转换则会收到true,否则是false。 (奇怪的是,在一些情况下SQL标准要求对显式和隐式转换的不同表现。我们不推荐您设计自己的数据类型,这很重要。)
一个转换函数的返回类型必须是与转换的目标类型相同或者对转换的目标类型二进制可强制转换 。
通常,一个转换必须有不同的源和目标数据类型。 然而,若有多于一个参数的转换实现函数,则允许声明一个有相同的源和目标类型的转换。 这用于表示系统目录中的特定类型的长度强制函数。 命名的函数用于强制一个该类型的值为第二个参数给出的类型修饰符值。
如果一个类型转换的源类型和目标类型不同,并且接收多于一个参数,它就表示从一种类型转换成另外一种类型只用一个步骤,并且同时实施长度转换。 如果没有这样的项可用, 那么转换成一个使用了类型修饰词的类型将涉及两个步骤,一个是在数据类型之间转换, 另外一个是施加修饰词指定的转换。
对域类型的转换目前没有作用。转换一般是针对域相关的所属数据类型。
使用DROP CAST删除用户定义的转换。
请注意,如果希望能双向转换类型,那么你需要明确地定义两个方向的转换。
通常不需要创建用户定义类型与标准字符串类型之间的转换(text,varchar和char(n),以及被定义为字符串的范畴的用户定义的类型)。 PostgreSQL为此提供自动I/O转换转换。 字符串类型的自动转换可以认为是分配转换,而来自字符串的自动转换是唯一显式的。 您可以通过声明自己的转换替换系统的自动转换,但是,通常这么做的唯一原因是,你想让转化比标准唯一分配或者唯一显式设置更容易调用。 另一个可能的原因是你想让转化变现的不同于类型的I/O函数; 但是最重要的是您应该反复考虑这是否是一个好主意。(少量内部类型确实对转换有不同的性能要求,大部分是因为要求SQL标准。)
在PostgreSQL7.3之前,每个与数据类型名称相同的函数会返回那个数据类型,并取一个不同类型的参数的函数,自动成为一个转换函数。 在面临模式引入时约定已取消并且能代表系统表中的二进制可强制转换。内置的转换功能仍然遵循这种命名模式,但是他们必须像系统表pg_cast中的转换一样显示。
虽然不是必须的,但是还是建议你遵循旧的命名类型转换实现函数的习惯,也就是说, 函数名和目标数据类型同名。 许多用户习惯于使用函数风格的表示法typename(x)来做数据类型转换。 这种表示法恰好就是调用类型转换实现函数,这样并不会被当作一种类型转换而被特殊看待。 如果你的转换函数没有按照这种传统命名,那么你就会让用户很奇怪。 因为PostgreSQL允许同名不同参数的函数重载,因此同时存在多个从不同类型向同样类型转换的同名转换函数一点问题都没有。
注意: 事实上前面所述是过分简化的:在两种情况下函数调用结构被认为是一个转换请求而不需要将其匹配为一个实际函数。 如果函数调用name(x)不准确匹配任何现有函数,但是name是一个数据类型的名称 并且pg_cast从x类型提供了一个二进制可强制转换到这个类型,则调用会被解析为一个二进制可强制转换。 即使是没有任何转换函数,也设计了一种异常,二进制可强制转换可以通过使用函数语法来调用, 同样的,若无pg_cast条目,但转换会到达或者来自一个字符串类型, 调用将会被视为一个I/O转换转换。 该异常情况下允许I/O转换转换通过使用函数语法来调用。
注意: 也还有一种异常中的异常:从复合数据类型向字符串类型的I/O转换不能使用函数语法,必须设计为精确的转换语法(CAST 或 :: 声明) 增加这种异常是因为在介绍过自动执行的I/O转换后,用户会发现在一个函数或是字段参考时很容易误执行一个类似的转换。