CREATE CAST — 定义一个新转换
CREATE CAST (source_type
AStarget_type
) WITH FUNCTIONfunction_name
[ (argument_type
[, ...]) ] [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type
AStarget_type
) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type
AStarget_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 转换强制转换。通过调用源数据类型的输出函数并传递结果字符串到目标数据类型的输入函数来执行 I/O 转换强制转换。在许多常见情况下,此功能可避免为转换编写单独的强制转换函数。I/O 转换强制转换的行为与常规基于函数的强制转换相同;只有实现方式不同。
默认情况下,只能通过显式强制转换请求强制转换,即显式CAST(
或x
AS typename
)x
::
typename
构建。
如果强制转换标记为AS ASSIGNMENT
,则在向目标数据类型列分配值时可以隐式调用它。例如,假设foo.f1
是类型为text
的列,则
INSERT INTO foo (f1) VALUES (42);
如果从类型integer
向类型text
的强制转换标记为AS ASSIGNMENT
,则允许,否则不允许。(我们通常使用术语分配强制转换来描述这种类型的强制转换。)
如果强制转换标记为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
运算符的替代方法之间进行选择。由于缺乏任何有关何种选择更合适的知识,它将放弃并声明该查询不明确。仅两个转换中一个为隐式的这一事实是我们向解析器教授优先将混合的 numeric
和 integer
表达式解析为 numeric
的方式;对这一点没有内置知识。
将转换标记为隐式时保持保守很明智。过多的隐式转换路径会导致 PostgreSQL 选择对命令进行令人惊讶的解释,或者由于存在多种可能的解释而无法解析命令。一个好的经验法则是,仅当在同一通用类型类别内的类型之间进行信息保留转换时才让转换可隐式调用。例如,从 int2
到 int4
的转换可以合理地是隐式的,但从 float8
到 int4
的转换可能应该仅限于赋值。最好将跨类型类别的转换(例如从 text
到 int4
)设为仅明确。
有时由于可用性或标准合规性原因,有必要在一定类型的集合中提供多个隐式转换,从而导致无法像上述那样避免的歧义。解析器有一个基于类型类别和首选类型的回退启发式方法,可以帮助在这些情况下提供所需的行为。有关更多信息,请参阅CREATE TYPE。
要能够创建转换,您必须拥有源数据或目标数据类型,并对其他类型拥有 USAGE
权限。要创建可二进制强制的转换,您必须是超级用户。(做出此限制是因为二进制强制转换错误容易导致服务器崩溃。)
source_type
强制转换源数据类型的名称。
target_type
强制转换目标数据类型的名称。
function_name
[(argument_type
[, ...])]
用于执行强制转换的函数。函数名称可以是模式限定的,如果不是,将沿模式搜索路径查找该函数。该函数的结果数据类型必须与强制转换的目标类型匹配。其参数在下面会有讨论。如果未指定参数列表,函数名在其模式中必须是唯一的。
WITHOUT FUNCTION
表示源类型可以强制转换为二进制目标类型,因此无需函数来执行强制转换。
WITH INOUT
表示强制转换是一个 I/O 转换强制转换,通过调用源数据类型的输出函数并将其结果字符串传递给目标数据类型的输入函数来执行。
AS ASSIGNMENT
表示强制转换可以在赋值上下文中隐式调用。
AS IMPLICIT
表示强制转换可以在任何上下文中隐式调用。
强制转换实现函数可以有一个到三个参数。第一个参数类型必须与强制转换的源类型相同或可以强制转换为二进制目标类型。如果存在第二个参数,它必须是类型 integer
;它接收与目标类型关联的类型修改符,如果不存在则接收 -1
。如果存在第三个参数,它必须是类型 boolean
;如果是显式强制转换,则接收 true
;否则接收 false
。(奇怪的是,SQL 标准要求在某些情况下显式强制转换和隐式强制转换具有不同的行为。为必须实现这种强制转换的函数提供了此参数。建议你不要设计自己的数据类型来影响此参数。)
强制转换函数的返回类型必须与强制转换的目标类型相同或可以强制转换为二进制目标类型。
通常,强制转换必须具有不同的源数据类型和目标数据类型。但是,允许声明源数据类型和目标数据类型相同的强制转换,只要它具有具有多个参数的强制转换实现函数。这用于在系统目录中表示特定于类型的长度强制转换函数。命名函数用于根据其第二个参数给出的类型修改符值强制转换该类型的某个值。
如果一个 cast 具有不同的源类型和目标类型,并且一个函数接受多个参数,它支持单步从一种类型转换为另一种类型并应用长度强制。当不存在此类条目时,对将使用类型修饰符的类型的强制涉及两个 cast 步骤,一个在数据类型之间转换,另一个应用修饰符。
当前,对域类型进行转换或从域类型进行转换不起作用。对域进行转换或从域进行转换使用与其基础类型关联的 cast。
使用 DROP CAST
删除用户定义的 cast。
记住,如果您希望能够双向转换类型,则需要显式地双向声明 cast。
通常不需要在用户定义类型和标准字符串类型(text
、varchar
和 char(
,以及定义为字符串类别的用户定义类型)之间创建 cast。 PostgreSQL 为此提供了自动 I/O 转换 cast。对字符串类型的自动 cast 被视为赋值 cast,而对字符串类型执行的自动 cast 仅为显式 cast。您可以通过声明自己的 cast 来替换自动 cast 以覆盖此行为,但通常这样做唯一的理由是您希望转换比标准的仅赋值或仅显式设置更容易调用。另一个可能的原因是您希望转换的行为不同于类型的 I/O 函数;但这令人惊讶,您应当三思而后行是否这样做是一个好主意。(少数内置类型确实具有不同的转换行为,主要是因为 SQL 标准的要求。)n
)
虽然不是必须的,但我们建议您继续遵循此旧惯例,即以目标数据类型为 cast 实现函数命名。许多用户习惯于使用函数式符号,即 typename
(x
) 来进行数据类型转换。事实上,此符号只不过是调用 cast 实现函数;它不被特别视为一个 cast。如果您的转换函数未命名为支持此惯例,则您的用户会感到惊讶。由于 PostgreSQL 允许使用不同的参数类型对同一函数名进行重载,因此多个转换函数都可以从不同的类型转换,并且都使用目标类型的名称,这样不会有任何困难。
事实上,前一段简化过度了:有两个情况,函数调用结构将会被视为演员请求,而无需与实际函数匹配。如果函数调用name
(x
) 与任何现有函数不完全匹配,但 name
是数据类型名称,并且 pg_cast
提供了一种从 x
的类型强制转换为该类型的二进制兼容强制转换,那么调用将被解释为二进制兼容强制转换。这样做的目的是,即使没有任何函数,也可以使用函数语法来调用二进制兼容强制转换。同样,如果不存在 pg_cast
项,但转换是与字符串类型之间转换,那么调用将被解释为输入/输出转换强制转换。这样做允许使用函数语法来调用输入/输出转换强制转换。
这个例外也有例外:不能使用函数语法调用从复合类型到字符串类型的输入/输出转换强制转换,而必须在显式强制转换语法中写入(CAST
或 ::
符号)。添加此例外是因为在自动提供输入/输出转换强制转换后,发现意图调用的是函数或列引用时,很容易意外地调用了这种转换。
要使用函数 int4(bigint)
从类型 bigint
创建分配强制转换到类型 int4
CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;
(系统中已预定义此强制转换。)
CREATE CAST
命令符合SQL标准,但 SQL 没有针对二进制兼容类型或为实现函数提供额外参数做出规定。 AS IMPLICIT
也是 PostgreSQL 扩展。