tasks/database/items-functions.sql
Emmanuel BENOîT 9677ad4dd3 Initial import of tasks application
This initial import is a heavily modified version of the code I had
here, as Arse was modified for other purposes in the meantime and the
application no longer worked with it.

In addition:
 * I did not import the user management part yet,
 * task dependencies are supported in-base, but there is no interface
for that yet.
2012-02-05 18:47:04 +01:00

276 lines
5.9 KiB
PL/PgSQL

--
-- Re-order items
-- * first create a temporary table containing text paths
-- * use that temporary table to re-order the main table
--
CREATE OR REPLACE FUNCTION reorder_items( )
RETURNS VOID
STRICT VOLATILE
SECURITY INVOKER
AS $$
DECLARE
i_id INT;
i_parent INT;
i_ordering INT;
i_path TEXT;
BEGIN
-- Create and fill temporary table
CREATE TEMPORARY TABLE items_ordering (
item_id INT NOT NULL PRIMARY KEY ,
item_ordering_path TEXT NOT NULL
) ON COMMIT DROP;
FOR i_id , i_parent , i_ordering IN
SELECT p.item_id , p.item_id_parent , p.item_ordering
FROM items p
INNER JOIN items_tree pt
ON pt.item_id_child = p.item_id
GROUP BY p.item_id , p.item_id_parent , p.item_ordering
ORDER BY MAX( pt.pt_depth )
LOOP
IF i_parent IS NULL THEN
i_path := '';
ELSE
SELECT INTO i_path item_ordering_path || '/' FROM items_ordering WHERE item_id = i_parent;
END IF;
i_path := i_path || to_char( i_ordering , '000000000000' );
INSERT INTO items_ordering VALUES ( i_id , i_path );
END LOOP;
-- Move all rows out of the way
UPDATE items SET item_ordering = item_ordering + (
SELECT 1 + 2 * max( item_ordering ) FROM items );
-- Re-order items
UPDATE items p1 SET item_ordering = 2 * p2.rn
FROM ( SELECT item_id , row_number() OVER( ORDER BY item_ordering_path ) AS rn FROM items_ordering ) p2
WHERE p1.item_id = p2.item_id;
END;
$$ LANGUAGE plpgsql;
-- Insert a item before another
CREATE OR REPLACE FUNCTION insert_item_before( i_name TEXT , i_before INT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $insert_item_before$
DECLARE
i_ordering INT;
i_parent INT;
BEGIN
PERFORM 1 FROM items FOR UPDATE;
SELECT INTO i_ordering , i_parent item_ordering - 1 , item_id_parent
FROM items
WHERE item_id = i_before;
IF NOT FOUND THEN
RETURN 2;
END IF;
BEGIN
INSERT INTO items ( item_name , item_id_parent , item_ordering )
VALUES ( i_name , i_parent , i_ordering );
EXCEPTION
WHEN unique_violation THEN
RETURN 1;
END;
PERFORM reorder_items( );
RETURN 0;
END;
$insert_item_before$ LANGUAGE plpgsql;
-- Insert item as the last child of another
CREATE OR REPLACE FUNCTION insert_item_under( i_name TEXT , i_parent INT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $insert_item_under$
DECLARE
i_ordering INT;
BEGIN
PERFORM 1 FROM items FOR UPDATE;
SELECT INTO i_ordering max( item_ordering ) + 1 FROM items;
BEGIN
INSERT INTO items ( item_name , item_id_parent , item_ordering )
VALUES ( i_name , i_parent , i_ordering );
EXCEPTION
WHEN unique_violation THEN
RETURN 1;
WHEN foreign_key_violation THEN
RETURN 2;
END;
PERFORM reorder_items( );
RETURN 0;
END;
$insert_item_under$ LANGUAGE plpgsql;
-- Add a item as the last root element
CREATE OR REPLACE FUNCTION insert_item_last( i_name TEXT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $insert_item_last$
DECLARE
i_ordering INT;
BEGIN
PERFORM 1 FROM items FOR UPDATE;
SELECT INTO i_ordering max( item_ordering ) + 1 FROM items;
IF i_ordering IS NULL THEN
i_ordering := 0;
END IF;
BEGIN
INSERT INTO items ( item_name , item_ordering )
VALUES ( i_name , i_ordering );
EXCEPTION
WHEN unique_violation THEN
RETURN 1;
END;
PERFORM reorder_items( );
RETURN 0;
END;
$insert_item_last$ LANGUAGE plpgsql;
-- Rename a item
CREATE OR REPLACE FUNCTION rename_item( i_id INT , i_name TEXT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $rename_item$
BEGIN
UPDATE items SET item_name = $2 WHERE item_id = $1;
RETURN 0;
EXCEPTION
WHEN unique_violation THEN
RETURN 1;
END
$rename_item$ LANGUAGE plpgsql;
-- Move a item before another
CREATE OR REPLACE FUNCTION move_item_before( i_id INT , i_before INT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $move_item_before$
DECLARE
i_ordering INT;
i_parent INT;
BEGIN
PERFORM 1 FROM items FOR UPDATE;
IF i_before = i_id THEN
RETURN 1;
ELSE
SELECT INTO i_ordering , i_parent item_ordering - 1 , item_id_parent
FROM items
WHERE item_id = i_before;
IF NOT FOUND THEN
RETURN 2;
END IF;
END IF;
BEGIN
UPDATE items SET item_ordering = i_ordering , item_id_parent = i_parent
WHERE item_id = i_id;
EXCEPTION
WHEN unique_violation THEN
RETURN 1;
END;
PERFORM reorder_items( );
RETURN 0;
END;
$move_item_before$ LANGUAGE plpgsql;
-- Move a item at the end of another's children
CREATE OR REPLACE FUNCTION move_item_under( i_id INT , i_parent INT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $move_item_under$
DECLARE
i_ordering INT;
BEGIN
PERFORM 1 FROM items FOR UPDATE;
IF i_parent = i_id THEN
RETURN 1;
ELSE
SELECT INTO i_ordering MAX( item_ordering ) + 1
FROM items
WHERE item_id_parent = i_parent;
IF i_ordering IS NULL THEN
i_ordering := 1;
END IF;
END IF;
BEGIN
UPDATE items SET item_ordering = i_ordering , item_id_parent = i_parent
WHERE item_id = i_id;
EXCEPTION
WHEN unique_violation THEN
RETURN 1;
WHEN foreign_key_violation THEN
RETURN 2;
END;
PERFORM reorder_items( );
RETURN 0;
END;
$move_item_under$ LANGUAGE plpgsql;
-- Move a item to the end of the tree
CREATE OR REPLACE FUNCTION move_item_last( i_id INT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $move_item_last$
DECLARE
i_ordering INT;
BEGIN
PERFORM 1 FROM items FOR UPDATE;
SELECT INTO i_ordering MAX( item_ordering ) + 1
FROM items;
IF i_ordering IS NULL THEN
i_ordering := 0;
END IF;
BEGIN
UPDATE items SET item_ordering = i_ordering , item_id_parent = NULL
WHERE item_id = i_id;
EXCEPTION
WHEN unique_violation THEN
RETURN 1;
END;
PERFORM reorder_items( );
RETURN 0;
END;
$move_item_last$ LANGUAGE plpgsql;
-- Delete a item, moving all children to the item's parent
CREATE OR REPLACE FUNCTION delete_item( i_id INT )
RETURNS VOID
STRICT VOLATILE
SECURITY DEFINER
AS $delete_item$
DECLARE
i_parent INT;
BEGIN
PERFORM 1 FROM items FOR UPDATE;
DELETE FROM items WHERE item_id = i_id;
PERFORM reorder_items( );
END;
$delete_item$ LANGUAGE plpgsql;