2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3

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 类型。(如果未定义合适的类型转换,则转换失败。)

两种类型可以二进制可转换,这意味着转换可以“免费”执行,而无需调用任何函数。这要求对应的值使用相同的内部表示。例如,textvarchar 类型可以双向二进制可转换。二进制可转换并非一定是对称关系。例如,在当前实现中,从 xmltext 的转换可以免费执行,但反方向需要一个至少执行语法检查的函数。(双向二进制可转换的两种类型也称为二进制兼容。)

您可以使用 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);

如果从 integertext 的类型转换标记为 AS ASSIGNMENT,则允许执行此操作,否则不允许。(我们通常使用赋值类型转换这个术语来描述这种类型的转换。)

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

SELECT 2 + 4.0;

解析器最初将常量标记为 integernumeric 类型。系统目录中没有 integer + numeric 操作符,但有一个 numeric + numeric 操作符。因此,如果存在从 integernumeric 的类型转换并且该类型转换标记为 AS IMPLICIT — 实际上确实如此 — 则查询将成功。解析器将应用隐式转换,并像查询写成这样一样进行解析:

SELECT CAST ( 2 AS numeric ) + 4.0;

现在,目录还提供了从 numericinteger 的类型转换。如果该类型转换被标记为 AS IMPLICIT — 它实际上并未被标记 — 那么解析器将面临在上述解释和将 numeric 常量转换为 integer 并应用 integer + integer 操作符之间的选择。由于不知道偏好哪种选择,它将放弃并声明查询模棱两可。只有两个类型转换中的一个具有隐式转换,这是我们教解析器如何偏好解析混合 numericinteger 表达式为 numeric 的方式;这方面没有内置的知识。

谨慎地标记隐式类型转换是明智的。过多的隐式类型转换路径可能导致 PostgreSQL 选择令人惊讶的命令解释,或者由于存在多种可能的解释而无法解析命令。一个经验法则是,只有在同一通用类型类别中的类型之间进行信息保留转换时,才使类型转换能够隐式调用。例如,从 int2int4 的类型转换可以合理地是隐式的,但从 float8int4 的类型转换可能应该是仅赋值的。跨类型类别的转换,例如 textint4,最好只做显式转换。

注意

有时出于可用性或符合标准的原因,需要在类型集合之间提供多个隐式类型转换,从而导致无法像上面那样避免的歧义。解析器有一个基于类型类别首选类型的回退启发式方法,这有助于在这些情况下提供所需的行为。有关更多信息,请参阅 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 标准要求在某些情况下显式和隐式转换具有不同的行为,这很奇怪。此参数是为必须实现此类转换的函数提供的。不建议您设计自己的数据类型,使其具有这种意义。)

类型转换函数的返回类型必须与类型转换的目标类型相同或可以二进制可转换为目标类型。

通常,类型转换必须具有不同的源数据类型和目标数据类型。但是,如果类型转换有一个包含多个参数的实现函数,则允许声明具有相同源和目标类型的类型转换。这用于在系统目录中表示类型特定的长度转换函数。指定的函数用于将类型的值转换为其第二个参数给出的类型修饰符值。

当类型转换具有不同的源和目标类型以及一个接受多个参数的函数时,它支持在一个步骤中将一种类型转换为另一种类型并应用长度转换。当没有此类条目可用时,转换为使用类型修饰符的类型需要两个类型转换步骤,一个用于在数据类型之间进行转换,第二个用于应用修饰符。

目前,转换为域类型或从域类型转换没有效果。转换为域或从域转换使用与其基础类型相关的类型转换。

注释

使用 DROP CAST 删除用户定义的类型转换。

请记住,如果您想能够双向转换类型,则需要显式声明双向类型转换。

通常不需要在用户定义类型和标准字符串类型(textvarcharchar(n),以及定义为字符串类别的用户定义类型)之间创建类型转换。 PostgreSQL 会为这些类型提供自动 I/O 转换类型转换。自动转换为字符串类型的类型转换被视为赋值类型转换,而自动从字符串类型转换的类型转换仅显式。您可以通过声明自己的类型转换来替换自动类型转换来覆盖此行为,但通常唯一的原因是如果您希望转换比标准的仅赋值或仅显式设置更容易调用。另一个可能的原因是您希望转换的行为与类型的 I/O 函数不同;但这足够令人惊讶,您应该三思而后行。(一些内置类型确实在转换方面具有不同的行为,主要是由于 SQL 标准的要求。)

虽然不是必需的,但建议您继续遵循此旧惯例,即根据目标数据类型为类型转换实现函数命名。许多用户习惯于能够使用函数风格的表示法转换数据类型,即 typename(x)。此表示法实际上只是一个类型转换实现函数的调用;它不被特别视为类型转换。如果您的转换函数不是按照此约定命名的,您将令用户感到惊讶。由于 PostgreSQL 允许使用不同的参数类型重载相同的函数名称,因此拥有来自不同类型但都使用目标类型名称的多个转换函数没有任何困难。

注意

实际上,前一段过于简化了:在两种情况下,函数调用构造将被视为类型转换请求,而无需将其与实际函数匹配。如果函数调用 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 CAST 命令符合SQL标准,但 SQL 没有为二进制可转换类型或实现函数的附加参数提供规定。 AS IMPLICIT 也是 PostgreSQL 的扩展。

提交更正

如果您在文档中看到任何不正确、不符合您对特定功能的经验或需要进一步说明的内容,请使用 此表格 报告文档问题。