Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
Pages : 1
#1 21/12/2011 16:12:25
- ofthestreet
- Membre
Garder INTEGER comme type boolean
Pour des raisons de portabilité, j'aimerai conserver integer comme type primitif pour mes booléen.
Je me heurte à des problèmes de cast lors de false ou true. Le code suivant ne marche pas :
drop table Tutu;
create table Tutu (isNull_ INTEGER);
insert into Tutu Values(false);
ERREUR: la colonne "isnull_ " est de type integer mais l'expression est de type boolean
LIGNE 1 : insert into Tutu Values(false);
^
ASTUCE : Vous devez réécrire l'expression ou lui appliquer une transformation de type.
il me faut écrire :
drop table Tutu;
create table Tutu (isNull_ INTEGER);
insert into Tutu Values(cast(false as integer));
Cela m'oblige à modifier le code, ce que j'aimerai éviter.
J'ai essayé les cast lors de l'assignement, sans y arriver :
create cast (boolean as INTEGER) WITH FUNCTION int4(boolean) AS ASSIGNMENT
> ERREUR: la conversion du type boolean vers le type integer existe déjà
Comment faire pour que false et true soit systématiquement transformé en entier ?
Est il possible de changet le type boolean en entier ?
merci
Hors ligne
#2 21/12/2011 17:56:40
- gleu
- Administrateur
Re : Garder INTEGER comme type boolean
Non et non. Un booléen n'est pas un entier et inversement. Je comprends que ce serait plus simple ainsi mais ça apporte aussi son lot d'erreurs. À partir de la version 8.3, PostgreSQL a considérablement renforcé le respect des types en supprimant un certain nombre de conversions implicites qui pouvaient se révéler dangereuses. D'où le fait que la conversion booléen vers entier existe, mais pas de façon implicite.
Guillaume.
Hors ligne
#3 21/12/2011 18:47:58
- flo
- Membre
Re : Garder INTEGER comme type boolean
Salut gleu,
C'est un problème souvent rencontré lors des migrations j'ai l'impression (à partir de bases de données qui ne connaissent pas le type booléen, quel dommage...).
Du coup, on est obligé de réécrire toutes les requêtes.
Y'a pas de truc ou d'astuce alors?
(il me semble que le problème c'est que le driver JDBC d'Oracle convertit automatiquement les booléens en entiers, d'où les problèmes de migration ensuite. À vérifier)
Hors ligne
#4 21/12/2011 18:51:54
- ofthestreet
- Membre
Re : Garder INTEGER comme type boolean
:'( bouh bouh, va falloir modifier du code pour se connecter à postgresql malgré une compatibilité avec h2/sybase/oracle/sqlserver
NOTE : pour mysql, c'est une autre galère ... le sql c'est vraiment pas un standard ...
Hors ligne
#5 21/12/2011 19:04:02
- rjuju
- Administrateur
Re : Garder INTEGER comme type boolean
Il ne serait pas possible de modifier le nom de la table sous postgres, et d'utiliser le nom original pour créer une vue qui casterait explicitement le type entier en booléen, et ensuite créer une règle ou un trigger sur insertion/modification avec encore une conversion explicite de booléen vers entier ?
Si le nombre de tables impactées est grand, ça peut être lourd à mettre en place mais ça éviterait de modifier le code ?
Dernière modification par rjuju (21/12/2011 19:05:05)
Julien.
https://rjuju.github.io/
Hors ligne
#6 21/12/2011 22:12:26
- gleu
- Administrateur
Re : Garder INTEGER comme type boolean
Le SQL est un standard. L'implémentation des différents moteurs, c'est une autre histoire
Guillaume.
Hors ligne
#7 22/12/2011 10:16:44
- Marc Cousin
- Membre
Re : Garder INTEGER comme type boolean
En fait, il y a une méthode un peu sataniste pour rendre les casts entre integer et boolean implicites, à base de mises à jour de catalogues systèmes. Mais c'est toujours déconseillé de mettre à jour les tables systèmes (surtout pour rendre implicites des casts qui ne le sont pas en temps normal), et non supporté surtout.
Marc.
Hors ligne
#8 22/12/2011 11:16:58
- flo
- Membre
Re : Garder INTEGER comme type boolean
Le SQL est un standard. L'implémentation des différents moteurs, c'est une autre histoire
Oui, ma remarque était purement pratique : quand on tombe dans ce genre de problème, comment faire pour que cela impacte le moins possible le code? (dans le cas où on ne supporte qu'un moteur)
En pratique, pour ofthestreet qui doit gérer plusieurs moteurs dans le même code, si j'ai bien compris, je ferais plutôt la conversion booléen <-> entiers dans le code de l'application et je gèrerais tout avec des INTEGER en base. C'est pas très beau, mais au moins ce sera le même code pour tous les moteurs.
Hors ligne
#9 22/12/2011 11:22:33
- gleu
- Administrateur
Re : Garder INTEGER comme type boolean
Je pense que je ferais comme toi si je devais développer un outil multi-bases. Mais comme je pense qu'il n'y a aucune bonne raison de faire ça, je ne risque pas de me poser la question
Guillaume.
Hors ligne
#10 22/12/2011 11:50:46
- ofthestreet
- Membre
Re : Garder INTEGER comme type boolean
@flo
Ceci pose de cout de portage de code.
Tu me diras si le code est bien foutu, ceci devrait être concentré dans certaines classes.
N'y a t il pas un setting de guru dans postgres qui permettrait de impliciter false à 0 et true à 1 ?
Comment fait postgres pour reconnaitre 'y', 'yes', 'true', 't', 1 comme boolean ?
Si il est capable de faire ces cast de façon implicite ... ne pourrait on pas lui dire .. heu non non Mr Postgres, false, c'est désormais l'entier 1 ?
Hors ligne
#11 22/12/2011 11:54:27
- Marc Cousin
- Membre
Re : Garder INTEGER comme type boolean
Bon, méthode de «gourou», non supportée parce qu'on tripote directement une table système:
UPDATE pg_cast SET castcontext = 'i' WHERE oid IN (
SELECT c.oid
FROM pg_cast c
inner join pg_type src ON src.oid = c.castsource
inner join pg_type tgt ON tgt.oid = c.casttarget
WHERE src.typname LIKE 'bool%' AND tgt.typname LIKE 'int%'
);
=> Ça rend le cast de booleen vers entier implicite.
Après, insert into Tutu Values(cast(false as integer)); passe (0=false, 1=true)
Si on veut aussi un cast implicite dans l'autre sens, il faut évidemment inverser le src et le tgt dans la requête.
Mais c'est non supporté: on a fait un update sur une table système.
Marc.
Hors ligne
#12 22/12/2011 12:26:39
- gleu
- Administrateur
Re : Garder INTEGER comme type boolean
Par "non supporté", Marc veut dire : s'il vous arrive des bricoles à cause de ça, vous ne pouvez vous en prendre qu'à vous-même.
Guillaume.
Hors ligne
#13 22/12/2011 12:29:20
- Marc Cousin
- Membre
Re : Garder INTEGER comme type boolean
Oui, ça n'annule pas le contrat de support
Si vous avez des bizarreries dans des requêtes, il faudra toujours garder à l'esprit que vous avez fait cette manipulation, et essayer de reproduire le problème sans.
Marc.
Hors ligne
#14 22/12/2011 12:37:59
- ofthestreet
- Membre
Re : Garder INTEGER comme type boolean
Hi tom lane,
j'ai vu ta remarque (http://archives.postgresql.org/pgsql-ge … g00866.php) comme quoi c'est pas bien de modifier les tables internes de postgres, mais avec une conversion implicite à l'assignement faite par update de la table pg_cast, ca me permet d'utiliser false et true sur des integers :
-- http://docs.postgresql.fr/8.4/catalog-pg-cast.html
update pg_cast set castcontext = 'a' where oid in (
select c.oid
from pg_cast c
inner join pg_type src on src.oid = c.castsource
inner join pg_type tgt on tgt.oid = c.casttarget
where src.typname = 'bool' and tgt.typname = 'int4');
drop table Tutu;
create table Tutu (isNull_ INTEGER);
insert into Tutu Values(false);
Vais je au devant d'emmerde sans nom ?
Hors ligne
#15 22/12/2011 12:44:50
- Marc Cousin
- Membre
Re : Garder INTEGER comme type boolean
Il ne s'agit pas d'emmerdes sans nom. Le nom de l'emmerde est "operator is not unique", comme l'explique Tom Lane dans ce mail (et beaucoup d'autres, c'est une question qui revient régulièrement)
Bref, comme je disais au dessus: ça résout le problème, mais ça peut en créer d'autres (tordus). D'où le choix de quand même poster la «solution« ici, mais avec un gros avertissement.
Marc.
Hors ligne
#16 22/12/2011 17:50:16
- dverite
- Membre
Re : Garder INTEGER comme type boolean
:'( bouh bouh, va falloir modifier du code pour se connecter à postgresql malgré une compatibilité avec h2/sybase/oracle/sqlserver
Le code cité en exemple ne passe pas sous oracle non plus:
SQL> create table Tutu (isNull_ INTEGER);
Table created.
SQL> insert into Tutu Values(false);
insert into Tutu Values(false)
*
ERROR at line 1:
ORA-00984: column not allowed here
Autant pour la compatibilité inter-SGBD, le principe d'utiliser des entiers au lieu des booléens se tient tout à fait, autant une fois qu'on a fait ce choix, que vient faire le mot clef false dans une requête? C'est lui qui n'est pas supporté par tous les SGBDs, et plus généralement le concept de valeur booléenne en SQL (select 1=1 from dual ne fonctionne pas non plus)
@DanielVerite
http://blog-postgresql.verite.pro/
Hors ligne
Pages : 1