Bonjour,
Je mets ça là, sans savoir si ça servira compte tenu de la version 2.5 concernée...
Mon propos concerne la contrainte NOT NULL et la façon dont elle est gérée en interne par le SGBD.
Je développe un petit couteau suisse pour gérer des trucs sur des bases FB avec UIB. J'affiche ainsi dans un grid la structure d'une table avec l'indication du NOT NULL pour les colonnes constituantes, avec pour ambition de modifier à la volée ce NOT NULL par 1 clic sur la checkbox correspondante.
En première intention, je me fiais à la propriété "NotNull" (booléen) de chaque champ, telle que proposée par les Metadatas UIB, pour cocher ou pas cette case. Restait plus qu'à trouver les bonnes commandes pour procéder 
Une rapide recherche et je me lance, pas d'erreur dans les commandes, et dès le 1er essai pour supprimer le NOT NULL, success!
La table:
1 2 3 4 5 6 7
| CREATE TABLE TATA (
COL1 INTEGER NOT NULL,
COL2 VARCHAR(5) NOT NULL
);
ALTER TABLE TATA
ADD PRIMARY KEY (COL1)
USING INDEX RDB$PRIMARY4; |
et pour récupérer la contrainte sur COL2 :
1 2 3 4 5 6 7
| select rc.rdb$constraint_name
from rdb$relation_constraints rc
inner join rdb$check_constraints cc
on rc.rdb$constraint_name = cc.rdb$constraint_name
where rc.rdb$constraint_type = 'NOT NULL'
and rc.rdb$relation_name = 'TATA'
and cc.rdb$trigger_name = 'COL2' |
débouchant sur
ALTER TABLE TATA DROP CONSTRAINT INTEG_13
Je relance mon couteau suisse, c'est OK, la case de COL2 n'est plus cochée.
Remettons donc en place cette contrainte, c'est tellement facile :
ALTER TABLE TATA ADD CONSTRAINT COL2NN CHECK (COL2 IS NOT NULL)
Je rafraichis les Metadatas UIB et ... la case n'est pas cochée 
Je fouille dans les tables système, je vois bien une contrainte avec le nom attribué (COL2NN), mais mais ... rdb$constraint_type n'est pas 'NOT NULL' mais 'CHECK' et attends ... il y a 2 contraintes en fait qui adressent 2 triggers (1 before insert et 1 before update) et il faut aller dans le source des triggers pour trouver une référence à COL2 et s'assurer que ça concerne bien le NOT NULL.
La cause ?
Tellement triviale : je vous sers le SQL permettant de reconstruire la table (produit par UIB)
1 2 3 4 5 6 7 8 9
| CREATE TABLE TATA (
COL1 INTEGER NOT NULL,
COL2 VARCHAR(5)
);
ALTER TABLE TATA
ADD PRIMARY KEY (COL1);
ALTER TABLE TATA
ADD CONSTRAINT COL2NN
CHECK (COL2 IS NOT NULL); |
Il n'aura pas échappé à votre d’œil d'expert le subtil changement qui produit fonctionnellement une colonne COL2 avec la contrainte, tout comme précédemment.
Mais techniquement, ce n'est plus la même chose.
Du coup, le NotNull des UIB passe au travers, tout comme la jointure proposée par le Firebird Null Guide...
J'ai donc dû embarquer les 2 possibilités dans mon couteau suisse afin que, dans cas d'un NOT NULL installé par un ALTER, le résultat soit pertinent:
1 2 3 4 5 6 7 8 9 10
|
SELECT DISTINCT RC.RDB$CONSTRAINT_NAME
FROM RDB$RELATION_CONSTRAINTS RC
INNER JOIN RDB$CHECK_CONSTRAINTS CC
ON RC.RDB$CONSTRAINT_NAME = CC.RDB$CONSTRAINT_NAME
INNER JOIN RDB$TRIGGERS T
ON CC.RDB$TRIGGER_NAME = T.RDB$TRIGGER_NAME
WHERE RC.RDB$CONSTRAINT_TYPE = 'CHECK'
AND RC.RDB$RELATION_NAME = 'TATA'
AND T.RDB$TRIGGER_SOURCE CONTAINING 'K (COL2 IS NOT NULL' |
Je n'ai pas regardé comment cela était traité dans versions suivantes de FB.
A bon entendeur !
NB: pas sûr de l'utilité du 2nd inner 
PS: concernant les UIB, il faut pour chaque "fields" de la MetatTable, mouliner sur tous les "checks" pour vérifier la présence d'une référence NOT NULL pour ce fields:
1 2 3 4 5 6 7 8 9
|
if Fields[j].NotNull then // lors du create de la table
GridStructure.Cell[8,i].AsBoolean:=True
else
for z:=0 to ChecksCount-1 do // via un ALTER
if Pos('K ('+Fields[j].Name+' IS NOT NULL',checks[z].Constraint)<>0 then begin
GridStructure.Cell[8,i].AsBoolean:=True;
Break;
end; |
Partager