Cascading updates run seperately

From: Allan Wang <allanvv(at)gmail(dot)com>
To: pgsql-bugs(at)postgresql(dot)org
Subject: Cascading updates run seperately
Date: 2005-08-12 01:17:57
Message-ID: 1123809477.10708.20.camel@localhost
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

I'm running a fairly recent CVS head server, but I think this bug
applies in all versions.

talluria=# delete from items;
ERROR: insert or update on table "players" violates foreign key constraint "players_accessory1_fkey"
DETAIL: Key (accessory1)=(90205) is not present in table "items".
CONTEXT: SQL statement "UPDATE ONLY "public"."players" SET "head" = NULL WHERE "head" = $1"

players
"users_pkey" PRIMARY KEY, btree (playerid) CLUSTER
"players_name_key" UNIQUE, btree (name)
"players_coord" btree (mapid, x, y)
"players_lastactive_key" btree (lastactive)
"players_username_lkey" btree (lower(name::text))
Foreign-key constraints:
"players_accessory1_fkey" FOREIGN KEY (accessory1) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"players_accessory2_fkey" FOREIGN KEY (accessory2) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"players_accessory3_fkey" FOREIGN KEY (accessory3) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"players_feet_fkey" FOREIGN KEY (feet) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"players_stylesheet_fkey" FOREIGN KEY (stylesheet) REFERENCES stylesheets(stylesheetid) ON UPDATE CASCADE ON DELETE SET DEFAULT
"users_arm" FOREIGN KEY (arm) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"users_belt" FOREIGN KEY (belt) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"users_body" FOREIGN KEY (body) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"users_head" FOREIGN KEY (head) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"users_lefthand" FOREIGN KEY (lefthand) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"users_leg" FOREIGN KEY (leg) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"users_righthand" FOREIGN KEY (righthand) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL

talluria=# \d items
Table "public.items"
Column | Type | Modifiers
-------------+---------+----------------------------------------------------
itemid | integer | not null default nextval('items_itemid_seq'::text)
itemdataid | integer | not null default 0
playerid | integer |
quantity | integer | not null default 1
elementflag | integer | not null default 0
shopid | integer |
map | integer |
x | integer |
y | integer |
price | integer |
Indexes:
"items_pkey" PRIMARY KEY, btree (itemid)
"items_coord" btree (map, x, y)
"items_playerid_idx" btree (playerid)
Foreign-key constraints:
"items_playerid_fkey" FOREIGN KEY (playerid) REFERENCES players(playerid) ON UPDATE CASCADE ON DELETE CASCADE
Triggers:
test_valid_item_trig BEFORE INSERT OR UPDATE ON items FOR EACH ROW EXECUTE PROCEDURE valid_item()

I'm told this:
<AndrewSN> I think the problem is that the cascading updates all run separately
<AndrewSN> which means that the one that does SET head = NULL, for example, fails because all the other fields still have values pointing at the deleted row
<AndrewSN> or at _a_ deleted row

I made a testcase, but after some retrying (without the mistakes I made) I was unable to reproduce it anymore..

allan=# create table items (itemid serial, playerid int);
NOTICE: CREATE TABLE will create implicit sequence "items_itemid_seq1" for serial column "items.itemid"
CREATE TABLE
allan=# create table items (itemid serial, playerid int);
allan=# create table players (playerid serial, head int references items(itemid) on update cascade on delete set null, body int references items(itemid) on update cascade on delete set null);
NOTICE: CREATE TABLE will create implicit sequence "players_playerid_seq1" for serial column "players.playerid"
ERROR: there is no unique constraint matching given keys for referenced table "items"
allan=# \d items
Table "public.items"
Column | Type | Modifiers
----------+---------+------------------------------------------------------------
itemid | integer | not null default nextval('public.items_itemid_seq1'::text)
playerid | integer |

allan=# create unique index
information_schema. pg_temp_1. plays_pkey public. videos_pkey
pg_catalog. pg_toast. plays_videoid_key videos_path_key
allan=# create unique index items_pkey on items using btree(itemid);
CREATE INDEX
allan=# create table players (playerid serial, head int references items(itemid) on update cascade on delete set null, body int references items(itemid) on update cascade on delete set null);
NOTICE: CREATE TABLE will create implicit sequence "players_playerid_seq1" for serial column "players.playerid"
CREATE TABLE
allan=# insert into players
allan=# \d players
Table "public.players"
Column | Type | Modifiers
----------+---------+----------------------------------------------------------------
playerid | integer | not null default nextval('public.players_playerid_seq1'::text)
head | integer |
body | integer |
Foreign-key constraints:
"players_body_fkey" FOREIGN KEY (body) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
"players_head_fkey" FOREIGN KEY (head) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL

allan=# insert into players default values;
INSERT 0 1
allan=# \d items
Table "public.items"
Column | Type | Modifiers
----------+---------+------------------------------------------------------------
itemid | integer | not null default nextval('public.items_itemid_seq1'::text)
playerid | integer |
Indexes:
"items_pkey" UNIQUE, btree (itemid)

allan=# insert into items (playerid) values ((select playerid from players limit 1));
INSERT 0 1
allan=# insert into items (playerid) values ((select playerid from players limit 1));
INSERT 0 1
allan=# update players set head=(select itemid from items order by itemid asc limit 1);
UPDATE 1
allan=# update players set body=(select itemid from items order by itemid desc limit 1);
UPDATE 1
allan=# select * from players;
playerid | head | body
----------+------+------
1 | 1 | 2
(1 row)

allan=# select * from items;
itemid | playerid
--------+----------
1 | 1
2 | 1
(2 rows)

allan=# begin;
BEGIN
allan=# delete from items;
DELETE 2
allan=# rollback;
ROLLBACK
allan=# select * from players;
playerid | head | body
----------+------+------
1 | 1 | 2
(1 row)

allan=# begin;
BEGIN
allan=# delete from items;
DELETE 2
allan=# select * from players;
playerid | head | body
----------+------+------
1 | NULL | NULL
(1 row)

allan=# select * from items;
itemid | playerid
--------+----------
(0 rows)

allan=# rollback;
ROLLBACK
allan=# select * from items;
itemid | playerid
--------+----------
1 | 1
2 | 1
(2 rows)

allan=# select * from players
allan-# ;
playerid | head | body
----------+------+------
1 | 1 | 2
(1 row)

allan=# update players set bo
allan=# begin;
BEGIN
allan=# update players set body=1;
UPDATE 1
allan=# delete from items;
ERROR: insert or update on table "players" violates foreign key constraint "players_body_fkey"
DETAIL: Key (body)=(1) is not present in table "items".
CONTEXT: SQL statement "UPDATE ONLY "public"."players" SET "head" = NULL WHERE "head" = $1"
allan=# rollback;l
ROLLBACK
allan-#
allan=# begin;
BEGIN
allan=# select * from items;
itemid | playerid
--------+----------
1 | 1
2 | 1
(2 rows)

allan=# select * from players;
playerid | head | body
----------+------+------
1 | 1 | 2
(1 row)

allan=# update players set head=2, body=1;
UPDATE 1
allan=# delete from items;
ERROR: insert or update on table "players" violates foreign key constraint "players_head_fkey"
DETAIL: Key (head)=(2) is not present in table "items".
CONTEXT: SQL statement "UPDATE ONLY "public"."players" SET "body" = NULL WHERE "body" = $1"

Allan Wang

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Steve Peterson 2005-08-12 02:05:34 Re: BUG #1819: COPY filename rejects Windows format path
Previous Message Bernard 2005-08-11 23:18:49 BUG #1820: Installation: Dependency failure