我的用户和我在PL / pgSQL中不使用函数重载。我们每个(模式,名称)元组总是有一个函数。因此,我们只想按名称删除函数,更改其签名而不必先删除它等。例如,考虑以下函数:
CREATE OR REPLACE FUNCTION myfunc(day_number SMALLINT)
RETURNS TABLE(a INT)
AS
$BODY$
BEGIN
RETURN QUERY (SELECT 1 AS a);
END;
$BODY$
LANGUAGE plpgsql;
为了节省时间,我们想按如下方式调用它,而不用::SMALLINT
限定1,因为只有一个名为myfunc的函数,它只有一个名为day_number的参数:
SELECT * FROM myfunc(day_number := 1)
没有歧义,值1与SMALLINT
类型一致,但PostgreSQL抱怨:
SELECT * FROM myfunc(day_number := 1);
ERROR: function myfunc(day_number := integer) does not exist LINE 12: SELECT * FROM myfunc(day_number := 1); ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
当我们从Python调用这些函数时,我们使用一个包装器来查找函数的签名并使用类型限定参数。这种方法有效,但似乎有可能改进。
有没有办法完全关闭功能重载?
答案 0 :(得分:6)
无法禁用重载 - 这是PostgreSQL函数API系统的基本功能 - 无法禁用。我们知道有一些副作用,比如强大的功能特征刚性 - 但是当在视图,表定义中使用函数时,它可以防止一些令人不快的副作用。所以你不能禁用它。
您只需检查您是否有重载功能:
postgres=# select count(*), proname
from pg_proc
where pronamespace <> 11
group by proname
having count(*) > 1;
count | proname
-------+---------
(0 rows)
答案 1 :(得分:4)
这实际上不是函数重载的问题(这是不可能“关闭”)。这是功能类型分辨率的问题。 (当然,没有重载函数,该算法可以更宽松。)
所有这些都可行:
SELECT * FROM myfunc(day_number := '1');
SELECT * FROM myfunc('1'); -- note the quotes
SELECT * FROM myfunc(1::smallint);
SELECT * FROM myfunc('1'::smallint);
最后两个相当明显,你已经在你的问题中提到了这一点 前两个更有趣,解释隐藏在Function Type Resolution:
中为了这个目的,假定未知的文字可以转换成任何东西。
这应该是简单解决方案:使用字符串文字。
SQL标准中定义的无类型文字('1'
,带引号)或“字符串文字”在性质上与任何其他类型的文字(或常量)不同。
数字常量(1
,不带引号)会立即转换为数字类型 。 Per documentation:
既不包含小数点也不包含小数点的数字常量 如果指数的值适合,则指数最初被假定为类型为整数 type
integer
(32位);否则,如果是,则假定为bigint
类型 它的值适合类型bigint
(64位);否则它被认为是 输入numeric
。包含小数点和/或指数的常量 最初总是假定为numeric
类型。数字常量的初始分配数据类型只是a 类型分辨率算法的起点。在大多数情况下 常量将自动强制转换为最合适的类型 取决于具体情况。必要时,可以强制使用数值 通过强制转换将其解释为特定的数据类型。
大胆强调我的。
函数调用(day_number := 1
)中的赋值是一种特殊情况,此时day_number
的数据类型 unknown 。 Postgres无法从此分配中派生数据类型,默认为integer
。
因此,Postgres会寻找一个首先采用integer
的函数。然后,对于仅使用隐式投射类型的函数远离integer
,换句话说:
SELECT casttarget::regtype
FROM pg_cast
WHERE castsource = 'int'::regtype
AND castcontext = 'i';
所有这些都会被发现 - 如果有多个功能则会发生冲突。 这将是函数重载 ,您将收到不同的错误消息。有两个候选函数,如:
SELECT * FROM myfunc(1);
ERROR: function myfunc(integer) is not unique
请注意消息中的“整数”:数字常量已转换为integer
。
但是,从integer
到smallint
的演员阵营“仅”是分配广告。这就是旅程结束的地方:
No function matches the given name and argument types.
这些相关答案中有更详细的解释:
你 可以 通过将演员阵容从integer
升级到smallint
再到隐式演员来解决此问题:
UPDATE pg_cast
SET castcontext = 'i'
WHERE castsource = 'int'::regtype
AND casttarget = 'int2'::regtype;
但我会强烈反对篡改默认的投射系统。如果您确切知道自己在做什么,请考虑这一点。您可以在Postgres列表中找到相关的讨论。它可以有各种副作用,从功能类型分辨率开始,但不是在那里结束。
功能类型分辨率完全独立于使用的语言。 SQL函数将与PL / perl或PL / pgSQL或“内部”函数竞争相同。功能签名至关重要。内置函数仅排在第一位,因为pg_catalog
在默认search_path
中排在第一位。
答案 2 :(得分:0)
有很多内置函数会被重载,所以如果关闭函数重载就不行了。