Re: Delete / F/K error

From: Michael Fuhr <mike(at)fuhr(dot)org>
To: CSN <cool_screen_name90001(at)yahoo(dot)com>
Cc: "pgsql-general(at)postgresql(dot)org" <pgsql-general(at)postgresql(dot)org>
Subject: Re: Delete / F/K error
Date: 2005-12-31 00:26:37
Message-ID: 20051231002637.GA15480@winnie.fuhr.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Stephan Szabo 2005-12-31 00:51:14 Re: Delete / F/K error
Previous Message Jure Ložar 2005-12-31 00:06:23 How to read wal?