跳到主要内容
版本:1.0.13

CREATE CAST

CREATE CAST — 定义一种新的造型


大纲:

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);

通过调用一个之前指定的函数(这种情况中是 float8(int4))把整型常量 42 转换成类型float8(如果没有定义合适的造型,该转换会失败)。

两种类型可以是二进制可强制,这表示该转换可以被“免费”执行而不用调用任何函数。

这要求相应的 值使用同样的内部表示。例如,类型text和 varchar在双向都是二进制可强制的。二进制可强制性并不必是一种对称关系。例如,在当前实现中从xml到 text的造型可以被免费执行,但是反向则需要一个函数来执行至少一次语法检查(两种在双向都二进制值兼容的类型也被称作二进制兼容)。

通过使用WITH INOUT语法,你可以把一种造型定义成I/O 转换造型。一种 I/O 转换造型执行时,会调用源数据类型的输出函数,并且把结果字符串传递给目标数据类型的输入函数。

在很多常见情况中,这种特性避免了为转换单独定义一个造型函数。一种 I/O 转换造型表现得和一个常规的基于函数的造型相同,只是实现不同而已。

默认情况下,只有一次显式造型请求才会调用造型,形式是CAST(x AS typename) or x::typename。

如果造型被标记为AS ASSIGNMENT,那么在为一个目标数据类型的列赋值时会隐式地调用它。例如,假设foo.f1是 一个类型text的列,那么如果从类型integer 到类型text的造型被标记为AS ASSIGNMENT,则:

INSERT INTO foo (f1) VALUES (42);

将被允许,否则不会允许(我们通常使用赋值造型来描述此类造型)。

如果造型被标记为AS IMPLICIT,那么可以在任何上下文中隐式地调用它,无论是赋值还是在一个表达式内部(我们通常用术语隐式造型来描述这类造型)。例如,考虑这个查询:

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操作符。由于缺少哪种选择更好的判断,解析器会放弃并且说明查询有歧义。

对隐式转换持保守态度是明智的。过多的隐式转换可能导致系统以莫名其妙的方式解释命令,或者由于有多种可能解释而根本无法解析命令。一种好的实践是让一种类型转换只对于同一种类型分类中的类型间的信息保持转换隐式可调用。例如,从int2到int4的造型 可以被合理地标记为隐式,但是从float8到 int4的造型可能应该只能在赋值时使用。

注意 有时为了可用性或者标准兼容的原因,有必要提供在一个类型集合之间 的多种隐式造型,这会导致上述不可避免的歧义。解析器还有一招基于类型分类和优先类型的后手,它能帮助 提供这类情况下预期的行为。详见 CREATE TYPE。

要创建一种造型,你必须拥有源数据类型和目标数据类型并且具有在其他类型上 的USAGE特权。要创建一种二进制可强制造型,你必须是一个超级用户(这种限制是因为错误的二进制可强制造型转换很容易让服务器崩溃)。


参数:

source_type

该造型的源数据类型的名称。

target_type

该造型的目标数据类型的名称。

function_name[(argument_type [, ...])]

被用于执行该造型的函数。函数名称可以用模式限定。如果没有被限定,将在模式搜索路径中查找该函数。函数的结果数据类型必须是该造型的目标数据类型。它的参数讨论如下。

如果没有指定参数列表,则该函数名称在其模式中必须是唯一的。

WITHOUT FUNCTION

指示源类型可以二进制强制到目标类型,因此执行该造型不需要函数。

WITH INOUT

指示该造型是一种 I/O 转换造型,执行需要调用源数据类型的输出函数, 并且把结果字符串传递给目标数据类型的输入函数。

AS ASSIGNMENT

指示该造型可以在赋值的情况下被隐式调用。

AS IMPLICIT

指示该造型可以在任何上下文中被隐式调用。

