Отбросить все функции в пространстве имен?(Выполнить сгенерированные команды DDL?) - PullRequest
4 голосов
/ 30 ноября 2011

Я пытаюсь написать команду, которая удалит все функции в пространстве имен. Я уже нашел команду, которая сгенерирует скрипт удаления функций:

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

Однако я не могу понять, как изменить код, чтобы фактически удалить функции, а не только генерировать команды.

Есть идеи?

Ответы [ 5 ]

4 голосов
/ 30 ноября 2011

Системные каталоги изменены в 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 или оператор DO (PostgreSQL 9.0+) с EXECUTE.

  • Обратите внимание на использование функции pg_get_function_identity_arguments() и 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, но я здесь этого не делал, поскольку это делает функцию еще более опасной.

Связано:

0 голосов
/ 28 сентября 2017
-- 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();
0 голосов
/ 25 апреля 2013

Моя версия без хранимой процедуры

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$$;
0 голосов
/ 30 ноября 2011

Для любого выражения 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;
0 голосов
/ 30 ноября 2011

Просто скопируйте + вставьте вывод вашего запроса в интерпретатор psql. Он будет запускать все команды, которые вы вставляете.

...