Hi,

On PostgreSQL 7.4.2 I can create a situation in which a foreign key is
violated:

bug=# SELECT b.name, exists(SELECT 1 FROM a WHERE a.name = b.name) FROM b;
 name | ?column?
------+----------
 xxx  | f
(1 ÐÐÐÐÑÑ)
 
bug=# \d+ b
                       ÐÐÐÐÐÑÐ "public.b"
 ÐÐÐÐÐÐÐ | ÐÐÐ | ÐÐÐÐÑÐÐÐÑÐÑÑ | ÐÐÐÑÐÐÐÐ
----------------+--------+--------------------------+------------------
 name           | text   | not null                 |
ÐÐÐÐÐÑÑ:
    "b_pkey" ÐÐÑÑÐÐÐÐ ÐÐÐÐ, btree (name)
ÐÐÑÐÐÐÑÐÐÐÑ ÐÐ ÐÑÐÑÐÑÐÐÐÑ ÐÐÑÑÑ:
    "$1" FOREIGN KEY (name) REFERENCES a(name) ON UPDATE CASCADE
ÐÑÐÐÐÐÐ:
    b_rename AS ON UPDATE TO b DO INSTEAD UPDATE a SET name = new.name WHERE (a.name = 
old.name)

I create the situation as follows:

CREATE TABLE a (name TEXT PRIMARY KEY);
INSERT INTO a VALUES ('xxx');
CREATE TABLE b (name TEXT PRIMARY KEY REFERENCES a(name) ON UPDATE CASCADE);
INSERT INTO b VALUES ('xxx');
CREATE RULE b_rename AS ON UPDATE TO b DO INSTEAD UPDATE a SET name = NEW.name WHERE 
name = OLD.name;
UPDATE b SET name = 'yyy' WHERE name = 'xxx';
SELECT b.name, exists(SELECT 1 FROM a WHERE a.name = b.name) FROM b;
 name | ?column?
------+----------
 xxx  | f
(1 ÐÐÐÐÑÑ)

Up to here I thought that the following was going on: The UPDATE b
statement was rewritten into a UPDATE a statement by the rule system.
The update on a triggers the foreign key update on b. This UPDATE gets
rewritten again by the rule system to update a instead. The update to a
triggers the foreign key again, which recognizes that it is already
running and does nothing. The outer foreign key is done and the update
to a is realized. b stays unchanged.

But then I discovered that if I update the row in a prior to creating
the rule, the rule works as expected:

CREATE TABLE a (name TEXT PRIMARY KEY);
INSERT INTO a VALUES ('xxx');
CREATE TABLE b (name TEXT PRIMARY KEY REFERENCES a(name) ON UPDATE CASCADE);
INSERT INTO b VALUES ('xxx');
UPDATE a SET name = 'zzz' WHERE name = 'xxx';
CREATE RULE b_rename AS ON UPDATE TO b DO INSTEAD UPDATE a SET name = NEW.name WHERE 
name = OLD.name;
UPDATE b SET name = 'yyy' WHERE name = 'zzz';
SELECT b.name, exists(SELECT 1 FROM a WHERE a.name = b.name) FROM b;
 name | ?column?
------+----------
 yyy  | t
(1 ÐÐÐÐÑÑ)

This somehow renders my theory invalid. Can someone comment?

I also tried the same rule without INSTEAD. That does what I want and it
is what I'm using in the application now. I wonder if that is The Right
WayÂ.

And should PostgreSQL allow foreign key violations like in the example
above?

Thanks

-- 
Markus Bertheau <[EMAIL PROTECTED]>


---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])

Reply via email to