CREATE CAST

定义一个新的转换类型。

概要

CREATE CAST (<sourcetype> AS <targettype>) 
       WITH FUNCTION <funcname> (<argtype> [, ...]) 
       [AS ASSIGNMENT | AS IMPLICIT]

CREATE CAST (<sourcetype> AS <targettype>)
       WITHOUT FUNCTION 
       [AS ASSIGNMENT | AS IMPLICIT]

CREATE CAST (<sourcetype> AS <targettype>)
       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 类型名) 或 x:: 类型名 构造。

如果字符串被标记为AS ASSIGNMENT,则在为目标数据类型的列赋值时可隐式调用该字符串。例如,假设foo.f1是类型为text的列,则:

INSERT INTO foo (f1) VALUES (42);

若将整数类型强制转换为文本类型的操作被标记为AS ASSIGNMENT,则允许该转换;否则不允许。此类转换通常被称为赋值转换。

如果类型转换标记为隐式转换,则可在任何上下文中隐式调用该转换,无论是赋值语句还是表达式内部。隐式转换一词通常用于描述此类转换。例如,考虑以下查询:

SELECT 2 + 4.0;

解析器最初将常量分别标记为整数型和数值型。系统目录中不存在整数与数值的加法运算符,但存在数值与数值的加法运算符。若存在整数转数值的隐式转换(实际存在)且被标记为隐式转换(实际如此),则该查询将成功执行。解析器仅应用隐式转换,并将查询解析为如下形式:

SELECT CAST ( 2 AS numeric ) + 4.0;

目录还提供了从数值型到整数型的强制转换。若该转换被标记为隐式(实际并非如此),解析器将面临两种解释:一是按上述方式处理,二是将数值常量强制转换为整数后应用整数加法运算符。由于缺乏优先处理的依据,解析器将放弃解析并判定查询存在歧义。仅其中一个转换为隐式转换的设计,正是我们教解析器优先将混合数值与整数的表达式解析为数值表达式的方式;解析器本身并不具备这种内置知识。

在标记隐式转换时保持谨慎是明智之举。过多的隐式转换路径可能导致数据库对命令做出出人意料的解释,或因存在多种可能解释而完全无法解析命令。一条通用准则是:仅当类型转换属于同一大类且能保持信息完整时,才允许隐式调用转换。例如 int2 到 int4 的转换可合理采用隐式方式,但 float8 到 int4 的转换则应仅限于赋值操作。跨类型类别的转换(如文本到 int4)最好仅采用显式方式。

出于可用性或标准兼容性考虑,有时需要在一组类型间提供多重隐式转换,这将导致如上所述无法避免的歧义。解析器会基于类型类别和首选类型采用回退启发式策略,以在这种情况下实现预期行为。更多信息请参阅 CREATE TYPE。

要创建强制类型转换,您必须拥有源数据类型或目标数据类型的所有权,并对另一种类型具有USAGE权限。要创建二进制强制类型转换,您必须是超级用户。(此限制是因为错误的二进制强制类型转换可能轻易导致服务器崩溃。)

