Einschränkung definiert DEFERRABLE INITIALLY IMMEDIATE ist immer noch ZURÜCKGESTELLT?
In Verbindung mit die Antwort stieß ich auf ein Phänomen, das ich nicht erklären kann.
Version:
PostgreSQL 9.1.2 auf x86_64-unknown-linux-gnu, compiled by gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit -
Betrachten Sie die folgende demo. Testbed:
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) UPDATE-Anweisung geändert wird, die mehrere Zeilen:
UPDATE t
SET id = t_old.id
FROM t t_old
WHERE (t.id, t_old.id) IN ((1,2), (2,1));
Scheint es einen bug in der aktuellen Implementierung? Die oben genannten UPDATE funktioniert, obwohl es sollte nicht. Die Einschränkung definiert INITIALLY IMMEDIATE
und ich habe nicht mit SET CONSTRAINTS
.
Bin ich etwas fehlt, oder ist dies ein (eher harmloser) bug?
2) Daten ändern CTE
Folglich ein Daten ändern CTE funktioniert, auch wenn es fehlschlägt, mit einem NOT DEFERRED
pk:
WITH x AS (
UPDATE t SET id = 1 WHERE id = 2
)
UPDATE t SET id = 2 WHERE id = 1;
Ich zitiere die Handbuch auf Allgemeine Tabellenausdrücke:
Den sub-Anweisungen in MIT ausgeführt werden, die gleichzeitig miteinander
und mit der Haupt-Abfrage. Deshalb, wenn Sie Daten ändern
Aussagen, die Reihenfolge, in der die angegebenen updates eigentlich
geschehen ist unberechenbar. Alle Anweisungen ausgeführt, die mit der gleichen
Schnappschuss (siehe Kapitel 13), so dass Sie nicht "sehen" gegenseitig Ihre Wirkung
auf dem Ziel-Tabellen.
3) Mehrere UPDATE-Anweisungen in einer Transaktion
Ohne SET CONSTRAINTS
dieses schlägt mit einem EINMALIGEN Verstoß - wie erwartet:
BEGIN;
-- SET CONSTRAINTS t_pkey DEFERRED;
UPDATE t SET id = 2 WHERE txt = 'one';
UPDATE t SET id = 1 WHERE txt = 'two';
COMMIT;
Die Art, wie ich Lesen Sie die Dokumentation, ich denke, das update fehlschlagen sollte. Würde ich es nennen, ein Fehler.
Können Sie der Dokumentation, die zeigt, warum "Die da oben UPDATE funktioniert, obwohl es nicht sein sollte." - warum das update nicht funktionieren sollte?
Betrachten Sie die Antworten unten. Auch Folgen den link in die Kommentare und prüfen, Peter Eisentraut ist die Antwort da.
was sagt "Der SQL-standard sagt, dass die Eindeutigkeit erzwungen werden soll, die nur am Ende der Anweisung ... Zu erhalten standard-konform Verhalten, erklären die constraint als DEFERRABLE aber nicht die latenten (d.h., ZUNÄCHST IMMEDIATE)" - das ist genau das, was Sie tun, damit das update erfolgreich sein sollte, weil am Ende der Anweisung werden alle IDs sind einzigartig.
InformationsquelleAutor Erwin Brandstetter | 2012-04-05
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich erinnere mich, dass Sie hob einen fast identischen Punkt, wenn PG9 war im alpha-Zustand. Hier war die Antwort von Tom Lane (high-profile-PG-core-Entwickler):
http://archives.postgresql.org/pgsql-general/2010-01/msg00221.php
Kurz: wird nicht behoben.
Nicht zu sagen, dass ich einverstanden mit Ihrem Vorschlag, dass das aktuelle Verhalten ist ein bug. Betrachten Sie es von der gegenüberliegenden Winkel: es ist das Verhalten von
NOT DEFERRABLE
das ist falsch.In der Tat, die constraint-Verletzung in diesem UPDATE sollte nie passieren, in jedem Fall, denn am Ende des UPDATES wird die Einschränkung zufrieden. Der Zustand am Ende des Befehls ist es, was zählt. Die Zwischenzustände, die während der Ausführung einer einzelnen Anweisung sollte nicht für den Benutzer verfügbar gemacht.
Scheint es, wie die PostgreSQL implementiert die non-deferrable constraint-von der Dublettenprüfung nach jeder Zeile aktualisiert, und nicht, sofort auf das erste Duplikat, das ist im wesentlichen fehlerhaft. Aber dies ist ein bekanntes problem, das vermutlich so alt ist wie PostgreSQL.
Heute ist die Abhilfe für dieses ist es gerade, verwenden Sie ein DEFERRABLE constraint. Und es gibt eine gewisse Ironie in sich, dass Sie suchen, Sie als mangelhaft, weil es nicht zu scheitern, während irgendwie soll es die Lösung sein, um den Ausfall in den ersten Platz!
Zusammenfassung des status quo in PostgreSQL 9.1
NOT DEFERRABLE
UNIQUE
oderPRIMARY KEY
constraints werden überprüft nach jeder Zeile.DEFERRABLE
constraints aufIMMEDIATE
(INITIALLY IMMEDIATE
oder überSET CONSTRAINTS
) überprüft werden nach jeder Anweisung.DEFERRABLE
constraints aufDEFERRED
(INITIALLY DEFERRED
oder überSET CONSTRAINTS
) überprüft werden nach jeder Transaktion.Beachten Sie die Besondere Behandlung von
UNIQUE
/PRIMARY KEY
Einschränkungen.Zitat aus dem Handbuch Seite für
CREATE TABLE
:Während es Staaten, die weiter unten in der Kompatibilität Abschnitt unter
Non-deferred uniqueness constraints
:Fett-Hervorhebung von mir.
Wenn Sie alle
FOREIGN KEY
Einschränkungen Verweis auf die Spalte(N),DEFERRABLE
ist nicht eine option, weil (pro Dokumentation):InformationsquelleAutor Daniel Vérité
Es eine kleine Dokumentation, bug hier, aber nicht für den Fall, Sie sind zeigt. Wenn Sie eine Transaktion BEGINNEN und versuchen, die updates nacheinander, Sie scheitern, aber wenn ein einzigen Anweisung lässt die Dinge in einem guten Zustand, es nicht beschweren. Die docs sagen:
Das ist genau das, was passiert zu sein scheint. Was ist die überraschung für mich, da die Dokumentation der
DEFERRABLE
, die sagt in Teil:Ohne die
DEFERRABLE INITIALLY IMMEDIATE
Optionen, die beispielsweise update fehlschlägt, obwohl dieUPDATE
- Anweisung (vermutlich Konstituierung der "Befehl") lässt die Dinge in einem guten Zustand. Vielleicht sind die docs geändert werden sollte, um zu sagen, dass einNOT DEFERRABLE
Einschränkung erzwungen als jede Zeile wird geändert durch eine Erklärung?InformationsquelleAutor kgrittn