14

この答えに関連して、説明できない現象に出くわしました。

バージョン:
x86_64-unknown-linux-gnu 上の PostgreSQL 9.1.2、gcc-4.4.real でコンパイル (Debian 4.4.5-8) 4.4.5、64 ビット

テストベッド:

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複数の行を変更するステートメント:

UPDATE t
SET    id = t_old.id
FROM   t t_old
WHERE (t.id, t_old.id) IN ((1,2), (2,1));

上記UPDATEは動作しますが、動作しないはずです。制約が定義されINITIALLY IMMEDIATEており、使用しませんでしSET CONSTRAINTSた。

何か足りないのでしょうか、それとも (無害な) バグですか?

2) データ変更 CTE

したがって、CTE を変更するデータも機能します。NOT DEFERREDpkで失敗しますが:

WITH x AS (UPDATE t SET id = 1 WHERE id = 2)
UPDATE t SET id = 2 WHERE id = 1;

CTEのマニュアルを引用します:

のサブステートメントはWITH、相互に、およびメイン クエリと同時に実行されます。したがって、 でデータ変更ステートメントを使用する場合WITH、指定された更新が実際に発生する順序は予測できません。すべてのステートメントは同じスナップショットで実行されるため(第 13 章を参照)、ターゲット テーブルに対する互いの影響を「見る」ことはできません。

3) 1 つのトランザクションでの複数の UPDATE ステートメント

がないSET CONSTRAINTSと、これは UNIQUE 違反で失敗します - 予想通り:

BEGIN;
-- SET CONSTRAINTS t_pkey DEFERRED;
UPDATE t SET id = 2 WHERE txt = 'one';
UPDATE t SET id = 1 WHERE txt = 'two';
COMMIT;
4

2 に答える 2

6

ここにはわずかなドキュメントのバグがあるかもしれませんが、あなたが示しているケースではありません. トランザクションを BEGIN し、一度に 1 つずつ更新を試みると失敗しますが、1つのステートメントが物事を良好な状態のままにしておけば、文句はありません。ドキュメントは言う:

制約が遅延可能である場合、この句は、制約をチェックするデフォルトの時間を指定します。制約が INITIALLY IMMEDIATE の場合、各ステートメントの後にチェックされます。これがデフォルトです。制約が INITIALLY DEFERRED の場合、トランザクションの最後にのみチェックされます。

これはまさに起こっているようです。のドキュメントを考えると、私にとって驚きは何ですかDEFERRABLE

延期できない制約は、すべてのコマンドの直後にチェックされます。

オプションを指定しないと、ステートメント (おそらく「コマンド」を構成する) によって状態が良好DEFERRABLE INITIALLY IMMEDIATEであっても、更新の例は失敗します。UPDATEおそらく、各行がステートメントによって変更されるとNOT DEFERRABLE制約が適用されると言うように、ドキュメントを変更する必要がありますか?

于 2012-04-05T17:32:35.977 に答える