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

#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 ... sad 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)

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 smile


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

gleu a écrit :

Le SQL est un standard. L'implémentation des différents moteurs, c'est une autre histoire smile

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 smile


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 smile

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 ? hmm

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) smile

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

ofthestreet a écrit :

:'( 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)

Hors ligne

Pied de page des forums