-- The index on container_id is not very good -- and in some cases can be quite detrimental -- see http://openacs.org/forums/message-view?message_id=142769 drop index group_elem_idx_container_idx; -- There is already a unique constraint on context_id, object_id so the explicitly added one -- is not needed... -- drop index acs_objects_context_object_idx; -- recreate acs_objects_get_tree_sortkey with isstrict, iscachable. -- create or replace function acs_objects_get_tree_sortkey(integer) returns varbit as ' declare p_object_id alias for $1; begin return tree_sortkey from acs_objects where object_id = p_object_id; end;' language 'plpgsql' with (isstrict, iscachable); ------------------------------------------------------------ -- -- 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 -- CREATE TABLE tmp_newtree as SELECT object_id, int_to_tree_key(object_id+1000) as tree_sortkey FROM acs_objects where context_id is null; --now add an index on object_id since we need it for the next function... create unique index tmp_newtree_idx on tmp_newtree(object_id); create or replace function __tmp_newtree() returns integer as ' DECLARE ngen integer; nrows integer; totrows integer; rec record; childkey varbit; last_context integer; BEGIN totrows := 0; ngen := 0; LOOP ngen := ngen + 1; nrows := 0; last_context := -9999; -- loop over those which have a parent in newtree but are not themselves in newtree. FOR rec IN SELECT o.object_id, o.context_id, n.tree_sortkey FROM acs_objects o, tmp_newtree n WHERE n.object_id = o.context_id and not exists (select 1 from tmp_newtree e where e.object_id = o.object_id) ORDER BY o.context_id, o.object_id LOOP if last_context = rec.context_id THEN childkey := tree_increment_key(childkey); else childkey := tree_increment_key(null); last_context := rec.context_id; end if; insert into tmp_newtree values (rec.object_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_newtree(); drop function __tmp_newtree(); -- make sure unique constraint can be added ALTER TABLE tmp_newtree add constraint tmp_newtree_sk_un unique(tree_sortkey); -- compute the new maxchilds. CREATE TABLE tmp_maxchild as SELECT context_id as object_id, max(tree_leaf_key_to_int(t.tree_sortkey)) as max_child_sortkey FROM acs_objects o, tmp_newtree t where t.object_id = o.object_id GROUP BY context_id; create index tmp_maxchild_idx on tmp_maxchild(object_id); -- we are going to use a unique constraint on this column now drop index acs_objs_tree_skey_idx; -- Drop the triggers on acs_objects -- -- these change anyway -- drop trigger acs_objects_context_id_up_tr on acs_objects; drop function acs_objects_context_id_up_tr(); drop trigger acs_objects_update_tr on acs_objects; drop function acs_objects_update_tr(); drop trigger acs_objects_insert_tr on acs_objects; drop function acs_objects_insert_tr(); -- -- don't want to mess up modification dates. -- drop trigger acs_objects_last_mod_update_tr on acs_objects; drop function acs_objects_last_mod_update_tr(); -- add the max_child_sortkey -- alter table acs_objects add max_child_sortkey varbit; -- Actually update the tree_sortkeys in acs_objects... -- UPDATE acs_objects SET tree_sortkey = (select tree_sortkey from tmp_newtree n where n.object_id = acs_objects.object_id), max_child_sortkey = (select int_to_tree_key(max_child_sortkey) from tmp_maxchild n where n.object_id = acs_objects.object_id); -- Drop the temp tables as we no longer need them... -- drop table tmp_newtree; drop table tmp_maxchild; -- add back the unique not null constraint on tree_sortkey -- ALTER TABLE acs_objects add constraint acs_objects_tree_sortkey_un unique(tree_sortkey); ALTER TABLE acs_objects ALTER COLUMN tree_sortkey SET NOT NULL; -- Recreate the triggers -- create function acs_objects_last_mod_update_tr () returns opaque as ' begin new.last_modified := now(); return new; end;' language 'plpgsql'; create trigger acs_objects_last_mod_update_tr before update on acs_objects for each row execute procedure acs_objects_last_mod_update_tr (); create function acs_objects_insert_tr() returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; begin if new.context_id is null then new.tree_sortkey := int_to_tree_key(new.object_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM acs_objects WHERE object_id = new.context_id FOR UPDATE; UPDATE acs_objects SET max_child_sortkey = v_max_child_sortkey WHERE object_id = new.context_id; new.tree_sortkey := v_parent_sk || v_max_child_sortkey; end if; new.max_child_sortkey := null; return new; end;' language 'plpgsql'; create trigger acs_objects_insert_tr before insert on acs_objects for each row execute procedure acs_objects_insert_tr (); -- -- create function acs_objects_update_tr() returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; v_old_parent_length integer; begin if new.object_id = old.object_id and ( new.context_id = old.context_id or (new.context_id is null and old.context_id is null) ) then return new; end if; -- 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.context_id is null then v_parent_sk := int_to_tree_key(new.object_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM acs_objects WHERE object_id = new.context_id FOR UPDATE; UPDATE acs_objects SET max_child_sortkey = v_max_child_sortkey WHERE object_id = new.context_id; v_parent_sk := v_parent_sk || v_max_child_sortkey; end if; UPDATE acs_objects 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 acs_objects_update_tr after update on acs_objects for each row execute procedure acs_objects_update_tr (); create or replace function acs_objects_context_id_up_tr () returns opaque as ' declare pair record; outer record; inner record; security_context_root integer; begin if new.object_id = old.object_id and ((new.context_id = old.context_id) or (new.context_id is null and old.context_id is null)) and new.security_inherit_p = old.security_inherit_p then return new; end if; -- Remove my old ancestors from my descendants. for outer in select object_id from acs_object_context_index where ancestor_id = old.object_id and object_id <> old.object_id loop for inner in select ancestor_id from acs_object_context_index where object_id = old.object_id and ancestor_id <> old.object_id loop delete from acs_object_context_index where object_id = outer.object_id and ancestor_id = inner.ancestor_id; end loop; end loop; -- Kill all my old ancestors. delete from acs_object_context_index where object_id = old.object_id; insert into acs_object_context_index (object_id, ancestor_id, n_generations) values (new.object_id, new.object_id, 0); if new.context_id is not null and new.security_inherit_p = ''t'' then -- Now insert my new ancestors for my descendants. for pair in select * from acs_object_context_index where ancestor_id = new.object_id LOOP insert into acs_object_context_index (object_id, ancestor_id, n_generations) select pair.object_id, ancestor_id, n_generations + pair.n_generations + 1 as n_generations from acs_object_context_index where object_id = new.context_id; end loop; else security_context_root = acs__magic_object_id(''security_context_root''); if new.object_id != security_context_root then -- We need to make sure that new.OBJECT_ID and all of its -- children have security_context_root as an ancestor. for pair in select * from acs_object_context_index where ancestor_id = new.object_id LOOP insert into acs_object_context_index (object_id, ancestor_id, n_generations) values (pair.object_id, security_context_root, pair.n_generations + 1); end loop; end if; end if; return new; end;' language 'plpgsql'; create trigger acs_objects_context_id_up_tr after update on acs_objects for each row execute procedure acs_objects_context_id_up_tr ();