存储过程中不寻常的 UPDATE 语法

Unusual UPDATE syntax in stored procedure

我需要帮助来理解我在正在审计的遗留系统中发现的这个存储过程。特别是我无法理解 IF 条件中的 UPDATE 命令:UPDATE authors.author_id ....

DECLARE

    p_mem_id ALIAS FOR ;
    p_auth_id ALIAS FOR ;

    res     bool ;
    v_rec   authors.author_gov_id%ROWTYPE;

    BEGIN
        res := 0;
        SELECT INTO v_rec * FROM authors.author_gov_id WHERE author_id = p_auth_id;

        IF FOUND THEN
              UPDATE authors.author_id = (SELECT gov_id FROM authors.gov_id WHERE mem_id=p_mem_id);
        ELSE
              .. snip ..
        END IF;

        RETURN res;
    END;

我觉得这很奇怪,因为这个更新语句在我的 PSQL 版本中似乎是不受支持的语法[1](没有 SET,直接赋值),并且因为在我的数据库(pg_proc 中也没有)。

my_database=# \d authors.author_id;
Did not find any relation named "authors.author_id".

[1] https://www.postgresql.org/docs/9.3/sql-update.html

这是无效的 SQL 语法,当您实际调用此函数时,postgres 会吐出来。

在看到评论基础表明我并没有因为困惑而疯狂后,我找到了一个安装了这个存储过程的暂存数据库,并试图触发 UPDATE 子句 - 导致以下错误:

ERROR:  syntax error at or near "="
LINE 1: UPDATE authors.author_id = (SELECT gov_id FROM authors...
                                ^
QUERY:  UPDATE authors.author_id = (SELECT gov_id FROM authors.gov_id WHERE mem_id=p_mem_id)
CONTEXT:  PL/pgSQL function authors.copy_govid(integer,integer) line 15 at SQL statement

正如其他人所指出的,这是无效的语法。

但是,当您创建一个函数时,实际的函数代码("body")作为字符串传递并且不会被检查基本 create function 语法的部分解析。该字符串被移交给指定的 "language" 以进行进一步验证。

配置选项 check_function_bodies 控制是否在创建函数时进行此检查。

如果将其设置为 off,则不会验证正文,即使正文无效,create function() 也会成功。

所以下面成功创建函数:

set check_function_bodies=off;

create function invalid()
  returns void
as
$$
begin
  update foo.bar = 'this is so wrong';
end;
$$
language plpgsql;

我想您在该数据库中看到的函数代码就是这样创建的。


一个有效的用例是创建相互依赖的函数,而不必考虑它们的创建顺序。