====== tag_path(int) ====== **Extract the tag name with its hierarchy.** \\ This recursive function takes the ID of a tag and returns its full name, including its hierarchy. CREATE OR REPLACE FUNCTION tag_path(in_tag_id INTEGER) RETURNS text AS $$ DECLARE r text; id INTEGER; BEGIN IF in_tag_id IS NULL THEN RETURN null; END IF; SELECT name, parent_id INTO r,id FROM tags WHERE tag_id=in_tag_id; IF (id IS NULL) THEN RETURN r; ELSE RETURN tag_path(id)||'->'||coalesce(r,''); END IF; END; $$ LANGUAGE plpgsql STABLE; Example: SELECT tag_id,tag_path(tag_id) FROM tags ORDER BY 2 will retrieve all tags sorted and formatted as in the "Current messsages" tree in the Quick selection panel of the user interface. ====== tag_depth(int) ====== **Returns the depth of a tag inside its hierarchy**. \\ This recursive function takes the ID of a tag and returns its depth inside its hierarchy, starting by 1 for top-level tags. CREATE OR REPLACE FUNCTION tag_depth(in_tag_id INTEGER) RETURNS INT AS $$ DECLARE id INTEGER; BEGIN IF in_tag_id IS NULL THEN RETURN NULL; END IF; SELECT parent_id INTO id FROM tags WHERE tag_id=in_tag_id; IF (id IS NULL) THEN RETURN 1; ELSE RETURN 1+tag_depth(id); END IF; END; $$ LANGUAGE plpgsql STABLE STRICT; ====== tag_id(text) ====== **Returns the ID of a tag from its full hierarchical name (case insensitive).** \\ This is the inverse function of tag_path(int). If the name is not found, it returns null. CREATE OR REPLACE FUNCTION tag_id(in_tag_path text) RETURNS integer AS $$ DECLARE id INTEGER:=null; component text; BEGIN FOR component IN SELECT regexp_split_to_table(in_tag_path, '->') LOOP SELECT tag_id FROM tags WHERE upper(NAME)=upper(component) AND parent_id is not distinct from id INTO id; END LOOP; RETURN id; END; $$ LANGUAGE plpgsql STABLE STRICT; ====== child_tags(int) ====== **Return all childs of a tag.** \\ Takes the ID of a tag or null to designate the root of all tags. Returns the set of child tags. create function child_tags(top_id integer) returns setof integer as $$ WITH RECURSIVE tagr(_tag_id) as ( select tag_id from tags where parent_id is not distinct from top_id UNION ALL select tag_id FROM tags JOIN tagr ON tagr._tag_id=tags.parent_id ) select _tag_id FROM tagr; $$ language sql stable ====== get_header_line() ====== **Extract entries from a mail header.** \\ This function takes a mail_id and the name of a header field and returns all corresponding header entries for this message. CREATE FUNCTION get_header_line(int, text) RETURNS SETOF text AS $$ SELECT (regexp_matches(lines, '^'||$2||': (.*?)$', 'gni'))[1] FROM header WHERE mail_id=$1; $$ LANGUAGE sql;