-- -- procedure category__change_parent/3 -- CREATE OR REPLACE FUNCTION category__change_parent( p_category_id integer, p_tree_id integer, p_parent_id integer ) RETURNS integer AS $$ DECLARE v_old_left_ind integer; v_old_right_ind integer; v_new_left_ind integer; v_new_right_ind integer; v_width integer; BEGIN update categories set parent_id = p_parent_id where category_id = p_category_id; -- first save the subtree, then compact tree, then expand tree to make room -- for subtree, then insert it select left_ind, right_ind into v_old_left_ind, v_old_right_ind from categories where category_id = p_category_id; v_width := v_old_right_ind - v_old_left_ind + 1; -- cut out old subtree update categories set left_ind = -left_ind, right_ind = -right_ind where tree_id = p_tree_id and left_ind >= v_old_left_ind and right_ind <= v_old_right_ind; -- compact parent trees update categories set right_ind = right_ind - v_width where tree_id = p_tree_id and left_ind < v_old_left_ind and right_ind > v_old_right_ind; -- compact right tree portion update categories set left_ind = left_ind - v_width, right_ind = right_ind - v_width where tree_id = p_tree_id and left_ind > v_old_left_ind; if (p_parent_id is null) then select 1, coalesce(max(right_ind)+1, 1) into v_new_left_ind, v_new_right_ind from categories where tree_id = p_tree_id and right_ind > 0; else select left_ind, right_ind into v_new_left_ind, v_new_right_ind from categories where category_id = p_parent_id; end if; -- move parent trees to make room update categories set right_ind = right_ind + v_width where tree_id = p_tree_id and left_ind <= v_new_left_ind and right_ind >= v_new_right_ind; -- move right tree portion to make room update categories set left_ind = left_ind + v_width, right_ind = right_ind + v_width where tree_id = p_tree_id and left_ind > v_new_right_ind; -- insert subtree at correct place update categories set left_ind = -left_ind + (v_new_right_ind - v_old_left_ind), right_ind = -right_ind + (v_new_right_ind - v_old_left_ind) where tree_id = p_tree_id and left_ind < 0; -- for debugging reasons perform category_tree__check_nested_ind(p_tree_id); return 0; END; $$ LANGUAGE plpgsql;