Cascading updates run seperately - Mailing list pgsql-bugs

From Allan Wang
Subject Cascading updates run seperately
Date
Msg-id 1123809477.10708.20.camel@localhost
Whole thread Raw
Responses Re: Cascading updates run seperately
List 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
SETDEFAULT 
    "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
havevalues 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,
bodyint 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,
bodyint 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

pgsql-bugs by date:

Previous
From: Tom Lane
Date:
Subject: Re: [8.0.0] out of memory on large UPDATE
Next
From: Stephan Szabo
Date:
Subject: Re: Cascading updates run seperately