Thread: Foreign key reference counting strategy?

Foreign key reference counting strategy?

From
Joost Kraaijeveld
Date:
Hi,

Is there a strategy to implement reference counting for foreign keys so
that if the last reference to the key is deleted, the record is deleted
also?

TIA

-- 
Groeten,

Joost Kraaijeveld
Askesis B.V.
Molukkenstraat 14
6524NB Nijmegen
tel: 024-3888063 / 06-51855277
fax: 024-3608416
web: www.askesis.nl


Re: Foreign key reference counting strategy?

From
Markus Schaber
Date:
Hi, Joost,

Joost Kraaijeveld wrote:

> Is there a strategy to implement reference counting for foreign keys so
> that if the last reference to the key is deleted, the record is deleted
> also?

Create an "after delete" trigger on the referencing table that checks
whether there still are records with the same key (IF EXISTS()), and
deletes the referenced row otherwise.

It won't hurt to have an index on the referencing column, for speed reasons.

HTH,
Markus
-- 
Markus Schaber | Logical Tracking&Tracing International AG
Dipl. Inf.     | Software Development GIS

Fight against software patents in Europe! www.ffii.org
www.nosoftwarepatents.org


Re: Foreign key reference counting strategy?

From
Michael Fuhr
Date:
On Sat, Oct 14, 2006 at 03:52:04PM +0200, Markus Schaber wrote:
> Joost Kraaijeveld wrote:
> > Is there a strategy to implement reference counting for foreign keys so
> > that if the last reference to the key is deleted, the record is deleted
> > also?
> 
> Create an "after delete" trigger on the referencing table that checks
> whether there still are records with the same key (IF EXISTS()), and
> deletes the referenced row otherwise.

In a concurrent environment that delete can fail with a foreign key
constraint violation because IF EXISTS won't see uncommitted changes
in other transactions.  If changes in another transaction reference
the same key then the delete will block until the other transaction
commits or rolls back; if the other transaction commits then the
delete will fail.  In PL/pgSQL you can trap that failure with an
EXCEPTION clause that catches foreign_key_violation.

-- 
Michael Fuhr


Re: Foreign key reference counting strategy?

From
Tom Lane
Date:
Michael Fuhr <mike@fuhr.org> writes:
> On Sat, Oct 14, 2006 at 03:52:04PM +0200, Markus Schaber wrote:
>> Create an "after delete" trigger on the referencing table that checks
>> whether there still are records with the same key (IF EXISTS()), and
>> deletes the referenced row otherwise.

> In a concurrent environment that delete can fail with a foreign key
> constraint violation because IF EXISTS won't see uncommitted changes
> in other transactions.

No, I don't think so, because the DELETE will already be holding
exclusive lock on the doomed PK row, which any would-be inserters of
matching FK rows will be blocked on.  AFAICS the DELETE should go
through and then the inserters will fail.  Which is not necessarily
better of course ... but if you want logic like this, you probably
should have code to make the FK inserters deal with no-such-key
failures.
        regards, tom lane


Re: Foreign key reference counting strategy?

From
Michael Fuhr
Date:
On Sat, Oct 14, 2006 at 07:58:06PM -0400, Tom Lane wrote:
> Michael Fuhr <mike@fuhr.org> writes:
> > On Sat, Oct 14, 2006 at 03:52:04PM +0200, Markus Schaber wrote:
> >> Create an "after delete" trigger on the referencing table that checks
> >> whether there still are records with the same key (IF EXISTS()), and
> >> deletes the referenced row otherwise.
> 
> > In a concurrent environment that delete can fail with a foreign key
> > constraint violation because IF EXISTS won't see uncommitted changes
> > in other transactions.
> 
> No, I don't think so, because the DELETE will already be holding
> exclusive lock on the doomed PK row, which any would-be inserters of
> matching FK rows will be blocked on.  AFAICS the DELETE should go
> through and then the inserters will fail.

Unless the inserters got there first.  I just tested both ways; if
the insert acquires the lock first then the delete fails, but if the
delete acquires the lock first then the insert fails.

-- 
Michael Fuhr


Re: Foreign key reference counting strategy?

From
Tom Lane
Date:
Michael Fuhr <mike@fuhr.org> writes:
> On Sat, Oct 14, 2006 at 07:58:06PM -0400, Tom Lane wrote:
>> No, I don't think so, because the DELETE will already be holding
>> exclusive lock on the doomed PK row, which any would-be inserters of
>> matching FK rows will be blocked on.  AFAICS the DELETE should go
>> through and then the inserters will fail.

> Unless the inserters got there first.  I just tested both ways; if
> the insert acquires the lock first then the delete fails, but if the
> delete acquires the lock first then the insert fails.

Well, if the inserters get a lock on the PK row before the DELETE does,
then of course.  I was just disputing the assertion that doing IF EXISTS
in an after trigger would add a new way for the DELETE to fail.  At that
point, any uncommitted inserts must be blocked waiting for the delete.
        regards, tom lane


Re: Foreign key reference counting strategy?

From
Michael Fuhr
Date:
On Sat, Oct 14, 2006 at 08:20:10PM -0400, Tom Lane wrote:
> Michael Fuhr <mike@fuhr.org> writes:
> > Unless the inserters got there first.  I just tested both ways; if
> > the insert acquires the lock first then the delete fails, but if the
> > delete acquires the lock first then the insert fails.
> 
> Well, if the inserters get a lock on the PK row before the DELETE does,
> then of course.  I was just disputing the assertion that doing IF EXISTS
> in an after trigger would add a new way for the DELETE to fail.

My intent wasn't to assert that IF EXISTS adds a new way for the
DELETE to fail.  I was just pointing out that the test "if no
referencing rows exist then delete the referenced row" isn't
foolproof, viz., the DELETE can fail even though IF EXISTS said
there were no referencing rows.

-- 
Michael Fuhr


Re: Foreign key reference counting strategy?

From
Tom Lane
Date:
Michael Fuhr <mike@fuhr.org> writes:
> My intent wasn't to assert that IF EXISTS adds a new way for the
> DELETE to fail.  I was just pointing out that the test "if no
> referencing rows exist then delete the referenced row" isn't
> foolproof, viz., the DELETE can fail even though IF EXISTS said
> there were no referencing rows.

Actually, it's me that was confused --- I was thinking in terms of
the original DELETE being done on the PK row, but of course that's
not the case here --- the original DELETE would be on some FK row.

It might be possible to make it work by adding a SELECT FOR UPDATE
that locks the PK row in the trigger before doing the IF EXISTS test,
but I think that that could create deadlock failures.  You'd basically
be making the transaction upgrade a share row lock to an exclusive
lock, and that's generally unsafe.  If you could ensure that your
trigger runs before the RI integrity trigger, maybe it would work...
        regards, tom lane