【问题标题】:Drop all functions in a namespace? (Execute generated DDL commands?)删除命名空间中的所有函数? (执行生成的 DDL 命令?)
【发布时间】:2012-01-09 04:57:40
【问题描述】:

我正在尝试编写一个命令来删除命名空间中的所有函数。我已经找到了一个可以生成 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);

但是,我不知道如何更改代码,以便实际删除函数 - 而不是仅生成命令。

有什么想法吗?

【问题讨论】:

标签: sql postgresql plpgsql dynamic-sql


【解决方案1】:

只需将查询的输出复制+粘贴到您的psql 解释器中。它将运行您粘贴的所有命令。

【讨论】:

    【解决方案2】:

    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 functionDO 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 来解决,但我在这里没有这样做,因为它使函数更加危险。

    相关:

    【讨论】:

    • @Hartwig:我添加了缺少的; 感谢您的反馈。
    • 需要在执行之前检查_sql是否为空,以防没有功能,并且可能还需要删除级联
    • @Chin:好点。我相应地更新了(只有CASCADE 的注释)以及有关第 11 页的更多信息。
    【解决方案3】:

    对于任何生成一组命令的 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;
    

    【讨论】:

    • 在这种特殊情况下会引发错误。该函数(位于public 模式中)会自行删除。随后的drop 引发错误,导致一切回滚。这是一个有趣的效果。 :)
    【解决方案4】:

    没有存储过程的我的版本

    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$$;
    

    【讨论】:

      【解决方案5】:
      -- 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();
      

      【讨论】:

        猜你喜欢
        • 2016-02-04
        • 2012-03-08
        • 2020-08-30
        • 2023-03-21
        • 1970-01-01
        • 2011-02-26
        • 2021-05-04
        • 2016-01-02
        • 1970-01-01
        相关资源
        最近更新 更多