DROP FUNCTION不知道参数的数量/类型?

时间:2011-10-01 20:54:08

标签: postgresql plpgsql dynamic-sql sql-drop

我将所有功能都保存在'CREATE OR REPLACE FUNCTION somefunction'的文本文件中。 因此,如果我添加或更改某些功能,我只需将文件提供给psql。

现在,如果我向现有函数添加或删除参数,它会创建一个具有相同名称的重载,并按照确切的顺序删除所有参数类型中的原始I类型,这是一种单调乏味的行为。

我是否可以使用某种通配符来删除具有给定名称的所有函数,以便我可以在文件顶部添加DROP FUNCTION行?

7 个答案:

答案 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尚未移动 更多相关答案:

对于使用regprocpg_get_function_identity_arguments(oid)的功能超过9.1或更早版本的Postgres版本,请检查此答案的修改历史记录。 < / p>

答案 1 :(得分:21)

您需要编写一个带有函数名称的函数,并使用information_schema中的参数类型查找每个重载,然后为每个重载生成并执行DROP

编辑:事实证明这比我想象的要困难得多。看起来information_schema未在其routines目录中保留必要的参数信息。所以你需要使用PostgreSQL的补充表pg_procpg_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的答案略有增强版本。另外支持以下

  • &#39;像&#39;而不是精确的函数名称匹配
  • 可以在&#39;干模式&#39;和&#39;追踪&#39;用于删除函数的SQL

复制/粘贴代码:

mysite
    -settings.py
    -templates/