Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
#1 08/02/2017 19:31:43
- ail
- Membre
[Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
Bonjour,
J'ai migré une application d'un serveur RHEL 5 vers une RHEL 6.5 et donc d'une base PostgreSQL 8.4.2 vers une PostgreSQL 9.5.4.
Je rencontre un problème lors de l'appel d'une fonction stockée dont le prototype est de la forme :
CREATE OR REPLACE FUNCTION ma_fonction(int4)
L'erreur que j'ai est la suivante :
ERREUR: la fonction ma_fonction(bigint) n'existe pas au caractère ..
ASTUCE : Aucune fonction ne correspond au nom donné et aux types d'arguments.
Je l'appelle depuis un code C++ en lui passant un long en argument.
Ceci ne posait pas de problème auparavant, même sur une machine 64 bits.
J'ai pu résoudre le problème en faisant un cast dans le code C++ vers un int32_t, mais je me pose plusieurs questions :
1/ Comment se fait il que je n'ai pas vu d'autres erreurs de ce type alors que de nombreuses fonctions stockées sont définies avec des paramètres déclarés en int4, et appelées avec des long en paramètre ?
2/ Pourquoi cette différence de comportement entre une version 8.4 et une version 9.5 ? (je n'ai rien vu dans les release notes)
3/ Existe-t-il une façon de forcer un cast pour ce type de paramètres ?
Merci
Dernière modification par ail (10/02/2017 10:25:55)
Hors ligne
#2 09/02/2017 11:57:41
- Marc Cousin
- Membre
Re : [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
Bonjour,
J'imagine qu'initialement le code avait été compilé en 32 bits, même si déployé sur une machine 64 bits, ou quelque chose du genre. Pour le reste, impossible de vous répondre avec si peu d'information… il y a forcément une différence de comportement quelque part, mais je pense que ce n'est pas au niveau de Postgres. Il n'y a normalement pas de changement de comportement des casts entre 8.4 et 9.5 de bigint vers int. Dans les deux, le cast bigint -> int est déclaré comme AS ASSIGNMENT (https://www.postgresql.org/docs/9.5/sta … ecast.html)
Marc.
Hors ligne
#3 09/02/2017 12:24:12
- ail
- Membre
Re : [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
Bonjour,
Merci pour cette réponse.
Je viens de vérifier, le code avait été compilé en 64 bits.
En lisant cette page : https://www.postgresql.org/docs/9.5/sta … -func.html, j'avais compris que PostgreSQL cherchait dans la mesure du possible à faire un cast sur le nom de la fonction appelée
Existe-t-il une différence de traitement du cast entre la 8.4 et la 9.5, ou bien une manière de configurer les types de cast que peut faire PostreSQL ?
Merci
Hors ligne
#4 09/02/2017 16:24:03
- Marc Cousin
- Membre
Re : [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
En 8.4 comme en 9.5, j'ai exactement le même comportement:
create function ma_function(toto int4) returns void language plpgsql as
$$
begin
return;
end;
$$
;
select ma_function(12);
ma_function
-------------
marc=# select ma_function(12::bigint);
ERROR: function ma_function(bigint) does not exist
LINE 1: select ma_function(12::bigint);
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Quand le code spécifie le type passé en paramètre (à coup de cast, ou d'opérateur ::, ou en précisant le type dans la préparation d'une requête préparée par exemple), ça ne marche pas. Ni en 8.4 ni en 9.5.
Il faudrait que le cast de bigint à integer soit «implicit», et pas «assignment», pour que ça marche. Peut-être que le catalogue système de la base de départ avait été bidouillé pour que ça marche (j'espère que non). Vous pouvez toujours le contrôler avec \dC dans psql
Marc.
Hors ligne
#5 09/02/2017 16:44:54
- dverite
- Membre
Re : [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
1/ Comment se fait il que je n'ai pas vu d'autres erreurs de ce type alors que de nombreuses fonctions stockées sont définies avec des paramètres déclarés en int4, et appelées avec des long en paramètre ?
Les éléments de réponse sont à trouver dans l'API / la bibliothèque C++ utilisée côté client pour s'interfacer avec le serveur. Certaines APIs vont injecter les paramètres textuellement dans la requête sans indication de type, auquel cas c'est le serveur qui déduit le type et le problème en question ne se produira pas. D'autres vont déduire le type SQL du type C++, en l'occurrence "long" si 8 octets correspond à [select oid from pg_type where typname='int8'] donc le type d'OID 20. Si la lib C++ utilise en sous-main PQexecParams() de libpq et met en dur 20 dans le tableau paramTypes, alors le serveur SQL se basera dessus et ça produira l'erreur en question s'il n'y pas de fonction acceptant bigint. La même différence peut se produire selon que les APIs clientes utilisent les prepared statements ou pas. Dans certains cas il y a un switch logiciel qui permet d'activer ou non les prepared statements parce que ça a des effets sur les performances par ailleurs, et parce que les paramètres ne peuvent pas être utilisés librement dans les requêtes DDL.
2/ Pourquoi cette différence de comportement entre une version 8.4 et une version 9.5 ? (je n'ai rien vu dans les release notes)
Un large changement de cast implicit a lieu en 8.3 mais pas après, et ça concernait surtout le sens texte->entier.
Voir http://petereisentraut.blogspot.fr/2008 … resql.html
3/ Existe-t-il une façon de forcer un cast pour ce type de paramètres ?
On peut créer des CAST implicites avec CREATE CAST mais dans le cas int8->int4, ça parait une mauvaise solution puisque la majorité des valeurs de la source ne pourraient pas être converties dans la destination.
Pour moi le plus logique serait de faire l'inverse, passer le paramètre de la fonction de int en bigint puisque la taille de ce paramètre est 64-bit côté client, et "qui peut le plus peut le moins".
Il est aussi possible d'avoir deux versions de la même fonction, une prenant int, l'autre bigint. Mais elles doivent renvoyer le même type.
@DanielVerite
http://blog-postgresql.verite.pro/
Hors ligne
#6 10/02/2017 10:25:27
- ail
- Membre
Re : [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
Bonjour,
Merci pour cette réponse, encore une chose que j'ignorais de PostgreSQL.
J'ai vérifié, il n'y a pas de différence entre les deux installations de PostgreSQL.
Par contre, ça m'a permis de mettre en évidence que le problème était ailleurs : une variable, qui dans certains cas n'est pas correctement initialisée, contient une valeur supérieure à 2^31, et qui donc ne tient pas dans un bigint.
En appelant ma fonction avec une valeur inférieure à 2^31, elle fonctionne sans problème, par contre, je reproduis bien la même erreur dès que la valeur passée en argument est supérieure à 2^31.
Désolé pour le dérangement et merci beaucoup pour le temps que vous avez bien voulu m'accorder.
Une dernière question cependant : j'ai eu beaucoup de mal à trouver des notes de migration d'une version à l'autre de PostgreSQL, où dois-je chercher de telles notes (si elles existent)
Encore merci
Hors ligne
#7 10/02/2017 10:40:10
- Marc Cousin
- Membre
Re : [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
Il y a deux sources: les release notes : https://www.postgresql.org/docs/9.6/static/release.html (il suffit de regarder celles des versions majeures)
Et sinon sur le wiki de PostgreSQL, il y a une série d'articles «what's new in postgresql x.y». Par exemple pour la 9.6: https://wiki.postgresql.org/wiki/NewIn96, qui sont plus accessibles…
Je ne pense pas qu'elles soient référencées sur une page précise du wiki… le mieux c'est encore une recherche google avec «what's new in postgresql» comme chaine de recherche.
Marc.
Hors ligne
#8 10/02/2017 10:41:31
- ail
- Membre
Re : [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint
Merci beaucoup !
Hors ligne