2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不受支持的版本: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.f1text 类型的列,那么

INSERT INTO foo (f1) VALUES (42);

如果从 integer 类型到 text 类型的强制转换标记为 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

指示可以在任何上下文中隐式调用强制转换。

强制转换实现函数可以具有 1 到 3 个参数。第一个参数类型必须与强制转换的源类型相同或二进制可强制转换为源类型。第二个参数(如果存在)必须是 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的扩展。

提交更正

如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用此表单报告文档问题。