Received: from maia.hub.org (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id 4617B65B13D for ; Tue, 16 Mar 2010 17:50:02 -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 04420-02 for ; Tue, 16 Mar 2010 20:49:51 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from shetland.sei.cmu.edu (shetland.sei.cmu.edu [192.58.107.44]) by mail.postgresql.org (Postfix) with ESMTP id 85F9C65B12A for ; Tue, 16 Mar 2010 17:49:51 -0300 (ADT) Received: from ms02.sei.cmu.edu (ms02.sei.cmu.edu [128.237.22.38]) by shetland.sei.cmu.edu (8.13.8/8.13.8/1294) with ESMTP id o2GKnkFl003254; Tue, 16 Mar 2010 16:49:46 -0400 Received: from lisa.yellow.cert.org (lisa.yellow.cert.org [10.20.10.153]) by ms02.sei.cmu.edu (8.13.1/8.13.1/1295) with ESMTP id o2GKnj1T027430; Tue, 16 Mar 2010 16:49:45 -0400 Message-ID: <4B9FEEE8.1060404@andrew.cmu.edu> Date: Tue, 16 Mar 2010 16:49:44 -0400 From: Tony Cebzanov User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.8) Gecko/20100227 Thunderbird/3.0.3 Mnenhy/0.7.6.0 MIME-Version: 1.0 To: Tom Lane CC: Richard Huxton , pgsql-sql@postgresql.org Subject: Re: Avoiding cycles in a directed graph References: <4B9FDFDE.5030005@andrew.cmu.edu> <4B9FE752.4080709@archonet.com> <14113.1268771643@sss.pgh.pa.us> In-Reply-To: <14113.1268771643@sss.pgh.pa.us> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit 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/114 X-Sequence-Number: 33821 On 3/16/10 4:34 PM, Tom Lane wrote: > 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 :-( Are you saying there's no way to avoid cycles at all, or just no way to do it using uniqueness constraints? I'm okay with running the big, fat WITH RECURSIVE query in my insert trigger if I have to -- it won't be great for performance, but I don't expect this to be a frequent operation, so I'll accept the performance hit if it works. Unfortunately I can't even get that working. Here's the (not at all functional) trigger I've got right now, which only detects the cycle *after* it's been inserted, which is of no help at all. Any way I can modify this to do the right thing? CREATE OR REPLACE FUNCTION check_edge_cycle() RETURNS trigger AS $$ DECLARE cycles INTEGER; BEGIN WITH RECURSIVE search_graph(parent, child, id, depth, path, cycle) AS ( SELECT NEW.parent, NEW.child, NEW.id, 1, ARRAY[NEW.id], false UNION ALL SELECT g.parent, g.child, g.id, sg.depth + 1, path || g.id, g.id = ANY(path) FROM catalog_edge g, search_graph sg WHERE g.parent = sg.child AND NOT cycle ) SELECT INTO cycles COUNT(*) FROM search_graph WHERE cycle=true; RAISE NOTICE 'cycles: %', cycles; IF cycles > 0 THEN RAISE EXCEPTION 'cycle'; END IF; RETURN NEW; END $$ LANGUAGE plpgsql;