如何重新检查使用 check_function_bodies=false 创建的 SQL 函数?
How to re-check an SQL function created with check_function_bodies=false?
在 之后,我了解到我可以通过设置 check_function_bodies=false
.
来禁用 SQL 函数的语法检查
在我的例子中:运行 使用 Flyway 的升级
- 函数创建顺序未明确定义
- 一些功能使用其他功能尚未在同一升级中创建。
我的问题是 - 是否可以发出 "recheck" 这样一个函数而不必实际调用它 - 一旦所有其他依赖项都到位?
类似于 Oracle 的 alter function ... compile
.
理想情况下,我想在升级开始时设置 check_function_bodies=false
,然后在升级结束时重新检查每个 SQL 功能。
我想避免:
- 控制脚本的顺序 运行。
- 重新运行函数创建脚本
我尝试过的事情:
- 做假人
alter function
- 呼叫
pg_get_functiondef
我可以想到两个办法:
可以直接调用语言验证器函数:
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
您可以重新定义函数并检查它是否抛出错误:
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; $$;
在 check_function_bodies=false
.
在我的例子中:运行 使用 Flyway 的升级
- 函数创建顺序未明确定义
- 一些功能使用其他功能尚未在同一升级中创建。
我的问题是 - 是否可以发出 "recheck" 这样一个函数而不必实际调用它 - 一旦所有其他依赖项都到位?
类似于 Oracle 的 alter function ... compile
.
理想情况下,我想在升级开始时设置 check_function_bodies=false
,然后在升级结束时重新检查每个 SQL 功能。
我想避免:
- 控制脚本的顺序 运行。
- 重新运行函数创建脚本
我尝试过的事情:
- 做假人
alter function
- 呼叫
pg_get_functiondef
我可以想到两个办法:
可以直接调用语言验证器函数:
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
您可以重新定义函数并检查它是否抛出错误:
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; $$;