PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 26/04/2018 12:22:06

Mlan2
Membre

Pusieurs occurences de fonctions présentes.

Bonjour,

Lors d'une revue de code, j'ai listé l'ensemble des fonctions utilisées dans notre développement, et je me suis étonné de la présence de doublons de fonctions portant le même nom.

J'ai bien noté que des fonctions de même nom ayant des paramètres différents faisaient l'objet de fonctions différentes. En listant ces fonctions en doublons, et en affichant également leurs paramètres, je constate qu'ils sont identiques pour chacune des fonctions en doublon.

Aussi, je m'interroge sur la présence de ces doublons de fonctions. Celles-ci ont également le même type de retour.

Comment expliquer alors la présence de ces doublons. (présentes dans le même schéma et associées au même utilisateur).

Voici le code utilisé pour lister ces fonctions :

DO
$$
DECLARE
 r record;
 user_name       VARCHAR      (255);
 schema_name     VARCHAR      (255);
 Function_Name   VARCHAR      (255);
 
 parg        TEXT;
 
BEGIN
  user_name       := 'xxxx';                         -- Le propriétaire
  schema_name     := 'yyyy';                         -- Le schema original
  
  FOR r IN SELECT p.proname, p.proowner, p.pronamespace
             FROM pg_proc p
            WHERE (p.proowner     = (select u.usesysid
                                       From  pg_user u
                                      Where (u.usename = user_name)))
              AND (p.pronamespace = (select oid from pg_namespace
                                      Where (nspname = schema_name)))
          ORDER BY p.proname
  LOOP
    Select pg_get_function_arguments (f.oid) into parg from pg_proc f where f.proname=r.proname;
    RAISE NOTICE 'Nom de la fonction (%), (%)', r.proname, parg;
  END LOOP;

END;
$$;

Si je veux éditer une de ces fonctions depuis une session psql par la commande : \ef <ma fonction>, je ne peux le faire car il m'indique qu'il y a plus d'une fonction de ce nom.

D'ailleurs, comment pourrait t'on faire pour éditer une des fonctions en doublon par la commande : \ef <Ma fonction> ?


D'avance merci de votre retour.

Cordialement.

Hors ligne

#2 26/04/2018 14:07:26

dverite
Membre

Re : Pusieurs occurences de fonctions présentes.

Effectivement il n'est pas possible d'avoir dans le même schéma deux fonctions de même nom et mêmes arguments.

Il y a d'ailleurs un index unique dans pg_proc qui l'empêche:
  "pg_proc_proname_args_nsp_index" UNIQUE, btree (proname, proargtypes, pronamespace)

Si je comprends bien la question, le code montré sort ces RAISE NOTICE avec des doublons,
mais c'est parce qu'il y a une erreur logique  dans
  Select pg_get_function_arguments (f.oid) into parg from pg_proc f where f.proname=r.proname;
ce SELECT renvoie plusieurs résultats par r.proname.

Ce qu'il faudrait faire c'est
...
FOR r IN SELECT p.oid, p.proname, p.proowner, p.pronamespace
...
  Select pg_get_function_arguments (f.oid) into parg from pg_proc f where f.oid = r.oid;

puisque la clef primaire de pg_proc est pg_proc.oid, pas proname.


Pour ce qui est de \ef il faut préciser les types des arguments,par exemple \ef mafonction(text,int)

Dernière modification par dverite (26/04/2018 14:08:31)

Hors ligne

#3 26/04/2018 15:37:40

Mlan2
Membre

Re : Pusieurs occurences de fonctions présentes.

Merci de la réponse.

J'ai rejoué le code en tenant compte de ta remarque, mais le résultat est identique.

DO
$$
DECLARE
 r record;
 user_name       VARCHAR      (255);
 schema_name     VARCHAR      (255);
 Function_Name   VARCHAR      (255);
 
 parg        TEXT;
 
