Re: resolution order for foreign key actions? - Mailing list pgsql-general

From Karl Czajkowski
Subject Re: resolution order for foreign key actions?
Date
Msg-id 20161108224119.GB22642@moraine.isi.edu
Whole thread Raw
In response to Re: resolution order for foreign key actions?  ("David G. Johnston" <david.g.johnston@gmail.com>)
List 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

pgsql-general by date:

Previous
From: Tom Lane
Date:
Subject: Re: Gin indexes on intarray is fast when value in array does not exists, and slow, when value exists
Next
From: Hector Yuen
Date:
Subject: which work memory parameter is used for what?