我将所有函数保存在一个带有
'CREATE OR REPLACE FUNCTION somefunction'
的文本文件中。现在,如果我向现有函数添加或删除参数,它会创建一个具有相同名称的重载,并且要删除原始函数,我需要按确切的顺序输入所有参数类型,这有点乏味。
是否可以使用某种通配符来
DROP
具有给定名称的所有函数,以便我可以将 DROP FUNCTION
行添加到文件顶部?
此查询创建所有必需的 DDL 语句:
SELECT 'DROP FUNCTION ' || oid::regprocedure
FROM pg_proc
WHERE proname = 'my_function_name' -- name without schema-qualification
AND pg_function_is_visible(oid); -- restrict to current search_path
输出:
DROP FUNCTION my_function_name(string text, form text, maxlen integer);
DROP FUNCTION my_function_name(string text, form text);
DROP FUNCTION my_function_name(string text);
检查合理性后执行命令。
传递函数名称区分大小写且不添加双引号以与
pg_proc.proname
匹配。
regprocedure
(oid::regprocedure
),然后隐式转换为 text
,生成带有参数类型的函数名称,根据当前的情况自动使用双引号和模式限定search_path
需要的地方。 不可能进行 SQL 注入。
pg_function_is_visible(oid)
将选择限制为当前 search_path
中的功能(“可见”)。您可能想要也可能不想要这个。
如果您在多个模式中有多个同名函数,或者具有各种函数参数的重载函数,则其中的 所有 将单独列出。您可能希望限制为特定模式或特定函数参数。
相关:
EXECUTE
立即执行语句。
小心!它会降低你的功能!
CREATE OR REPLACE FUNCTION f_delfunc(_name text, OUT functions_dropped int)
LANGUAGE plpgsql AS
$func$
-- drop all functions with given _name in the current search_path, regardless of function parameters
DECLARE
_sql text;
BEGIN
SELECT count(*)::int
, 'DROP FUNCTION ' || string_agg(oid::regprocedure::text, '; DROP FUNCTION ')
FROM pg_catalog.pg_proc
WHERE proname = _name
AND pg_function_is_visible(oid) -- restrict to current search_path
INTO functions_dropped, _sql; -- count only returned if subsequent DROPs succeed
IF functions_dropped > 0 THEN -- only if function(s) found
EXECUTE _sql;
END IF;
END
$func$;
致电:
SELECT f_delfunc('my_function_name');
如果没有引发异常,该函数将返回找到并删除的函数的数量。
0
如果没有找到。
进一步阅读:
对于 9.1 之前的 Postgres 版本或使用
regproc
和 pg_get_function_identity_arguments(oid)
的旧版本函数,请检查此答案的编辑历史记录。
您需要编写一个函数,该函数采用函数名称,并从
information_schema
中查找每个重载及其参数类型,然后为每个重载构建并执行一个 DROP
。
编辑:事实证明这比我想象的要困难得多。看起来
information_schema
没有在其 routines
目录中保留必要的参数信息。所以需要使用PostgreSQL的补充表pg_proc
和pg_type
:
CREATE OR REPLACE FUNCTION udf_dropfunction(functionname text)
RETURNS text AS
$BODY$
DECLARE
funcrow RECORD;
numfunctions smallint := 0;
numparameters int;
i int;
paramtext text;
BEGIN
FOR funcrow IN SELECT proargtypes FROM pg_proc WHERE proname = functionname LOOP
--for some reason array_upper is off by one for the oidvector type, hence the +1
numparameters = array_upper(funcrow.proargtypes, 1) + 1;
i = 0;
paramtext = '';
LOOP
IF i < numparameters THEN
IF i > 0 THEN
paramtext = paramtext || ', ';
END IF;
paramtext = paramtext || (SELECT typname FROM pg_type WHERE oid = funcrow.proargtypes[i]);
i = i + 1;
ELSE
EXIT;
END IF;
END LOOP;
EXECUTE 'DROP FUNCTION ' || functionname || '(' || paramtext || ');';
numfunctions = numfunctions + 1;
END LOOP;
RETURN 'Dropped ' || numfunctions || ' functions';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
我在重载函数上成功测试了这一点。它的组装速度相当快,但作为一个实用函数工作得很好。我建议在实践中使用它之前进行更多测试,以防我忽略了一些东西。
改进原始答案以考虑
schema
,即。 schema.my_function_name
,
select
format('DROP FUNCTION %s(%s);',
p.oid::regproc, pg_get_function_identity_arguments(p.oid))
FROM pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE
p.oid::regproc::text = 'schema.my_function_name';
埃尔文答案的稍微增强版本。另外支持以下
复制/粘贴代码:
/**
* Removes all functions matching given function name mask
*
* @param p_name_mask Mask in SQL 'like' syntax
* @param p_opts Combination of comma|space separated options:
* trace - output SQL to be executed as 'NOTICE'
* dryrun - do not execute generated SQL
* @returns Generated SQL 'drop functions' string
*/
CREATE OR REPLACE FUNCTION mypg_drop_functions(IN p_name_mask text,
IN p_opts text = '')
RETURNS text LANGUAGE plpgsql AS $$
DECLARE
v_trace boolean;
v_dryrun boolean;
v_opts text[];
v_sql text;
BEGIN
if p_opts is null then
v_trace = false;
v_dryrun = false;
else
v_opts = regexp_split_to_array(p_opts, E'(\\s*,\\s*)|(\\s+)');
v_trace = ('trace' = any(v_opts));
v_dryrun = ('dry' = any(v_opts)) or ('dryrun' = any(v_opts));
end if;
select string_agg(format('DROP FUNCTION %s(%s);',
oid::regproc, pg_get_function_identity_arguments(oid)), E'\n')
from pg_proc
where proname like p_name_mask
into v_sql;
if v_sql is not null then
if v_trace then
raise notice E'\n%', v_sql;
end if;
if not v_dryrun then
execute v_sql;
end if;
end if;
return v_sql;
END $$;
select mypg_drop_functions('fn_dosomething_%', 'trace dryrun');
这是我在@Сухой27解决方案之上构建的查询,它生成sql语句以删除模式中的所有存储函数:
WITH f AS (SELECT specific_schema || '.' || ROUTINE_NAME AS func_name
FROM information_schema.routines
WHERE routine_type='FUNCTION' AND specific_schema='a3i')
SELECT
format('DROP FUNCTION %s(%s);',
p.oid::regproc, pg_get_function_identity_arguments(p.oid))
FROM pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE
p.oid::regproc::text IN (SELECT func_name FROM f);
从 Postgres 10 开始,您只能按名称删除函数,只要名称对于其架构是唯一的。只需将以下声明放在函数文件的顶部即可:
drop function if exists my_func;
文档这里。
根据名称删除过程时,如果存在多个同名但参数不同的过程,pgsql 会产生错误。因此,如果您想删除单个过程而不影响其他过程,则只需使用以下查询即可。
SELECT 'DROP FUNCTION ' || oid::regprocedure
FROM pg_proc
WHERE oid = {$proc_oid}