------------------------------------------------------------ -- Upgrade to enhance the performance of the acs-content-repository when adding / editing an -- cr_item, special fix for postgres to avoid using max() which is quite slow. -- Now update tree_sortkey in the process fix dups and add max_child_sortkey -- -- We need a table for the new tree_sortkey -- -- Get the root nodes specially -- Both cases, when the parent is 0 but is an cr_item, and when the parent is a non cr_item CREATE TABLE tmp_crnewtree as SELECT item_id, int_to_tree_key(item_id+1000) as tree_sortkey FROM cr_items where parent_id = 0 UNION SELECT cr.item_id, int_to_tree_key(cr.parent_id+1000) || int_to_tree_key(cr.item_id+1000) as tree_sortkey FROM cr_items cr where cr.parent_id <> 0 and not exists (select 1 from cr_items cri where cri.item_id = cr.parent_id) ; --now add an index on item_id since we need it for the next function... create unique index tmp_crnewtree_idx on tmp_crnewtree(item_id); create or replace function __tmp_crnewtree() returns integer as ' DECLARE ngen integer; nrows integer; totrows integer; rec record; childkey varbit; last_parent integer; BEGIN totrows := 0; ngen := 0; LOOP ngen := ngen + 1; nrows := 0; last_parent := -9999; -- loop over those which have a parent in crnewtree but are not themselves in crnewtree. FOR rec IN SELECT cr.item_id, cr.parent_id, n.tree_sortkey FROM cr_items cr, tmp_crnewtree n WHERE n.item_id = cr.parent_id and not exists (select 1 from tmp_crnewtree e where e.item_id = cr.item_id) ORDER BY cr.parent_id, cr.tree_sortkey LOOP if last_parent = rec.parent_id THEN childkey := tree_increment_key(childkey); else childkey := tree_increment_key(null); last_parent := rec.parent_id; end if; insert into tmp_crnewtree values (rec.item_id, rec.tree_sortkey || childkey); if (nrows % 5000) = 0 and nrows > 0 then raise notice ''ngen % row %'',ngen,nrows; end if; nrows := nrows + 1; END LOOP; totrows := totrows + nrows; raise notice ''ngen % totrows %'',ngen,nrows; if nrows = 0 then exit; end if; END LOOP; return totrows; end;' language plpgsql; select __tmp_crnewtree(); drop function __tmp_crnewtree(); -- make sure unique constraint can be added ALTER TABLE tmp_crnewtree add constraint tmp_crnewtree_sk_un unique(tree_sortkey); -- compute the new maxchilds. CREATE TABLE tmp_crmaxchild as SELECT parent_id as item_id, max(tree_leaf_key_to_int(t.tree_sortkey)) as max_child_sortkey FROM cr_items cr, tmp_crnewtree t where t.item_id = cr.item_id GROUP BY parent_id; create index tmp_crmaxchild_idx on tmp_crmaxchild(item_id); -- we are going to use a unique constraint on this column now drop index cr_sortkey_idx; -- Drop the related triggers on cr_items -- drop trigger cr_items_tree_update_tr on cr_items; drop function cr_items_tree_update_tr(); drop trigger cr_items_tree_insert_tr on cr_items; drop function cr_items_tree_insert_tr(); -- -- add the max_child_sortkey -- alter table cr_items add max_child_sortkey varbit; -- Update the tree_sortkeys in cr_items... -- UPDATE cr_items SET tree_sortkey = (select tree_sortkey from tmp_crnewtree n where n.item_id = cr_items.item_id), max_child_sortkey = (select int_to_tree_key(max_child_sortkey) from tmp_crmaxchild n where n.item_id = cr_items.item_id); -- Drop the temp tables as we no longer need them... -- drop table tmp_crnewtree; drop table tmp_crmaxchild; -- add back the unique not null constraint on tree_sortkey -- ALTER TABLE cr_items add constraint cr_items_tree_sortkey_un unique(tree_sortkey); ALTER TABLE cr_items ALTER COLUMN tree_sortkey SET NOT NULL; -- Recreate the triggers -- create function cr_items_tree_insert_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; v_parent_id integer default null; begin select item_id into v_parent_id from cr_items where item_id = new.parent_id; if new.parent_id = 0 then new.tree_sortkey := int_to_tree_key(new.item_id+1000); elsif v_parent_id is null then new.tree_sortkey := int_to_tree_key(new.parent_id+1000) || int_to_tree_key(new.item_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM cr_items WHERE item_id = new.parent_id FOR UPDATE; UPDATE cr_items SET max_child_sortkey = v_max_child_sortkey WHERE item_id = new.parent_id; new.tree_sortkey := v_parent_sk || v_max_child_sortkey; end if; return new; end;' language 'plpgsql'; create trigger cr_items_tree_insert_tr before insert on cr_items for each row execute procedure cr_items_tree_insert_tr (); -- -- create function cr_items_tree_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; v_parent_id integer default null; v_old_parent_length integer; begin if new.item_id = old.item_id and ((new.parent_id = old.parent_id) or (new.parent_id is null and old.parent_id is null)) then return new; end if; select item_id into v_parent_id from cr_items where item_id = new.parent_id; -- the tree sortkey is going to change so get the new one and update it and all its -- children to have the new prefix... v_old_parent_length := length(new.tree_sortkey) + 1; if new.parent_id = 0 then v_parent_sk := int_to_tree_key(new.item_id+1000); elsif v_parent_id is null then v_parent_sk := int_to_tree_key(new.parent_id+1000) || int_to_tree_key(new.item_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM cr_items WHERE item_id = new.parent_id FOR UPDATE; UPDATE cr_items SET max_child_sortkey = v_max_child_sortkey WHERE item_id = new.parent_id; v_parent_sk := v_parent_sk || v_max_child_sortkey; end if; UPDATE cr_items SET tree_sortkey = v_parent_sk || substring(tree_sortkey, v_old_parent_length) WHERE tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); return new; end;' language 'plpgsql'; create trigger cr_items_tree_update_tr after update on cr_items for each row execute procedure cr_items_tree_update_tr ();