In connection with this answer I stumbled upon a phenomenon I cannot explain.
Version:
PostgreSQL 9.1.2 on x86_64-unknown-linux-gnu, compiled by gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit
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
statement modifying multiple rows:
UPDATE t
SET id = t_old.id
FROM t t_old
WHERE (t.id, t_old.id) IN ((1,2), (2,1));
The above UPDATE
works, though it expected it should not. The constraint is defined INITIALLY IMMEDIATE
and I did not use SET CONSTRAINTS
.
Am I missing something or is this a (rather harmless) bug?
2) Data modifying CTE
Consequently, a data modifying CTE works, too. Though it fails with a NOT DEFERRED
pk:
WITH x AS (UPDATE t SET id = 1 WHERE id = 2)
UPDATE t SET id = 2 WHERE id = 1;
I quote the manual on CTEs:
The sub-statements in
WITH
are executed concurrently with each other and with the main query. Therefore, when using data-modifying statements inWITH
, the order in which the specified updates actually happen is unpredictable. All the statements are executed with the same snapshot (see Chapter 13), so they cannot "see" each others' effects on the target tables.
3) Multiple UPDATE statements in one transaction
Without SET CONSTRAINTS
, this fails with a UNIQUE violation - as expected:
BEGIN;
-- SET CONSTRAINTS t_pkey DEFERRED;
UPDATE t SET id = 2 WHERE txt = 'one';
UPDATE t SET id = 1 WHERE txt = 'two';
COMMIT;