简体   繁体   English

PostgreSQL EXISTS 在用户定义的 function 中始终返回 true

[英]PostgreSQL EXISTS in user-defined function always returning true

I wrote a simple user-defined function to check for the existence of rows matching some conditions:我写了一个简单的用户定义的 function 来检查是否存在匹配某些条件的行:

CREATE OR REPLACE FUNCTION is_instructor_specialized_in(eid INT, course_area VARCHAR(50))
RETURNS BOOLEAN AS $$
  SELECT EXISTS(SELECT 1 FROM Specializes s WHERE s.eid = eid AND s.name = course_area);
$$ LANGUAGE sql;

I tested it with the following query:我使用以下查询对其进行了测试:

SELECT is_instructor_specialized_in(2, 'Artificial Intelligence') as function_output, 
    EXISTS(SELECT 1 FROM Specializes s WHERE s.eid = 2 AND s.name = 'Artificial Intelligence') as ground_truth;

and the function gave a wrong value of true when it is supposed to evaluate to false (there is no such row in the Specializes table): image并且 function 在应该评估为false时给出了错误的true值( Specializes表中没有这样的行):图片

In fact, it always gives the value of true .事实上,它总是给出true的值。 I'm super confused.我超级困惑。 Is there any reason why this is happening?发生这种情况有什么原因吗?

Version: PostgreSQL 13.2 on x86_64-apple-darwin19.6.0, compiled by Apple clang version 11.0.3 (clang-1103.0.32.62), 64-bit版本:x86_64-apple-darwin19.6.0 上的 PostgreSQL 13.2,Apple 编译 clang 版本 11.0.3 (clang-1103.0.32.62),64 位

Like @wildplasser hinted, your function parameter eid has the same name as a table column, which is never a good idea.就像@wildplasser 暗示的那样,您的 function 参数eid与表列同名,这绝不是一个好主意。 In this case it silently broke your function.在这种情况下,它默默地破坏了您的 function。

The unqualified eid in WHERE s.eid = eid resolves to the table column, not to the function parameter, like you seem to expect. WHERE s.eid = eid中的不合格eid解析为表列,而不是 function 参数,就像您所期望的那样。 So this predicate evaluates to true for any notnull input.因此,对于任何非空输入,此谓词的计算结果为true Sneaky error.偷偷摸摸的错误。

The manual: 手册:

If the argument name is the same as any column name in the current SQL command within the function, the column name will take precedence .如果参数名称与 function 中的当前 SQL 命令中的任何列名称相同,则列名称将优先 To override this, qualify the argument name with the name of the function itself, that is function_name.argument_name .要覆盖它,请使用 function 本身的名称限定参数名称,即function_name.argument_name (If this would conflict with a qualified column name, again the column name wins. You can avoid the ambiguity by choosing a different alias for the table within the SQL command.) (如果这会与限定的列名冲突,则列名再次获胜。您可以通过在 SQL 命令中为表选择不同的别名来避免歧义。)

Bold emphasis mine.大胆强调我的。

Qualifying with the function name is an awkward measure of last resort.使用 function 名称进行资格认证是不得已而为之的尴尬措施。 Avoid the problem to begin with unambiguous parameter names.避免以明确的参数名称开头的问题。 One convention is to prefix parameters with underscore ( _ ) - and never do the same for table columns:一种约定是使用下划线 ( _ ) 为参数添加前缀 - 并且永远不要对表列做同样的事情:

CREATE OR REPLACE FUNCTION func_proper(_eid int, _course_area text)
  RETURNS boolean
  LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT EXISTS(SELECT FROM specializes s WHERE s.eid = _eid AND s.name = _course_area);
$func$;

Or use positional $n parameter references for a simple case like yours.或者对像你这样的简单案例使用位置$n参数引用。 You can still have parameter names for documentation and for named function calls:您仍然可以为文档和命名的 function 调用提供参数名称:

CREATE OR REPLACE FUNCTION func_proper(_eid int, _course_area text)
  RETURNS boolean
  LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT EXISTS(SELECT FROM specializes s WHERE s.eid = $1 AND s.name = $2);
$func$;

db<>fiddle here db<> 在这里摆弄

The default behavior for the same naming conflict in a PL/pgSQL function is to raise an exception, btw. PL/pgSQL function 中相同命名冲突的默认行为是引发异常,顺便说一句。 See:看:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM