Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16

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

如果从类型 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

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

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

另请参阅

CREATE FUNCTIONCREATE TYPEDROP CAST