Re: resolution order for foreign key actions?

From: Karl Czajkowski <karlcz(at)isi(dot)edu>
To: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>
Cc: Adrian Klaver <adrian(dot)klaver(at)aklaver(dot)com>, "pgsql-general(at)postgresql(dot)org" <pgsql-general(at)postgresql(dot)org>
Subject: Re: resolution order for foreign key actions?
Date: 2016-11-08 22:41:19
Message-ID: 20161108224119.GB22642@moraine.isi.edu
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On Nov 08, David G. Johnston modulated:
...
> ON DELETE starts with the "one" side of a one-to-many relationship​. 
> When deleting the one row the question is what should be done with the
> many rows which refer to it.  If ALL of the many rows agree to be
> deleted then the one row in question can go away and no error is
> raised.  If ANY of the many rows refuse to die then the one row in
> question must remain in order to maintain referential integrity - thus
> an error will be raised.
>

I think I had the same intuition going into this.

However, I am testing with an artificial scenario to focus on the
ordering/precedence behavior. I was even hoping PostgreSQL might raise
an error when I created apparently conflicting constraints, but
unfortunately it does something much more confusing...

You might consider this to explore what happens if someone
accidentally redefines constraints with conflicting actions. I just
redefine the same constraint with only varying constraint name and ON
DELETE clause.

Here, I have assigned constraint names to demonstrate that the rules
are NOT applied based on a lexicographic sort of constraint names but
rather on order of definition (perhaps there is another
internally-generated name that sorts in order of definition?):

======================================
ALTER TABLE refs ADD CONSTRAINT z FOREIGN KEY (t_id) REFERENCES targets (id) ON DELETE NO ACTION;
ALTER TABLE
ALTER TABLE refs ADD CONSTRAINT y FOREIGN KEY (t_id) REFERENCES targets (id) ON DELETE SET NULL;
ALTER TABLE
ALTER TABLE refs ADD CONSTRAINT x FOREIGN KEY (t_id) REFERENCES targets (id) ON DELETE CASCADE;
ALTER TABLE

This test will show that ON DELETE NO ACTION is in effect due to constraint z.

Table "public.refs"
Column | Type | Modifiers
--------+---------+---------------------------------------------------
id | integer | not null default nextval('refs_id_seq'::regclass)
t_id | integer | not null
Indexes:
"refs_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"x" FOREIGN KEY (t_id) REFERENCES targets(id) ON DELETE CASCADE
"y" FOREIGN KEY (t_id) REFERENCES targets(id) ON DELETE SET NULL
"z" FOREIGN KEY (t_id) REFERENCES targets(id)

-------------
Content of refs table before deletion of target:
SELECT * FROM refs;
id | t_id
----+------
1 | 1
2 | 2
3 | 3
(3 rows)

-------------
Attempting to delete a target:
DELETE FROM targets WHERE name = 'foo1' RETURNING *;
ERROR: update or delete on table "targets" violates foreign key constraint "z" on table "refs"
DETAIL: Key (id)=(2) is still referenced from table "refs".

The attached BASH script will perform a sequence of tests defining the
constraints in different orders and showing the results. The excerpt
above is from the first test scenario.

It accepts optional arguments which are passed to 'psql' and can run
with no arguments if you can talk to your default DB with 'psql'
absent of any arguments, i.e. with Unix domain socket authentication.
It only creates and destroys tables public.targets and public.refs...

Thanks,

Karl

Attachment Content-Type Size
fkr-test.sh application/x-sh 1.5 KB

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Tom Lane 2016-11-08 23:05:05 Re: Gin indexes on intarray is fast when value in array does not exists, and slow, when value exists
Previous Message Hector Yuen 2016-11-08 22:34:44 which work memory parameter is used for what?