使用CREATE TABLE
时,可以声明varchar(12)
,varchar(34)
或varchar
数据类型,并且它们会有所不同...
但是在声明函数时,“子类型”将被忽略...没有警告(!)...
我发现忽略函数签名是一件好事这对于管理function overloading是必不可少的,“子类型签名”的管理将有些混乱……但是我在《指南》中没有看到(typeconv-func也没有),没有指南对此的警告,没有说明。
因此,在当今的2018年,在PostgreSQL v10 +的所有增强功能之后... 我可以配置PostgreSQL接受子类型的函数重载吗?
具体示例
CREATE TABLE foo ( x varchar(12), y varchar(34), z varchar );
\d foo
-- not ignored, as expected
CREATE OR REPLACE FUNCTION foo( p_x varchar ) RETURNS text AS
$f$ SELECT 'hello1' $f$ LANGUAGE SQL IMMUTABLE;
CREATE OR REPLACE FUNCTION foo( p_x varchar(12) ) RETURNS text AS
$f$ SELECT 'hello10' $f$ LANGUAGE SQL IMMUTABLE;
\df foo
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+------+------------------+-----------------------+--------
public | foo | text | p_x character varying | normal
(1 row)
因此,不可能声明foo(x)
与foo(z)
...相同的时间
SELECT pg_typeof(x),pg_typeof(y),pg_typeof(z) FROM foo;
-- returns "character varying" for all
当然,有时我们可以使用pg_typeof()
:
s
。geometry
可以检查子类型(例如POINT子类型)。这是一个超载解决方法,但不是“真正的超载”。 注意:带有适当注释的orthogonal重载函数集将解决带有注释foo('abc')
的解析错误。在示例中,使用
CREATE FUNCTION foo( p_x text ) RETURNS text AS $f$ SELECT 'hello-text'
$f$ LANGUAGE SQL IMMUTABLE;
“自动将abc
强制转换为文本”解决了select foo('abc')
正在工作的问题。
答案 0 :(得分:2)
“子类型”是类型修饰符,通常称为typmod。
当您在签名中创建带有typmods的函数时,它们将被忽略。 function catalog仅存储基本类型ID(不同于column catalog,它具有atttypmod
字段),因此无法仅通过typmod来区分两个功能。
据我所知,唯一的解决方法是创建一个domain(一个内置了typmod的用户定义类型别名)。这使您的函数可以引用typmod,而不必实际将它们存储在pg_proc
中:
CREATE DOMAIN varchar12 AS varchar(12);
CREATE OR REPLACE FUNCTION foo( p_x varchar12 ) RETURNS text AS
$f$ SELECT 'hello10'::text $f$ LANGUAGE SQL IMMUTABLE;
这样做的动机通常是为了保留长度限制;您的varchar(12)
函数将接受一个1000个字符的字符串,而不会引起投诉。
但是,尽管域类型确实允许您重载函数,但仍然需要将值转换为适当的域类型,才能解决重载。
因此,除非您愿意将表列也转换为使用域,否则它几乎没有实际用途。 (尽管假设您选择的名称比varchar12
更有意义,但是根据域来定义模式具有其自身的优势。)