Can this be done?
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
Ashley Clark <aclark@ghoti.org> writes:
Can I defer constraint checking on unique indexes?
No, not at present. Consider restructuring your UPDATE into sequential
steps so that the intermediate states can't cause index failures. Or
just don't make the index unique...
regards, tom lane
* Tom Lane in "Re: [GENERAL] Can this be done?" dated 2000/11/15 00:42
* wrote:
Ashley Clark <aclark@ghoti.org> writes:
Can I defer constraint checking on unique indexes?
No, not at present. Consider restructuring your UPDATE into
sequential steps so that the intermediate states can't cause index
failures. Or just don't make the index unique...
Ok, I can live with that. Is this something that's planned for in the
future?
--
shaky recall