BEGIN
  user_name       := 'xxxx';                         -- Le propriétaire
  schema_name     := 'yyyy';                         -- Le schema original
  
  FOR r IN SELECT p.proname, p.proowner, p.pronamespace
             FROM pg_proc p
            WHERE (p.proowner     = (select u.usesysid
                                       From  pg_user u
                                      Where (u.usename = user_name)))
              AND (p.pronamespace = (select oid from pg_namespace
                                      Where (nspname = schema_name)))
          ORDER BY p.proname
  LOOP
    Select pg_get_function_arguments (f.oid) into parg from pg_proc f where f.oid = r.oid;
--  RAISE NOTICE 'Nom de la fonction (%), (%)', r.proname, parg;
    RAISE NOTICE 'Nom de la fonction (%)', r.proname;
  END LOOP;

END;
$$;

Ci-dessous, le résultat obtenu (extrait) :

NOTICE:  Nom de la fonction (fn_icont)
NOTICE:  Nom de la fonction (fn_icont)
NOTICE:  Nom de la fonction (fn_reconcimat)
NOTICE:  Nom de la fonction (fn_reconcimat)

As tu une autre piste ?

D'avance merci de ton retour.

Hors ligne

#4 26/04/2018 16:21:32

dverite
Membre

Re : Pusieurs occurences de fonctions présentes.

Ce bloc fait une erreur pour moi:

ERROR:  record "r" has no field "oid"
CONTEXT:  SQL statement "Select pg_get_function_arguments (f.oid)           from pg_proc f where f.oid = r.oid"
PL/pgSQL function inline_code_block line 23 at SQL statement


ce qui est logique puisque r est alimenté par
  FOR r IN SELECT p.proname, p.proowner, p.pronamespace
             FROM pg_proc p

et qu'il n'y a pas d'oid derrière ce SELECT, il faut justement l'ajouter.

Hors ligne

#5 26/04/2018 16:48:19

Mlan2
Membre

Re : Pusieurs occurences de fonctions présentes.

Merci du retour.

Je suis étonné comme vous de ne pas avoir d'erreur à l'exécution. Il me parait logique en effet d'ajouter le champ oid dans le record "r", ce que j'ai d'ailleurs fait dans le code ci-dessous, et le résultat fourni (sans erreur) :

xxxx=> DO
xxxx-> $$
xxxx$> DECLARE
xxxx$>  r record;
xxxx$>  user_name       VARCHAR      (255);
xxxx$>  schema_name     VARCHAR      (255);
xxxx$>  Function_Name   VARCHAR      (255);
xxxx$>
xxxx$>  parg        TEXT;
xxxx$>
xxxx$> BEGIN
xxxx$>   user_name       := 'xxxx';                         -- Le propriétaire
xxxx$>   schema_name     := 'yyyy';                         -- Le schema original
xxxx$>
xxxx$>   FOR r IN SELECT p.oid, p.proname, p.proowner, p.pronamespace
xxxx$>              FROM pg_proc p
xxxx$>             WHERE (p.proowner     = (select u.usesysid
xxxx$>                                        From  pg_user u
xxxx$>                                       Where (u.usename = user_name)))
xxxx$>               AND (p.pronamespace = (select oid from pg_namespace
xxxx$>                                       Where (nspname = schema_name)))
xxxx$>           ORDER BY p.proname
xxxx$>   LOOP
xxxx$>     Select pg_get_function_arguments (f.oid) into parg from pg_proc f where f.oid = r.oid;
xxxx$> --  RAISE NOTICE 'Nom de la fonction (%), (%)', r.proname, parg;
xxxx$>     RAISE NOTICE 'Nom de la fonction (%)', r.proname;
xxxx$>   END LOOP;
xxxx$>
xxxx$> END;
xxxx$> $$;
NOTICE:  Nom de la fonction (fn_icont)
NOTICE:  Nom de la fonction (fn_icont)
NOTICE:  Nom de la fonction (fn_reconcimat)
NOTICE:  Nom de la fonction (fn_reconcimat)
DO
xxxx=>

Le code est exécuté par psql depuis une fenêtre putty.

Hors ligne

