如何重新检查使用 check_function_bodies=false 创建的 SQL 函数?

How to re-check an SQL function created with check_function_bodies=false?

之后,我了解到我可以通过设置 check_function_bodies=false.

来禁用 SQL 函数的语法检查

在我的例子中:运行 使用 Flyway 的升级

  1. 函数创建顺序未明确定义
  2. 一些功能使用其他功能尚未在同一升级中创建。

我的问题是 - 是否可以发出 "recheck" 这样一个函数而不必实际调用它 - 一旦所有其他依赖项都到位? 类似于 Oracle 的 alter function ... compile.

理想情况下,我想在升级开始时设置 check_function_bodies=false,然后在升级结束时重新检查每个 SQL 功能。

我想避免:

  1. 控制脚本的顺序 运行。
  2. 重新运行函数创建脚本

我尝试过的事情:

我可以想到两个办法:

  1. 可以直接调用语言验证器函数:

    SELECT lanname, lanvalidator::regprocedure FROM pg_language;
    
      lanname   |         lanvalidator         
    ------------+------------------------------
     internal   | fmgr_internal_validator(oid)
     c          | fmgr_c_validator(oid)
     sql        | fmgr_sql_validator(oid)
     plpgsql    | plpgsql_validator(oid)
     plpython3u | plpython3_validator(oid)
    (5 rows)
    

    对于 SQL 函数,它会像这样工作:

    SET check_function_bodies = off;
    CREATE FUNCTION bad() RETURNS void LANGUAGE sql AS 'SELECT ';
    
    SET check_function_bodies = on;
    SELECT fmgr_sql_validator('bad()'::regprocedure);
    
    ERROR:  there is no parameter 
    LINE 1: SELECT 
                   ^
    QUERY:  SELECT 
    
  2. 您可以重新定义函数并检查它是否抛出错误:

    SET check_function_bodies = on;
    DO $$BEGIN
       EXECUTE pg_get_functiondef('bad()'::regprocedure);
    END;$$;
    

根据 Laurenz 的出色回答,我编写了这个小辅助函数 - 为他人的利益而分享。

CREATE OR REPLACE FUNCTION recompile_functions()
RETURNS void
LANGUAGE plpgsql
VOLATILE
AS $$
DECLARE
    l_func regproc;
BEGIN
    --schema name can also be an input param or current_schema.
    --test sql functions
    FOR l_func IN (
        SELECT oid
        FROM pg_proc
        WHERE pronamespace='my_schema'::regnamespace
        AND prolang=(SELECT oid FROM pg_language WHERE lanname='sql')
    ) 
    LOOP
        PERFORM fmgr_sql_validator(l_func);
    END LOOP;

    --test plpgsql functions
    FOR l_func IN (
        SELECT oid
        FROM pg_proc
        WHERE pronamespace='my_schema'::regnamespace
        AND prolang=(SELECT oid FROM pg_language WHERE lanname='plpgsql')
    ) 
    LOOP
        PERFORM plpgsql_validator(l_func);
    END LOOP;

EXCEPTION
    WHEN OTHERS THEN
        RAISE EXCEPTION 'Function % failed validation checks: %', l_func::text, SQLERRM;
END; $$;