文档

CREATE CAST

更新时间:

CREATE CAST用于定义一种新的造型。

简介

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 ) or x :: typename

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

    INSERT INTO foo (f1) VALUES (42);

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

如果造型被标记为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更好的方法就是只让这两种造型中的一个是隐式的,没有有关于此的内建知识。

对标记造型为隐式持保守态度是明智的。过多的隐式造型路径可能导致 PolarDB以令人吃惊的方式解释命令,或者由于有多种可能解释而根本无法解析命令。一种好的经验是让一种造型只对于同一种一般类型分类中的类型间的信息保持转换隐式可调用。例如,从int2int4的造型可以被合理地标记为隐式,但是从float8int4的造型可能应该只能在赋值时使用。跨类型分类的造型(如textint4)最好只被用于显式使用。

语法

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

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

实际上前一段过于简化了:有两种情况中一个函数调用结构在没有被匹配到一个实际函数时将被当作一次造型请求。如果函数调用 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;