#6 26/04/2018 16:57:59

dverite
Membre

Re : Pusieurs occurences de fonctions présentes.

Mais maintenant il ne doit plus y avoir de doublons, en considérant le couple (proname,parg).

Sur le schéma pg_catalog, voici ce que ça me sort (juste la fin) en mettant le RAISE NOTICE qui va bien

...
NOTICE:  Nom de la fonction (xmlconcat2), (xml, xml)
NOTICE:  Nom de la fonction (xmlexists), (text, xml)
NOTICE:  Nom de la fonction (xmlvalidate), (xml, text)
NOTICE:  Nom de la fonction (xpath), (text, xml, text[])
NOTICE:  Nom de la fonction (xpath), (text, xml)
NOTICE:  Nom de la fonction (xpath_exists), (text, xml, text[])
NOTICE:  Nom de la fonction (xpath_exists), (text, xml)
DO

On voit bien par exemple que xpath() a deux définitions, mais avec des arguments différents.

Hors ligne

#7 26/04/2018 17:23:53

Mlan2
Membre

Re : Pusieurs occurences de fonctions présentes.

Merci du retour.

En affichant dans le RAISE la liste des arguments, pour les fonctions en doublon, je constate bien à présent que les arguments sont différents, et que les doublons sont justifiés.

Une confirmation que je voudrai avoir cependant de votre part est que l'appel d'une des fonctions en doublon réalisé en passant les n paramètres de cette fonction exécutera bien le code de cette fonction, et non pas le code de la même fonction en doublon qui ne comporterait un nombre de paramètres différent de n.

D'avance merci de votre retour.

Merci de votre collaboration.

Hors ligne

#8 26/04/2018 18:34:02

dverite
Membre

Re : Pusieurs occurences de fonctions présentes.

Est-ce que ça ne revient pas à demander si Postgres est capable de gérer sa fonctionnalité de "surcharge" dans tous les cas? La réponse est oui, sinon on serait bien embêtés.
Il est vrai que si on prend tout en compte: cast implicites de types en d'autres types, arguments "variadiques", valeurs par défaut, ordre de priorités du search_path, arguments IN et OUT, l'algorithme qui doit trouver la bonne fonction est complexe, mais à ma connaissance il est  totalement déterministe.

Hors ligne

#9 26/04/2018 20:05:41

rjuju
Administrateur

Re : Pusieurs occurences de fonctions présentes.

Oui, et il interdit toute ambiguité

# create function f1(v1 text) returns void as $$
begin
raise notice 'test';
end; $$ language plpgsql;
CREATE FUNCTION

# create function f1(v1 text, v2 text default '') returns void as $$
begin
raise notice 'test';
end; $$ language plpgsql;

# select f1('test'::text);
ERROR:  42725: function f1(text) is not unique
LINE 1: select f1('test'::text);
               ^
HINT:  Could not choose a best candidate function. You might need to add explicit type casts.

Hors ligne

#10 27/04/2018 07:58:08

Mlan2
Membre

Re : Pusieurs occurences de fonctions présentes.

Merci à tous pour cet éclairage.

Hors ligne

#11 27/04/2018 08:13:10

Mlan2
Membre

Re : Pusieurs occurences de fonctions présentes.

Dernière petite question,

Dans les échanges avec dverite, j'avais modifié le code en changeant le critère de recherche des arguments de (where f.proname=r.proname) par (where f.oid=r.oid) sans référencer le champ oid dans la liste des champs du record "r"

dverite obtenait une erreur, et moi non.

Celà voudrait t'il dire qu'un champ oid serait créé implicitement si ce champ n'était pas indiqué ?

Le comportement différent serait t'il lié à un paramètre de configuration particulier ?

Dans l'attente de votre retour.

Hors ligne

#12 27/04/2018 15:09:58

dverite
Membre

Re : Pusieurs occurences de fonctions présentes.

Il faudrait savoir si c'est reproductible et avec quelle version de PostgreSQL?

Hors ligne

Pied de page des forums