Is there a way to disable function overloading in Postgres
我的用户和我不使用PL / pgSQL中的函数重载。 我们每个(模式,名称)元组总是有一个函数。 因此,我们只想按名称删除函数,更改其签名而不必先删除它等。例如,考虑以下函数:
1 2 3 4 5 6 7 8 9 | 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; |
为了节省时间,我们想按如下方式调用它,而不用
1 | SELECT * FROM myfunc(day_number := 1) |
没有歧义,值1与
1 | SELECT * FROM myfunc(day_number := 1); |
1
2
3
4
5 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调用这些函数时,我们使用一个包装器来查找函数的签名并使用类型限定参数。 这种方法有效,但似乎有可能改进。
有没有办法完全关闭功能重载?
欧文发了正确答复。我的下一个回复与禁用重载的可能性有关。
无法禁用重载 - 这是PostgreSQL函数API系统的基本功能 - 无法禁用。我们知道有一些副作用,比如强大的功能特征刚性 - 但是当在视图,表定义中使用函数时,它可以防止一些令人不快的副作用。所以你不能禁用它。
您只需检查您是否有重载功能:
1 2 3 4 5 6 7 8 | postgres=# SELECT COUNT(*), proname FROM pg_proc WHERE pronamespace <> 11 GROUP BY proname HAVING COUNT(*) > 1; COUNT | proname -------+--------- (0 ROWS) |
这实际上不是函数重载的问题(不可能"关闭")。这是功能类型解析的问题。 (当然,没有重载函数,该算法可以更宽松。)
所有这些都可行:
1 2 3 4 5 | SELECT * FROM myfunc(day_number := '1'); SELECT * FROM myfunc('1'); -- note the quotes SELECT * FROM myfunc(1::SMALLINT); SELECT * FROM myfunc('1'::SMALLINT); |
为什么?
最后两个是相当明显的,你已经在你的问题中提到了。
前两个更有趣,解释隐藏在功能类型解析中:
unknown literals are assumed to be convertible to anything for this purpose.
这应该是你的简单解决方案:使用字符串文字。
SQL标准中定义的无类型文字
数字常量
A numeric constant that contains neither a decimal point nor an
exponent is initially presumed to be type integer if its value fits in
typeinteger (32 bits); otherwise it is presumed to be typebigint if
its value fits in typebigint (64 bits); otherwise it is taken to be
typenumeric . Constants that contain decimal points and/or exponents
are always initially presumed to be typenumeric .The initially assigned data type of a numeric constant is just a
starting point for the type resolution algorithms. In most cases the
constant will be automatically coerced to the most appropriate type
depending on context. When necessary, you can force a numeric value to
be interpreted as a specific data type by casting it.
大胆强调我的。
函数调用(
因此,Postgres首先寻找一个
1 2 3 4 | SELECT casttarget::regtype FROM pg_cast WHERE castsource = 'int'::regtype AND castcontext = 'i'; |
所有这些都将被发现 - 如果有多个功能则会发生冲突。那将是函数重载,你会得到一个不同的错误信息。有两个这样的候选函数:
1 | SELECT * FROM myfunc(1); |
1 ERROR: FUNCTION myfunc(INTEGER) IS NOT UNIQUE
请注意消息中的"整数":数字常量已转换为
但是,从
1 No FUNCTION matches the given name AND argument types.
SQL小提琴。
这些相关答案中有更详细的解释:
-
PostgreSQL错误:函数to_tsvector(字符变化,未知)不存在
-
生成一系列日期 - 使用日期类型作为输入
脏修复
您可以通过将演员从
1 2 3 4 | UPDATE pg_cast SET castcontext = 'i' WHERE castsource = 'int'::regtype AND casttarget = 'int2'::regtype; |
但我强烈反对篡改默认的投射系统。如果您确切知道自己在做什么,请考虑这一点。您可以在Postgres列表中找到相关的讨论。它可以有各种副作用,从功能类型分辨率开始,但不是在那里结束。
在旁边
功能类型分辨率完全独立于使用的语言。 SQL函数将与PL / perl或PL / pgSQL或"内部"函数竞争相同。功能签名至关重要。内置函数仅排在第一位,因为
有很多内置函数被重载,所以如果关闭函数重载就不行。