Can this be done?

From: Ashley Clark <aclark(at)ghoti(dot)org>
To: Postgres General List <pgsql-general(at)postgresql(dot)org>
Subject: Can this be done?
Date: 2000-11-15 05:32:40
Message-ID: 20001114233240.A4434@ghoti.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

I am implementing some set-based trees in a table and I've been writing
some functions to manipulate (delete branch, insert node, move branch)
them and I've run into a problem with the move_branch function.

When I try a select move_tree(13, 25, 0); to move the branch labeled g
to be a child of the branch labeled i I get an ERROR: Cannot insert a
duplicate key into unique index plan_items_pkey. Why is this happening,
I thought that the primary key constraints should be checked AFTER the
update is finished, am I wrong? Is there some other way to do this in a
single update or will I have to break it up? Can I defer constraint
checking on unique indexes? Any help would be appreciated.

I'll simplify my structure a little here:

create table plan_items (
lft int4 not null,
rgt int4 not null,
name char(50) not null,

primary key (lft),
check (lft < rgt),
check (lft > 0),
check (rgt > 0)
);

copy plan_items from stdin;
1 28 a
2 11 b
3 8 e
4 5 j
6 7 k
9 10 f
12 21 c
13 20 g
14 15 l
16 17 m
18 19 n
22 27 d
23 24 h
25 26 i
\.

And now for the function:

create function move_tree(integer, integer, integer)
returns integer as '
declare
p_node alias for $3;
p_parent alias for $4;
p_brother alias for $5;

droplft plan_items.lft%TYPE;
droprgt plan_items.rgt%TYPE;
newpos plan_items.lft%TYPE;
begin
select rgt
into newpos
from plan_items
where lft = p_parent;

if p_brother > 0 then
select rgt + 1
into newpos
from plan_items
where lft = p_brother;
end if;

select lft, rgt
into droplft, droprgt
from plan_items
where lft = p_node;

/* reorder nodes in position ??? */
update plan_items set
lft = case
when lft between droplft and droprgt then
lft + newpos - droprgt - 1
when (lft < droplft) and (lft >= newpos) then
lft + (droprgt - droplft + 1)
when (lft > droprgt) and (lft < newpos) then
lft - (droprgt - droplft + 1)
else lft end,
rgt = case
when rgt between droplft and droprgt then
rgt + newpos - droprgt - 1
when (rgt < droplft) and (rgt >= newpos) then
rgt + (droprgt - droplft + 1)
when (rgt > droprgt) and (rgt < newpos) then
rgt - (droprgt - droplft + 1)
else rgt end;
end;
' language 'plpgsql';

--
ashley clark

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Tom Lane 2000-11-15 05:42:27 Re: Can this be done?
Previous Message Tom Lane 2000-11-15 04:35:05 Re: Re: [ANNOUNCE] [RELEASE ANNOUNCEMENT] v7.0.3 *Final* now Available