造型实现函数可以具有1到3个参数。第一个参数类型必须等于源类型或者能从源类型二进制强制得到。第二个参数(如果存在)必须是类型 integer,它接收与目标类型相关联的类型修饰符,如果没有类型修饰符,它会收到-1。第三个参数(如果存在)必须是类型boolean,如果该造型是一种显式造型,它会收到 true,否则会收到false(奇怪地是,SQL 标准在某些情况中对显式和隐式造型要求不同的行为。这个参数被提供给必须实现这类造型的函数。不推荐在设计自己的数据类型时用它)。

一个造型函数的返回类型必须等于目标类型或者能二进制强制到目标类型。

通常,强制转换必须具有不同的源和目标数据类型。但是,如果它有一个带有多个参数的强制转换实现函数,则可以声明具有相同源类型和目标类型的造型。它用于表示系统目录中特定类型的长度强制函数。命名函数用于将类型的值强制转为其第二个参数提供的类型修饰符的值。

当强制转换具有不同的源类型和目标类型,并且一个函数使用多个参数时,它支持从一种类型转换为另一种类型,并在单个步骤中应用长度强制。如果没有这样的条目,强制转换为使用类型修饰符的类型将涉及两个强制转换步骤,一个是在数据类型之间进行转换,另一个是应用修饰符。

向域类型强制转换或从域类型强制转换当前无效。向域或从域强制转换使用与其基础类型关联的造型。


注解:

使用DROP CAST移除用户定义的造型。

记住如果你想要能够双向转换类型,你需要在两个方向上都显式声明造型。

通常没有必要创建用户定义类型和标准字符串类型(text、varchar和char(n),以及被定义在字符串分类中的用户定义类型)之间的造型。 系统会为它们提供自动的 I/O 转换造型。到字符串类型的自动造型被当做赋值造型,而字符串类型作为源的自动造型只能是显式的。通过声明你自己的造型来替换自动造型可以覆盖这种行为,但是这样做的唯一原因是你想让该转换比标准的设置更容易被调用。另一种可能的原因是你想让该转换的行为与该类型的 I/O 函数不同,但这种原因足够令人感到意外,你应该考虑再三它是不是个好主意(确实有少量内建类型对转换具有不同的行为,绝大部分是因为 SQL 标准的要求)。

虽然不必要,推荐你继续遵循这种在目标数据类型后面命名造型实现函数的习惯。很多用户习惯于能够使用一种函数风格的记法来造型 数据类型,即typename(x)。 这种记法正好是对造型实现函数的调用,这里它没有被作为造型特殊对待。如果你的转换函数没有被指定支持这种习惯,那么你的用户会觉得意外。由于系统允许用不同的参数类型重载同一个函数名,因此存在多个从不同类型到同一目标类型的同名转换函数并不困难。

注意 实际上前一段过于简化了:有两种情况中一个函数调用结构在没有被匹配到 一个实际函数时将被当作一次造型请求。如果函数调用 name(x)没有正好匹配任何现有函数, 但name是一种数据类型的名称并且 pg_cast提供了一种从x的类型到这种类型的二进制可强制造型,那么该调用将被翻译为一次二进制可强制造型。通过这种例外,二进制可强制造型能够以函数语法调用,即便没有该函数。同样的,如果没有pg_cast项,但是该造型是要造型到一种 字符串类型或者是要从一种字符串类型造型,调用将被翻译成一次 I/O 转换 造型。这种例外允许以函数语法调用 I/O 转换造型。

注意 还有一种例外中的例外:从组合类型到字符串类型的 I/O 转换造型不能使用函数语法调用,而必须被写成显式造型语法(CAST或者 ::记号)。增加这种例外是因为在引入了自动提供的 I/O 转换造型之后,在想要引用一个函数或者列时太容易意外地调用这种造型。


示例:

要使用函数int4(bigint)创建一种从类型 bigint到类型int4的赋值造型:

CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;

(在系统中这种造型已经被预定义)。


另见:

CREATE FUNCTION, CREATE TYPE, DROP CAST