我正在尝试编写一个删除命名空间中所有函数的命令。我已经找到了一个生成drop函数脚本的命令:
SELECT 'DROP FUNCTION ' || ns.nspname || '.' || proname || '('
|| oidvectortypes(proargtypes) || ');'
FROM pg_proc INNER JOIN pg_namespace ns ON (pg_proc.pronamespace = ns.oid)
WHERE ns.nspname = 'public' order by proname;
来源:http://www.postgresonline.com/journal/archives/74-How-to-delete-many-functions.html
这将生成如下内容:
?column?
------------------------------------------
DROP FUNCTION public.function1(bigint);
DROP FUNCTION public.function2();
DROP FUNCTION public.function3(text);
但是,我无法弄清楚如何更改代码,以便实际删除这些功能 - 而不是仅生成命令。
有什么想法吗?
答案 0 :(得分:4)
Postgres 11 中的系统目录已更改! (prokind
代替proisagg
)请参阅:
看起来像这样:
CREATE OR REPLACE FUNCTION public.f_delfunc(_schema text, _del text = '')
RETURNS text AS
$func$
DECLARE
_sql text;
_ct text;
BEGIN
SELECT INTO _sql, _ct
string_agg('DROP '
|| CASE p.proisagg WHEN true THEN 'AGGREGATE '
ELSE 'FUNCTION ' END
|| quote_ident(n.nspname) || '.' || quote_ident(p.proname)
|| '('
|| pg_catalog.pg_get_function_identity_arguments(p.oid)
|| ')'
, E'\n'
)
,count(*)::text
FROM pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE n.nspname = _schema;
-- AND p.proname ~~* 'f_%'; -- Only selected funcs?
-- AND pg_catalog.pg_function_is_visible(p.oid) -- Only visible funcs?
IF _ct = '0' THEN
RETURN 'Found 0 functions to delete';
ELSIF lower(_del) = 'del' THEN -- Actually delete!
EXECUTE _sql;
RETURN _ct || E' functions deleted:\n' || _sql;
ELSE -- Else only show SQL.
RETURN _ct || E' functions to delete:\n' || _sql;
END IF;
END
$func$ LANGUAGE plpgsql;
致电展示:
SELECT f_delfunc('public'); -- 2nd parameter is covered by default.
致电删除:
SELECT f_delfunc('public','del');
您需要动态SQL。使用plpgsql function或DO statement(PostgreSQL 9.0 +)与EXECUTE
。
请注意使用functions pg_get_function_identity_arguments()
and pg_function_is_visible
。后者可以省略。这是一种安全措施,因此您不会删除当前用户search_path
之外的功能。
我添加了“安全模式”。仅在$2 = 'del'
时删除。否则只显示生成的SQL。
请注意,如果函数存在于您删除的架构中,将自行删除。
我还添加了quote_ident()
来防范 SQLi 。请考虑以下事项:
CREATE FUNCTION "; DELETE FROM users;"()
RETURNS int AS
'SELECT 1'
LANGUAGE sql;
CASCADE
来解决,但我在这里没有这样做,因为它使功能更加危险。相关:
答案 1 :(得分:0)
只需将查询的输出复制+粘贴到psql
解释器中即可。它将运行您粘贴的所有命令。
答案 2 :(得分:0)
对于生成一组命令的任何SQL表达式:
begin;
create function _execute(text) returns boolean language plpgsql as $$
begin
raise info 'Execute: %', $1;
execute $1;
end;
$$;
select count(_execute(__SQL__)); -- __SQL__ is your command-generating statement
drop function _execute(text);
end;
答案 3 :(得分:0)
没有存储过程的我的版本
DO $$DECLARE command text;
BEGIN
command = (SELECT 'DROP FUNCTION ' || proname || '(' || oidvectortypes(proargtypes) || ')'
FROM pg_proc INNER JOIN pg_namespace ns ON (pg_proc.pronamespace = ns.oid)
WHERE proname='functioniliketodrop'
order by proname);
execute command;
END$$;
答案 4 :(得分:0)
-- DROP FUNCTION public.f_deleteAllFunctions();
CREATE OR REPLACE FUNCTION public.f_deleteAllFunctions()
RETURNS TABLE(functiondef character varying) AS
$BODY$
DECLARE
var_r record;
var_query TEXT;
BEGIN
FOR var_r IN(
SELECT ns.nspname || '.' || proname || '(' || oidvectortypes(proargtypes) || ');' as nombreFuncion
FROM pg_proc INNER JOIN pg_namespace ns ON (pg_proc.pronamespace = ns.oid)
WHERE ns.nspname = 'public' order by proname
)
LOOP
functionDef := 'DROP FUNCTION ' ||var_r.nombreFuncion;
RAISE NOTICE '%', functionDef;
EXECUTE functionDef;
RETURN NEXT;
END LOOP;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION public.f_deleteAllFunctions()
OWNER TO postgres;
select * from f_deleteAllFunctions();