我将所有功能都保存在'CREATE OR REPLACE FUNCTION somefunction'
的文本文件中。
因此,如果我添加或更改某些功能,我只需将文件提供给psql。
现在,如果我向现有函数添加或删除参数,它会创建一个具有相同名称的重载,并按照确切的顺序删除所有参数类型中的原始I类型,这是一种单调乏味的行为。
我是否可以使用某种通配符来删除具有给定名称的所有函数,以便我可以在文件顶部添加DROP FUNCTION
行?
答案 0 :(得分:62)
此查询创建所有必需的DDL语句(通过强制转换为regprocedure
简化):
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 ..
-- .. you may or may not want this
输出:
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);
执行命令(合理性检查后)。
函数名称区分大小写,并且在作为text
参数传递时不添加双引号以匹配pg_proc.proname
。
对象标识符类型regprocedure
( oid::regprocedure
)的强制转换使所有标识符对SQL注入安全(通过恶意格式错误的标识符) )。转换为text
时,函数名称会根据需要自动根据当前search_path
进行双引号和架构限定。
pg_function_is_visible(oid)
将选择限制为当前search_path
中的函数。你可能想要也可能不想要那样。条件pg_function_is_visible(oid)
到位后,保证函数可见。
如果在多个模式中有多个相同名称的函数,或者具有各种函数参数的重载函数,则 所有 将单独列出。您可能希望限制在特定模式或特定功能参数之后。
相关:
您可以围绕此构建plpgsql
函数,以使用EXECUTE
立即执行语句。对于Postgres 9.1 或更高版本:
小心!它会降低你的功能!
CREATE OR REPLACE FUNCTION f_delfunc(_name text, OUT func_dropped int) AS
$func$
DECLARE
_sql text;
BEGIN
SELECT count(*)::int
, 'DROP FUNCTION ' || string_agg(oid::regprocedure::text, '; DROP FUNCTION ')
FROM pg_proc
WHERE proname = _name
AND pg_function_is_visible(oid)
INTO func_dropped, _sql; -- only returned if trailing DROPs succeed
IF func_dropped > 0 THEN -- only if function(s) found
EXECUTE _sql;
END IF;
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT * FROM f_delfunc('my_function_name');
或者只是:
SELECT f_delfunc('my_function_name');
这样您就无法获得结果列的名称 func_dropped
列。对你来说无关紧要。
该函数返回找到和删除的函数数(没有异常引发) - 0
如果没有找到。
它假设{默认} search_path
,其中pg_catalog
尚未移动
更多相关答案:
对于使用regproc
和pg_get_function_identity_arguments(oid)
的功能超过9.1或更早版本的Postgres版本,请检查此答案的修改历史记录。 < / p>
答案 1 :(得分:21)
您需要编写一个带有函数名称的函数,并使用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;
我在重载函数上成功测试了这个。它被拼凑得非常快,但作为实用功能可以正常工作。我建议在实践中使用它之前测试更多,以防我忽略了某些事情。
答案 2 :(得分:4)
改进原始answer以考虑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';
答案 3 :(得分:3)
如果存在多个具有相同名称但不同参数的过程,则根据过程名称删除该过程时,pgsql会产生错误。因此,如果要删除单个过程而不影响其他过程,则只需使用以下查询。
SELECT 'DROP FUNCTION ' || oid::regprocedure
FROM pg_proc
WHERE oid = {$proc_oid}
答案 4 :(得分:1)
这是我在@Сухой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);
答案 5 :(得分:1)
从Postgres 10开始,您只能按名称删除函数,只要名称对于其架构是唯一的即可。只需将以下声明放在函数文件的顶部即可:
drop function if exists my_func;
文档here。
答案 6 :(得分:0)
Erwin的答案略有增强版本。另外支持以下
复制/粘贴代码:
mysite
-settings.py
-templates/