3

按照这个答案,我了解到我可以通过设置来禁用 SQL 函数的语法检查check_function_bodies=false

在我的情况下:使用 Flyway 运行升级 where

  1. 函数创建的顺序没有很好的定义
  2. 某些功能使用尚未在同一升级中创建的其他功能。

我的问题是 - 一旦所有其他依赖项都到位,是否可以对这样的函数进行“重新检查”而不必实际调用它?类似于 Oracle 的alter function ... compile.

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

我想避免不得不:

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

我尝试过的事情:

  • 做假人alter function
  • 打电话pg_get_functiondef
4

2 回答 2

5

我可以想到两种方法:

  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 $1';
    
    SET check_function_bodies = on;
    SELECT fmgr_sql_validator('bad()'::regprocedure);
    
    ERROR:  there is no parameter $1
    LINE 1: SELECT $1
                   ^
    QUERY:  SELECT $1
    
  2. 您可以重新定义该函数并检查它是否引发错误:

    SET check_function_bodies = on;
    DO $$BEGIN
       EXECUTE pg_get_functiondef('bad()'::regprocedure);
    END;$$;
    
于 2019-01-29T14:34:33.893 回答
0

遵循 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; $$;
于 2019-01-30T06:56:58.707 回答