关于sql:删除命名空间中的所有函数? (执行生成的DDL命令?)

Drop all functions in a namespace? (Execute generated DDL commands?)

我正在尝试编写一个删除命名空间中所有函数的命令。 我已经找到了一个生成drop函数脚本的命令:

1
2
3
4
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

这将产生类似于:

1
2
3
4
5
                 ?COLUMN?                
------------------------------------------
 DROP FUNCTION public.function1(BIGINT);
 DROP FUNCTION public.function2();
 DROP FUNCTION public.function3(text);

但是,我无法弄清楚如何更改代码,以便实际删除函数 - 而不是仅生成命令。

有任何想法吗?


Postgres 11中的系统目录已更改! (prokind而不是proisagg)请参阅:

  • 如何删除PostgreSQL中的所有函数?

看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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'
'

          )
          ,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:
'
|| _sql;
   ELSE                                               -- Else only show SQL.
      RETURN _ct || E' functions to delete:
'
|| _sql;
   END IF;
END
$func$  LANGUAGE plpgsql;

致电显示:

1
SELECT f_delfunc('public');         -- 2nd parameter is covered by default.

致电删除:

1
SELECT f_delfunc('public','del');

主要观点

  • 你需要动态SQL。使用带有EXECUTE的plpgsql函数或DO语句(PostgreSQL 9.0+)。

  • 请注意函数pg_get_function_identity_arguments()pg_function_is_visible的使用。后者可以省略。它是一种安全措施,因此您不会删除当前用户search_path之外的功能。

  • 我添加了一个"安全模式"。仅在$2 = 'del'时删除。否则只显示生成的SQL。

  • 请注意,如果该函数存在于您删除的架构中,则该函数将自行删除。

  • 我还添加了quote_ident()来防范SQLi。考虑以下:

1
2
3
4
CREATE FUNCTION"; DELETE FROM users;"()
  RETURNS INT AS
'SELECT 1'
  LANGUAGE SQL;
  • 如果对任何涉及的函数存在依赖性,则会失败。可以通过添加CASCADE来解决,但我在这里没有这样做,因为它使功能更加危险。

有关:

  • DROP FUNCTION不知道参数的数量/类型?
  • 如何获取函数参数列表(所以我可以删除一个函数)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
-- 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();


没有存储过程的我的版本

1
2
3
4
5
6
7
8
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$$;

对于生成一组命令的任何SQL表达式:

1
2
3
4
5
6
7
8
9
10
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;


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