Received: from maia.hub.org (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id A6CD565B0A8 for ; Tue, 16 Mar 2010 17:34:19 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 02095-03 for ; Tue, 16 Mar 2010 20:34:08 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from sss.pgh.pa.us (sss.pgh.pa.us [66.207.139.130]) by mail.postgresql.org (Postfix) with ESMTP id 0130265B0A7 for ; Tue, 16 Mar 2010 17:34:08 -0300 (ADT) Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1]) by sss.pgh.pa.us (8.14.2/8.14.2) with ESMTP id o2GKY3DL014114; Tue, 16 Mar 2010 16:34:03 -0400 (EDT) To: Richard Huxton cc: Tony Cebzanov , pgsql-sql@postgresql.org Subject: Re: Avoiding cycles in a directed graph In-reply-to: <4B9FE752.4080709@archonet.com> References: <4B9FDFDE.5030005@andrew.cmu.edu> <4B9FE752.4080709@archonet.com> Comments: In-reply-to Richard Huxton message dated "Tue, 16 Mar 2010 20:17:22 -0000" Date: Tue, 16 Mar 2010 16:34:03 -0400 Message-ID: <14113.1268771643@sss.pgh.pa.us> From: Tom Lane X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-2.599 tagged_above=-10 required=5 tests=BAYES_00=-2.599 X-Spam-Level: X-Archive-Number: 201003/113 X-Sequence-Number: 33820 Richard Huxton writes: > On 16/03/10 19:45, Tony Cebzanov wrote: >> That's great to avoid looping forever on queries, but what about >> preventing anyone from inserting edges that would create cycles in the >> first place? I reckon I'll need a trigger of some sort, but nothing >> I've tried has enabled me to do the cycle check as part of the trigger >> to avoid inserting an edge that would create a cycle. > You've got the right idea. > If you know that the table doesn't contain any cycles at the moment, > then all the trigger has to do is: > 1. Check "parent" <> "child" > 2. Build the set of parents of "parent". > 3. Check "child" isn't in that set. > 4. If there is a cycle, raise an error (which will abort the insert or > update) The problem with this approach is that it's not safe against concurrent insertions. If concurrent transactions T1 and T2 each insert a row that, taken together (and in combination with existing entries), create a cycle, then neither of their triggers will see the other's row so they'll both think they can commit. The same kind of problem exists for unique and foreign key constraints, both of which use low-level locking mechanisms to catch such cases. There's no way that I can see to express the "no cycle" constraint as a uniqueness constraint unfortunately. You could solve limited forms of it using the exclusion-constraint mechanism that's new in 9.0, but AFAICS not the general case :-( regards, tom lane