-- Tables, data, and functions to test a nested interval implementation -- create table and data for testing the ni_* functions create table ni_data ( node ni_path not null unique , numer integer not null , denom integer not null , unique (numer,denom) ); insert into ni_data (node, numer, denom) values ('1',3,2); insert into ni_data (node, numer, denom) values ('1.1',7,4); insert into ni_data (node, numer, denom) values ('1.1.1',15,8); insert into ni_data (node, numer, denom) values ('1.1.1.1',31,16); insert into ni_data (node, numer, denom) values ('1.1.2',27,16); insert into ni_data (node, numer, denom) values ('1.1.3',51,32); insert into ni_data (node, numer, denom) values ('1.2',11,8); insert into ni_data (node, numer, denom) values ('1.2.1',23,16); insert into ni_data (node, numer, denom) values ('1.3',19,16); insert into ni_data (node, numer, denom) values ('2',3,4); insert into ni_data (node, numer, denom) values ('2.1',7,8); insert into ni_data (node, numer, denom) values ('2.1.1',15,16); insert into ni_data (node, numer, denom) values ('2.2',11,16); insert into ni_data (node, numer, denom) values ('2.3',19,32); insert into ni_data (node, numer, denom) values ('3',3,8); insert into ni_data (node, numer, denom) values ('3.1',7,16); insert into ni_data (node, numer, denom) values ('3.2',11,32); -- folders table and associated functions create table folders ( folder_name text not null unique , num integer not null , den integer not null , unique (num,den) ); -- initialize the tree insert into folders (folder_name, num, den) values ('root', 3,2); create or replace function insert_folder ( text -- parent_folder_name , text -- new_folder_name ) returns void language plpgsql as ' declare parent_folder_name alias for $1; new_folder_name alias for $2; parent_folder_rational record; new_child_number integer; begin select num, den into parent_folder_rational from folders where folder_name = parent_folder_name; select (count(folder_name) + 1)::integer into new_child_number from folders where ni_parent_numer(num, den) = parent_folder_rational.num and ni_parent_denom(num,den) = parent_folder_rational.den; insert into folders (folder_name, num, den) values ( new_folder_name , ni_child_numer( parent_folder_rational.num , parent_folder_rational.den , new_child_number ) , ni_child_denom( parent_folder_rational.num , parent_folder_rational.den , new_child_number ) ); return; end; '; select insert_folder('root','usr'); select insert_folder('usr','local'); select insert_folder('local','src'); select insert_folder('local','pgsql'); select insert_folder('pgsql','bin'); select insert_folder('pgsql','data'); select insert_folder('pgsql','doc'); select insert_folder('doc','html'); select insert_folder('pgsql','include'); select insert_folder('pgsql','lib'); select insert_folder('pgsql','share'); create or replace view folder_hierarchy as select folder_name , num , den , num || '/' || den as folder_rational , repeat(' ',ni_distance(num,den, 3,2)) || folder_name as folder_name_ , ni_path(num,den) as folder_path from folders order by folder_path; create or replace function delete_folder ( text -- folder_name ) returns boolean language plpgsql as ' declare old_folder_name alias for $1; old_folder_child_number integer; sibling_count integer; old_folder record; parent_folder record; old_folder_child_count integer; old_folder_document_count integer; old_child record; new_child record; begin select num, den into old_folder from folders where folder_name = old_folder_name; select (count(folder_name))::integer into old_folder_child_count from folders where ni_parent_numer(num, den) = old_folder.num and ni_parent_denom(num, den) = old_folder.den; -- check to make sure the folder is empty (it has no children) -- and it is not the root folder, raising exceptions in either case if old_folder_child_count = 0 and old_folder.num <> 3 and old_folder.den <> 2 then select ni_parent_numer(old_folder.num,old_folder.den) as num , ni_parent_denom(old_folder.num,old_folder.den) as den into parent_folder; select (count(folder_name))::integer into sibling_count from folders where ni_parent_numer(num, den) = parent_folder.num and ni_parent_denom(num,den) = parent_folder.den; old_folder_child_number := ni_sibling_number(old_folder.num, old_folder.den); delete from folders where folder_name = old_folder_name; if (sibling_count - old_folder_child_number) > 1 then -- There are younger siblings of the deleted folder. -- Promote each by one child number to fill the -- hole left by the deleted folder for i in (old_folder_child_number + 1)..sibling_count loop select ni_child_numer(parent_folder.num, parent_folder.den, i) as num , ni_child_denom (parent_folder.num, parent_folder.den, i) as den into old_child; select ni_child_numer(parent_folder.num, parent_folder.den, i - 1) as num , ni_child_denom (parent_folder.num, parent_folder.den, i - 1) as den into new_child; update folders set num = ni_new_numer( num, den , old_child.num, old_child.den , new_child.num, new_child.den ) , den = ni_new_denom( num, den , old_child.num, old_child.den , new_child.num, new_child.den ) where ni_distance( num,den, old_child.num,old_child.den) >= 0; end loop; end if; return true; elsif (old_folder_child_count) <> 0 then raise exception ''Cannot delete non-empty folder.''; elsif (old_folder.num = 3 and old_folder.den = 2) then raise exception ''Cannot delete root folder.''; end if; end; ';