Je garde toutes mes fonctions dans un fichier texte avec 'CREATE OR REPLACE FUNCTION somefunction'
. Donc, si j'ajoute ou modifie une fonction, je nourris simplement le fichier dans psql.
Maintenant, si j'ajoute ou supprime des paramètres à une fonction existante, cela crée une surcharge avec le même nom et supprime le type d'origine nécessaire dans tous les types de paramètres dans l'ordre exact, ce qui est fastidieux.
Existe-t-il une sorte de caractère générique que je peux utiliser pour supprimer toutes les fonctions portant le même nom afin que je puisse simplement ajouter des lignes DROP FUNCTION
en haut de mon fichier?
Vous devez écrire une fonction qui prend le nom de la fonction et examine chaque surcharge avec ses types de paramètres à partir de information_schema
, puis crée et exécute une DROP
pour chacun.
EDIT: / Cela s'est avéré être beaucoup plus difficile que je pensais. Il semble que information_schema
ne conserve pas les informations de paramètre nécessaires dans son catalogue routines
. Vous devez donc utiliser les tables supplémentaires pg_proc
et pg_type
de PostgreSQL:
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;
Je l'ai testé avec succès sur une fonction surchargée. Il a été assemblé assez rapidement, mais fonctionne très bien comme fonction d’utilité. Je recommanderais de tester davantage avant de l'utiliser dans la pratique, au cas où j'oublierais quelque chose.
Cette requête crée toutes les instructions DDL nécessaires (simplifiées avec la conversion en 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
Sortie:
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);
Exécutez les commandes (après un contrôle de plausibilité).
Le nom de la fonction est sensible à la casse et ne contient pas de guillemets doubles lorsqu'il est transmis en tant que paramètre text
à faire correspondre à pg_proc.proname
.
Le transtypage en type d'identifiant d'objet regprocedure
(oid::regprocedure
) rend tous les identifiants safe contre l'injection SQL (au moyen d'identifiants malformés). Lors de la conversion en text
, le nom de la fonction est cité entre guillemets et qualifié du schéma conformément au search_path
automatiquement le cas échéant.
pg_function_is_visible(oid)
restreint la sélection aux fonctions du search_path
actuel. Vous pouvez ou non vouloir cela. Avec la condition pg_function_is_visible(oid)
en place, la fonction est garantie d'être visible.
Si vous avez plusieurs fonctions du même nom dans plusieurs schémas ou des fonctions surchargées avec différents arguments de fonction, tous parmi ceux-ci seront listés séparément. Vous souhaiterez peut-être limiter certains schémas ou fonctions spécifiques après tout.
En relation:
Vous pouvez créer une fonction plpgsql
autour de celle-ci pour exécuter les instructions immédiatement avec EXECUTE
. Pour Postgres 9.1 ou ultérieur: Attention! Il laisse tomber vos fonctions!
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;
Appel:
SELECT * FROM f_delfunc('my_function_name');
Ou juste:
SELECT f_delfunc('my_function_name');
De cette façon, vous n'obtenez pas la colonne nomfunc_dropped
pour la colonne de résultat. Peu importe pour vous.
La fonction renvoie le nombre de fonctions trouvées et supprimées (aucune exception n'a été déclenchée) - 0
si aucune n'a été trouvée.
Cela suppose un (code par défaut) search_path
où pg_catalog
n'a pas été déplacé.
Plus dans ces réponses connexes:
Pour les versions de Postgres antérieures à la version 9.1 ou antérieures, les variantes de la fonction utilisant regproc
et pg_get_function_identity_arguments(oid)
vérifient l'historique des modifications de cette réponse.
Amélioration de l'original answer afin de prendre en compte schema
, c'est-à-dire. 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';
A partir de Postgres 10, vous pouvez supprimer des fonctions par nom uniquement, à condition que les noms soient uniques dans leur schéma. Placez simplement la déclaration suivante en haut de votre fichier de fonction:
drop function if exists my_func;
Documentation ici .
Voici la requête que j'ai construite sur la solution @ Сухой27 qui génère des instructions SQL permettant de supprimer toutes les fonctions stockées dans un schéma:
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);
Version légèrement améliorée de la réponse d'Erwin. Prend également en charge le suivi
Code pour copier/coller:
/**
* Removes all functions matching given function name mask
*
* @param p_name_mask Mask in SQL 'like' syntax
* @param p_opts Combination of comma|space separated options:
* trace - output SQL to be executed as 'NOTICE'
* dryrun - do not execute generated SQL
* @returns Generated SQL 'drop functions' string
*/
CREATE OR REPLACE FUNCTION mypg_drop_functions(IN p_name_mask text,
IN p_opts text = '')
RETURNS text LANGUAGE plpgsql AS $$
DECLARE
v_trace boolean;
v_dryrun boolean;
v_opts text[];
v_sql text;
BEGIN
if p_opts is null then
v_trace = false;
v_dryrun = false;
else
v_opts = regexp_split_to_array(p_opts, E'(\\s*,\\s*)|(\\s+)');
v_trace = ('trace' = any(v_opts));
v_dryrun = ('dry' = any(v_opts)) or ('dryrun' = any(v_opts));
end if;
select string_agg(format('DROP FUNCTION %s(%s);',
oid::regproc, pg_get_function_identity_arguments(oid)), E'\n')
from pg_proc
where proname like p_name_mask
into v_sql;
if v_sql is not null then
if v_trace then
raise notice E'\n%', v_sql;
end if;
if not v_dryrun then
execute v_sql;
end if;
end if;
return v_sql;
END $$;
select mypg_drop_functions('fn_dosomething_%', 'trace dryrun');