Re: Delete / F/K error - Mailing list pgsql-general

From Michael Fuhr
Subject Re: Delete / F/K error
Date
Msg-id 20051231002637.GA15480@winnie.fuhr.org
Whole thread Raw
In response to Re: Delete / F/K error  (CSN <cool_screen_name90001@yahoo.com>)
Responses Re: Delete / F/K error
List pgsql-general
On Fri, Dec 30, 2005 at 02:38:48PM -0800, CSN wrote:
> I'm still confused what the problem was.

I think the problem is related to having multiple foreign key
constraints with ON DELETE SET NULL referencing the same target.
The triggers that enforce those constraints are fired one at a time
with a query like "UPDATE ONLY tbl SET col = NULL WHERE col = val".
Each update changes only one column; the other columns still have
their old values, so when the update checks those columns' foreign
key constraints you get an error because the referenced key has
already been deleted.  Interestingly, this only appears to be a
problem if the delete takes place in the same (sub)transaction that
inserted the referencing row.  Example:

test=> CREATE TABLE foo (
test(>     id  integer PRIMARY KEY
test(> );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
CREATE TABLE
test=>
test=> CREATE TABLE bar (
test(>     foo_id1  integer REFERENCES foo ON DELETE SET NULL,
test(>     foo_id2  integer REFERENCES foo ON DELETE SET NULL
test(> );
CREATE TABLE
test=> BEGIN;
BEGIN
test=> INSERT INTO foo VALUES (1);
INSERT 0 1
test=> INSERT INTO bar VALUES (1, 1);
INSERT 0 1
test=> DELETE FROM foo WHERE id = 1;
ERROR:  insert or update on table "bar" violates foreign key constraint "bar_foo_id2_fkey"
DETAIL:  Key (foo_id2)=(1) is not present in table "foo".
CONTEXT:  SQL statement "UPDATE ONLY "public"."bar" SET "foo_id1" = NULL WHERE "foo_id1" = $1"
test=> ROLLBACK;
ROLLBACK

But:

test=> BEGIN;
BEGIN
test=> INSERT INTO foo VALUES (1);
INSERT 0 1
test=> INSERT INTO bar VALUES (1, 1);
INSERT 0 1
test=> COMMIT;
COMMIT
test=> DELETE FROM foo WHERE id = 1;
DELETE 1

And:

test=> BEGIN;
BEGIN
test=> INSERT INTO foo VALUES (1);
INSERT 0 1
test=> INSERT INTO bar VALUES (1, 1);
INSERT 0 1
test=> SAVEPOINT x;
SAVEPOINT
test=> DELETE FROM foo WHERE id = 1;
DELETE 1
test=> COMMIT;
COMMIT

And:

test=> BEGIN;
BEGIN
test=> INSERT INTO foo VALUES (1);
INSERT 0 1
test=> SAVEPOINT x;
SAVEPOINT
test=> INSERT INTO bar VALUES (1, 1);
INSERT 0 1
test=> RELEASE x;
RELEASE
test=> DELETE FROM foo WHERE id = 1;
DELETE 1
test=> COMMIT;
COMMIT

Any developers following this?  Is this behavior bogus or correct?
The above examples are in 8.1.1 from CVS.

--
Michael Fuhr

pgsql-general by date:

Previous
From: Jure Ložar
Date:
Subject: How to read wal?
Next
From: Stephan Szabo
Date:
Subject: Re: Delete / F/K error