参数

  • sourcetype

    • 转换操作中源数据类型的名称。
  • targettype

    • 强制转换的目标数据类型名称。
  • funcname(argtype [, ...])

    • 用于执行类型转换的函数。函数名可以是带模式限定的。若未指定模式,数据库将在模式搜索路径中查找该函数。函数的结果数据类型必须与转换的目标类型匹配。

    • 转换实现函数可包含一至三个参数。第一个参数类型必须与转换源类型完全相同或可通过二进制强制转换获得。若存在第二个参数,其类型必须为整数型;该参数接收目标类型关联的类型修饰符,若无修饰符则接收-1。若存在第三个参数,其类型必须为布尔型;若转换为显式转换则接收true,否则接收false。SQL规范要求显式转换与隐式转换在某些情况下具有不同行为。此参数专为必须实现此类转换的函数提供。不建议您以此方式设计自定义数据类型。

    • 强制转换函数的返回类型必须与转换的目标类型完全相同,或可通过二进制强制转换转换为目标类型。

    • 通常情况下,强制转换必须具有不同的源数据类型和目标数据类型。然而,当强制转换实现函数接受多个参数时,允许声明源类型与目标类型相同的强制转换。此特性用于表示系统目录中类型特有的长度强制转换函数。命名函数用于将某类型的值强制转换为其第二个参数指定的类型修饰符值。

    • 当强制转换涉及不同源类型和目标类型,且函数接受多个参数时,该转换会在单一步骤中完成类型转换和长度强制转换。若不存在此类转换条目,则对使用类型修饰符的类型进行强制转换需分两步完成:第一步进行数据类型转换,第二步应用修饰符。

    • 目前,将类型转换为或从域类型转换为其他类型不会产生任何效果。将类型转换为或从域类型转换为其他类型时,将使用其底层类型关联的转换操作。

  • WITHOUT FUNCTION

    • 表示源类型可强制转换为目标类型,因此无需函数执行强制转换。
  • WITH INOUT

    • 表示该转换属于输入/输出转换,通过调用源数据类型的输出函数生成字符串,再将该字符串传递给目标数据类型的输入函数来实现。
  • AS ASSIGNMENT

    • 表示该类型可能在赋值上下文中被隐式调用。
  • AS IMPLICIT

    • 表示该类型可能在任何上下文中被隐式调用。

注意

请注意,在本版本数据库中,用户自定义转换中使用的用户自定义函数必须定义为IMMUTABLE。所有自定义函数的编译代码(共享库文件)必须放置在数据库阵列中每个主机(协调节点及所有分区节点)的相同位置。该位置还必须位于LD_LIBRARY_PATH环境变量中,以便服务器能够定位这些文件。

请记住,若要实现双向类型转换,必须显式声明双向强制转换。

通常无需在用户自定义类型与标准字符串类型(text、varchar、char(n))之间创建转换,也无需在定义为字符串类别的用户自定义类型之间创建转换。数据库为这些类型提供了自动I/O转换。自动转换为字符串类型时视为赋值转换,而从字符串类型自动转换则仅支持显式转换。可通过声明自定义转换来覆盖自动转换行为,但通常仅当需要比标准的"仅赋值"或"仅显式"设置更便捷的转换方式时才需如此操作。另一种可能动机是希望转换行为与类型I/O函数不同——实施前请三思。(少数内置类型确实存在转换行为差异,主要源于SQL标准要求。)

建议遵循命名约定,将目标数据类型的转换实现函数命名为与内置转换实现函数相同的名称。许多用户习惯于使用函数样式语法进行数据类型转换,即 typename(x)。

存在两种情况,函数调用构造会被视为转换请求,而无需与实际函数匹配。若函数调用 *name\(x\)* 与任何现有函数均不完全匹配,但 name 是数据类型的名称,且 pg_cast 为该类型提供了从 *x* 类型进行二进制强制转换的转换,则该调用将被解释为二进制强制转换。数据库设置此例外,旨在允许通过函数语法调用二进制强制转换,即使该转换本身不存在对应函数。同样地,若不存在pg_cast条目,但转换涉及字符串类型的输入或输出时,该调用将被解释为I/O转换。此例外机制同样支持通过函数语法调用I/O转换。

上述例外情况存在一个特例:复合类型到字符串类型的I/O转换强制转换不能使用函数式语法调用,而必须采用显式强制转换语法(即CAST或::表示法)。该特例的存在源于自动提供的I/O转换强制转换引入后,发现当开发者意图调用函数或列引用时,极易误触发此类强制转换。

示例

创建一个将类型 bigint 转换为类型 int4 的赋值操作,使用函数 int4(bigint)(该转换已在系统中预定义):

CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;

兼容性

CREATE CAST命令符合SQL标准,但需注意SQL未规定二进制强制转换类型或实现函数的额外参数。AS IMPLICIT同样属于数据库扩展功能。

另见

CREATE FUNCTION, CREATE TYPE, DROP CAST