ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# CREATE CAST ## Name CREATE CAST -- 定义一个用户定义的转换 ## Synopsis ``` 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`的操作符, 但是有一个`integer` + `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`,只能明确地转换。 > **Note:** 有时,有必要为了可用性和标准支持的原因在一组类型中提供多个隐含转换,导致上述无法避免的模棱两可的问题。 解析器有一个基于_type categories_和_preferred types_的启发式函数回调功能,有助于在这种情况下提供所期望的行为。 参阅[CREATE TYPE](#calibre_link-100)获取更多详细信息。 为了能够创建一个转换,您必须是源或者目标数据类型的所有者。 为了创建一个强制二进制的转换,您必须是超级用户。 (做这个约束的原因是错误的二进制可强迫转换转换可以很容易让服务器崩溃。) ## 参数 `_source_type_` 转换的源数据类型。 `_target_type_` 转换的目标数据类型。 `_function_name_`(`_argument_type_` [, ...]) 用于执行转换的函数。 这个函数名可以是用模式名修饰的。 如果它没有用模式名修饰, 那么该函数将从模式搜索路径中找出来。 函数的结果数据类型必须匹配转换的目标类型。 它的参数在下面讨论。 `WITHOUT FUNCTION` 表明源类型是对目标类型是二进制可强制转换的,所以没有函数需要执行此转换。 `WITH INOUT` 表明转换是I/O转换,通过调用源数据类型的输出函数来执行,并将结果传给目标数据类型的输入函数。 `AS ASSIGNMENT` 表示转换可以在赋值模式下隐含调用。 `AS IMPLICIT` 表示转换可以在任何环境里隐含调用。 转换实现函数可以有一到三个参数。 第一个参数的类型必须与转换的源类型相同的,或可以从转换的源类型二进制可强制转换的。 第二个参数,如果存在,必须是`integer`类型;它接收这些与目标类型相关联的类型修饰符,或者若什么都没有则是-1。 第三个参数,如果存在,必须是`boolean`类型;若转换是一个显式类型转换则会收到`true`,否则是`false`。 (奇怪的是,在一些情况下SQL标准要求对显式和隐式转换的不同表现。我们不推荐您设计自己的数据类型,这很重要。) 一个转换函数的返回类型必须是与转换的目标类型相同或者对转换的目标类型二进制可强制转换 。 通常,一个转换必须有不同的源和目标数据类型。 然而,若有多于一个参数的转换实现函数,则允许声明一个有相同的源和目标类型的转换。 这用于表示系统目录中的特定类型的长度强制函数。 命名的函数用于强制一个该类型的值为第二个参数给出的类型修饰符值。 如果一个类型转换的源类型和目标类型不同,并且接收多于一个参数,它就表示从一种类型转换成另外一种类型只用一个步骤,并且同时实施长度转换。 如果没有这样的项可用, 那么转换成一个使用了类型修饰词的类型将涉及两个步骤,一个是在数据类型之间转换, 另外一个是施加修饰词指定的转换。 对域类型的转换目前没有作用。转换一般是针对域相关的所属数据类型。 ## 注意 使用[DROP CAST](#calibre_link-535)删除用户定义的转换。 请注意,如果希望能双向转换类型,那么你需要明确地定义两个方向的转换。 通常不需要创建用户定义类型与标准字符串类型之间的转换(`text`,`varchar`和`char(``_n_`),以及被定义为字符串的范畴的用户定义的类型)。 PostgreSQL为此提供自动I/O转换转换。 字符串类型的自动转换可以认为是分配转换,而来自字符串的自动转换是唯一显式的。 您可以通过声明自己的转换替换系统的自动转换,但是,通常这么做的唯一原因是,你想让转化比标准唯一分配或者唯一显式设置更容易调用。 另一个可能的原因是你想让转化变现的不同于类型的I/O函数; 但是最重要的是您应该反复考虑这是否是一个好主意。(少量内部类型确实对转换有不同的性能要求,大部分是因为要求SQL标准。) 在PostgreSQL7.3之前,每个与数据类型名称相同的函数会返回那个数据类型,并取一个不同类型的参数的函数,自动成为一个转换函数。 在面临模式引入时约定已取消并且能代表系统表中的二进制可强制转换。内置的转换功能仍然遵循这种命名模式,但是他们必须像系统表`pg_cast`中的转换一样显示。 虽然不是必须的,但是还是建议你遵循旧的命名类型转换实现函数的习惯,也就是说, 函数名和目标数据类型同名。 许多用户习惯于使用函数风格的表示法`_typename_`(`_x_`)来做数据类型转换。 这种表示法恰好就是调用类型转换实现函数,这样并不会被当作一种类型转换而被特殊看待。 如果你的转换函数没有按照这种传统命名,那么你就会让用户很奇怪。 因为PostgreSQL允许同名不同参数的函数重载,因此同时存在多个从不同类型向同样类型转换的同名转换函数一点问题都没有。 > **Note:** 事实上前面所述是过分简化的:在两种情况下函数调用结构被认为是一个转换请求而不需要将其匹配为一个实际函数。 如果函数调用`_name_`(`_x_`)不准确匹配任何现有函数,但是`_name_`是一个数据类型的名称 并且`pg_cast`从`_x_`类型提供了一个二进制可强制转换到这个类型,则调用会被解析为一个二进制可强制转换。 即使是没有任何转换函数,也设计了一种异常,二进制可强制转换可以通过使用函数语法来调用, 同样的,若无`pg_cast`条目,但转换会到达或者来自一个字符串类型, 调用将会被视为一个I/O转换转换。 该异常情况下允许I/O转换转换通过使用函数语法来调用。 > **Note:** 也还有一种异常中的异常:从复合数据类型向字符串类型的I/O转换不能使用函数语法,必须设计为精确的转换语法(`CAST` 或 `::` 声明) 增加这种异常是因为在介绍过自动执行的I/O转换后,用户会发现在一个函数或是字段参考时很容易误执行一个类似的转换。 ## 例子 为了从类型`bigint`到类型`int4`创建一个指派映射要通过使用函数`int4(bigint)`: ``` CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT; ``` (这个转换在系统中已经预先定义了。) ## 兼容性 `CREATE CAST`指令符合SQL标准,除了SQL没有为二进制可强制转换类型或者实现函数的额外参数来实现功能。 `AS IMPLICIT`也是一个PostgreSQL扩展。 ## 参见 [CREATE FUNCTION](#calibre_link-4)、[CREATE TYPE](#calibre_link-100) 和[DROP CAST](#calibre_link-535)