Skip to content
Advertisement

Why `not deferrable` constraint is deferred when using `with`?

create table T1 (
    id bigint NOT NULL primary key,
    a bigint unique not null
);
create table T2 (
    id int not null primary key,
    b bigint,
    foreign KEY(id) references T1(id) not deferrable
);
alter table T1 add constraint fk_id foreign key (id) references T2(id) not deferrable;    

--Statement 1
with ins as (
        insert into T1(id, a) values(15, 4) returning id
)
insert into T2(id, b) values(15, 3);

--Statement 2
with ins as (
        insert into T2(id, b) values(14, 4) returning id
)
insert into T1(id, a) values(14, 3);

--Statement 3 (gives error)
with upd as (
        update T1 set a = 4 where id = 14 returning id
)
update T1 set a = 3 where id = 15;

When this script is run in PostgreSQL, why does Statement 1 and 2 work and only statement 3 gives an error even when both the foreign key constraint are explicitly not deferrable?

Advertisement

Answer

According to the docs non-deferrable unique constraints are checked for each row, contrary to the standards specification that they are checked only at the end of a statement.

When a UNIQUE or PRIMARY KEY constraint is not deferrable, PostgreSQL checks for uniqueness immediately whenever a row is inserted or modified. The SQL standard says that uniqueness should be enforced only at the end of the statement…

But this exception to the standards spec is only for uniqueness, not for foreign key. Foreign key constraints are checked at the end of the statement if they are either not deferrable or if they are deferrable but not deferred. Since any problems have been cured by the end of the statement in your first two examples, there is no error.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement