Je me souviens avoir soulevé un point presque identique lorsque PG9 était en état alpha. Voici la réponse de Tom Lane (développeur de base PG de haut niveau) :
http://archives.postgresql.org/pgsql-general/2010-01/msg00221.php
En bref :ne résoudra pas.
Cela ne veut pas dire que je suis d'accord avec votre suggestion selon laquelle le comportement actuel est un bogue. Regardez-le sous l'angle opposé :c'est le comportement de NOT DEFERRABLE
c'est incorrect.
En fait, la violation de contrainte dans ce UPDATE ne devrait jamais se produire dans tous les cas, puisqu'à la fin du UPDATE la contrainte est satisfaite. L'état à la fin de la commande est ce qui compte. Les états intermédiaires lors de l'exécution d'une seule instruction ne doivent pas être exposés à l'utilisateur.
Il semble que PostgreSQL implémente la contrainte non différée en vérifiant les doublons après chaque mise à jour de ligne et en échouant immédiatement après le premier doublon, ce qui est essentiellement défectueux. Mais c'est un problème connu, probablement aussi vieux que PostgreSQL. De nos jours, la solution de contournement consiste précisément à utiliser une contrainte DEFERRABLE. Et il y a une certaine ironie dans le fait que vous le considérez comme déficient parce qu'il échoue, alors qu'il est censé être la solution à l'échec en premier lieu !
Résumé du statu quo depuis PostgreSQL 9.1
-
NOT DEFERRABLE
UNIQUE
ouPRIMARY KEY
les contraintes sont vérifiées après chaque ligne . -
DEFERRABLE
contraintes définies surIMMEDIATE
(INITIALLY IMMEDIATE
ou viaSET CONSTRAINTS
) sont vérifiés après chaque instruction . -
DEFERRABLE
contraintes définies surDEFERRED
(INITIALLY DEFERRED
ou viaSET CONSTRAINTS
) sont vérifiés après chaque transaction .
Notez le traitement spécial de UNIQUE
/ PRIMARY KEY
contraintes.Citer la page de manuel pour CREATE TABLE
:
Une contrainte non reportable sera vérifiée immédiatement après chaque commande .
Bien qu'il soit indiqué plus bas dans la Compatibilité sous Non-deferred uniqueness constraints
:
Lorsqu'un
UNIQUE
ouPRIMARY KEY
la contrainte n'est pas reportable, PostgreSQL vérifie l'unicité immédiatement chaque fois qu'une ligne est insérée ou modifiée. La norme SQL indique que l'unicité doit être forcée uniquement à la fin de l'instruction; cela fait une différence lorsque, par exemple, une seule commande met à jour plusieurs valeurs de clé. Pour obtenir un comportement conforme à la norme, déclarez la contrainte commeDEFERRABLE
mais non différé (c'est-à-direINITIALLY IMMEDIATE
). Sachez que cela peut être beaucoup plus lent que la vérification immédiate de l'unicité.
J'insiste sur moi.
Si vous avez besoin d'une FOREIGN KEY
contraintes pour référencer la ou les colonnes, DEFERRABLE
n'est pas une option car (selon la documentation) :
Les colonnes référencées doivent être les colonnes d'une contrainte de clé unique ou primaire non différée dans la table référencée.