La contrainte définie DEFERRABLE INITIALLY IMMEDIATE est toujours DEFERRED?
En relation avec réponse je suis tombé sur un phénomène que je ne peut pas l'expliquer.
Version:
PostgreSQL 9.1.2 sur x86_64-unknown-linux-gnu, compilé par gcc-4.4.réel (Debian 4.4.5-8) 4.4.5, 64-bit
Envisager la démonstration suivante. Banc d'essai:
CREATE TEMP TABLE t (
id integer
,txt text
,CONSTRAINT t_pkey PRIMARY KEY (id) DEFERRABLE INITIALLY IMMEDIATE
);
INSERT INTO t VALUES
(1, 'one')
,(2, 'two');
1) mise à JOUR de l'énoncé de la modification de plusieurs lignes:
UPDATE t
SET id = t_old.id
FROM t t_old
WHERE (t.id, t_old.id) IN ((1,2), (2,1));
Il semble y avoir un bug dans l'implémentation actuelle? Le ci-dessus mise à JOUR fonctionne bien qu'il ne devrait pas. La contrainte est définie INITIALLY IMMEDIATE
et je n'utilise pas SET CONSTRAINTS
.
Suis-je raté quelque chose ou est-ce un (plutôt inoffensif) bug?
2) les Données de la modification de la CTE
Par conséquent, une modification de la CTE oeuvres, aussi, si elle échoue avec un NOT DEFERRED
pk:
WITH x AS (
UPDATE t SET id = 1 WHERE id = 2
)
UPDATE t SET id = 2 WHERE id = 1;
Je cite le manuel sur les expressions de table communes:
Les sous-états sont exécutées simultanément les uns avec les autres
et avec la requête principale. Par conséquent, lors de l'utilisation de données-modification de
états, l'ordre dans lequel les spécifiée mises à jour en fait
arriver, c'est imprévisible. Toutes les instructions sont exécutées avec la même
capture d'écran (voir Chapitre 13), de sorte qu'ils ne peuvent pas "voir" les uns et les autres effets
sur la cible des tables.
3) Plusieurs mise à JOUR des déclarations de transaction
Sans SET CONSTRAINTS
il échoue avec un UNIQUE violation - comme prévu:
BEGIN;
-- SET CONSTRAINTS t_pkey DEFERRED;
UPDATE t SET id = 2 WHERE txt = 'one';
UPDATE t SET id = 1 WHERE txt = 'two';
COMMIT;
source d'informationauteur Erwin Brandstetter
Vous devez vous connecter pour publier un commentaire.
Je me souviens avoir soulevé une presque identique à point quand PG9 était en état alpha. Ici, c'est la réponse de Tom Lane (haut-profil PG core developer):
http://archives.postgresql.org/pgsql-general/2010-01/msg00221.php
En bref: ne sera pas corrigé.
De ne pas dire que je suis d'accord avec votre suggestion que le comportement actuel est un bug. Regardez-le en face de l'angle: c'est le comportement de
NOT DEFERRABLE
qui est incorrect.En fait, la violation de la contrainte dans cette mise à JOUR ne devrait jamais se produire dans tous les cas, puisqu'à la fin de la mise à JOUR de la contrainte est satisfaite. L'état à la fin de la commande est ce qui compte. Les états intermédiaires au cours de l'exécution d'une seule instruction ne doit pas être exposé à l'utilisateur.
Il semble que l'PostgreSQL implémente le non reportable contrainte par le contrôle de doublon après chaque ligne mis à jour et, à défaut, immédiatement lors de la première double, qui est fondamentalement défectueux. Mais c'est un problème connu, probablement aussi vieille que PostgreSQL.
Aujourd'hui, la solution de contournement pour ce qui est précisément l'utilisation d'un REPORTABLE contrainte. Et il y a une certaine ironie dans le fait que vous êtes en train de regarder comme défectueux parce qu'il ne parvient pas à l'échec, tout en quelque sorte, c'est censé être la solution à l'échec en premier lieu!
Résumé du statu quo dans PostgreSQL 9.1
NOT DEFERRABLE
UNIQUE
ouPRIMARY KEY
contraintes sont vérifiées après chaque ligne.DEFERRABLE
des contraintes deIMMEDIATE
(INITIALLY IMMEDIATE
ou viaSET CONSTRAINTS
) sont contrôlés après chaque déclaration de.DEFERRABLE
des contraintes deDEFERRED
(INITIALLY DEFERRED
ou viaSET CONSTRAINTS
) sont contrôlés après chaque transaction.Note le traitement spécial de la
UNIQUE
/PRIMARY KEY
contraintes.Citant la page de manuel de
CREATE TABLE
:Alors qu'il affirme plus loin dans la Compatibilité en vertu de la section
Non différée de l'unicité des contraintes
:Gras c'est moi qui souligne.
Si vous avez besoin d'une
FOREIGN KEY
contraintes à la référence de la colonne(s),DEFERRABLE
est pas une option, car (par la documentation):Il peut y avoir une légère documentation bug ici, mais pas pour le cas où vous êtes à l'affiche. Si vous COMMENCEZ une transaction et d'essayer les mises à jour une à la fois, ils ne parviennent pas, mais si un seule instruction laisse les choses dans un bon état, il ne se plaint pas. Les docs disent:
Qui est exactement ce qui semble être le cas. Quelle est la surprise pour moi, compte tenu de la documentation de
DEFERRABLE
qui dit en partie:Sans
DEFERRABLE INITIALLY IMMEDIATE
options, l'exemple de mise à jour échoue, même si leUPDATE
déclaration (sans doute constituant la "commande") laisse les choses dans un bon état. Peut-être les docs doivent être modifiées pour dire qu'unNOT DEFERRABLE
contrainte est appliquée que chaque ligne est modifiée par une déclaration?