Fonction DROP sans connaître le nombre / type de paramètres?

je garde toutes mes fonctions dans un fichier texte avec 'CREATE OR REPLACE FUNCTION somefunction' . Donc, si j'ajoute ou modifie une fonction, je donne juste le fichier à psql.

maintenant si j'ajoute ou supprime des paramètres à une fonction existante, cela crée une surcharge avec le même nom et pour supprimer l'original j'ai besoin de taper tous les types de paramètres dans l'ordre exact qui est un peu fastidieux.

est-ce qu'il y a une sorte de Joker que je peux utiliser pour supprimer toutes les fonctions avec un nom donné pour que je puisse il suffit d'ajouter les lignes DROP FUNCTION en haut de mon fichier?

37
demandé sur Kara 2011-10-02 00:54:07

5 réponses

vous auriez besoin d'écrire une fonction qui a pris le nom de la fonction, et regardé chaque surcharge avec ses types de paramètres de information_schema , puis construit et exécuté un DROP pour chacun.

EDIT: Ce qui s'est avéré être beaucoup plus difficile que je ne le pensais. Il semble que information_schema ne garde pas les informations paramétriques nécessaires dans son catalogue routines . Vous devez donc utiliser les tables supplémentaires de PostgreSQL pg_proc et pg_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;

j'ai testé avec succès sur une fonction surchargée. Il a été assemblé assez rapidement, mais fonctionne très bien comme une fonction utilitaire. Je recommande de tester davantage avant de l'utiliser en pratique, au cas où j'aurais oublié quelque chose.

19
répondu Paul Bellora 2011-10-01 21:58:52

recherche de Base

cette requête crée toutes les déclarations DDL nécessaires (simplifié avec cast à 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écute les commandes (après un contrôle de plausibilité).

le nom de la fonction est sensible à la casse et ne comporte pas de guillemets lorsqu'il est passé sous le paramètre text pour correspondre à pg_proc.proname .

the cast to the object identifier type regprocedure ( oid::regprocedure ) rend tous les identificateurs sûrs contre l'injection SQL (par le biais d'identificateurs mal formés malicieusement). Lors de la conversion en text , le nom de la fonction est double-cité et qualifié de schéma selon le courant search_path automatiquement si nécessaire.

pg_function_is_visible(oid) restreint la sélection aux fonctions dans le courant search_path . Vous pouvez ou ne voulez pas que. 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 divers arguments de fonction, 1519510920" tous de ceux-ci seront énumérés séparément. Vous pouvez limiter schéma spécifique(s) ou d'une fonction spécifique paramètre(s), après tout.

Related:

fonction

vous pouvez construire une fonction plpgsql pour exécuter les instructions immédiatement avec EXECUTE . Pour Postgres 9.1 ou plus tard: attention! Il lâche 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 simplement:

SELECT f_delfunc('my_function_name');

de cette façon, vous n'obtiendrez pas la colonne nom func_dropped pour la colonne Résultat. Peut pas d'importance pour vous.

la fonction renvoie le nombre de fonctions trouvées et supprimées (aucune exception Elevée) - 0 si aucune n'a été trouvée.

il suppose un (par défaut) search_pathpg_catalog n'a pas été déplacé.

Plus dans ces réponses liées:

pour les versions Postgres Plus anciennes que 9.1 ou plus anciennes de la fonction en utilisant regproc et pg_get_function_identity_arguments(oid) vérifier l'historique éditer de cette réponse.

56
répondu Erwin Brandstetter 2017-09-24 15:51:48

Amélioration de l'original réponse afin de prendre schema en compte, 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';
3
répondu Сухой27 2017-07-06 06:29:20

version légèrement améliorée de la réponse D'Erwin. En outre, les supports suivant

  • 'comme' au lieu de la fonction exacte correspondance de nom
  • peut exécuter en 'dry-mode' et 'trace' le SQL pour enlever les fonctions

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');
0
répondu Xtra Coder 2016-04-03 09:50:55

Voici la requête que j'ai construite en haut de la solution @Сухой27 qui génère des instructions sql pour laisser tomber 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);
0
répondu Bo Guo 2018-01-07 20:18:47