DROP TABLE foo; CREATE TABLE foo ( id INTEGER, parent INTEGER, name TEXT ); INSERT INTO foo VALUES (1, 1, ''); INSERT INTO foo VALUES (2, 1, 'a'); INSERT INTO foo VALUES (3, 2, 'b'); INSERT INTO foo VALUES (4, 3, 'c'); INSERT INTO foo VALUES (5, 3, 'C'); INSERT INTO foo VALUES (6, 1, 'x'); INSERT INTO foo VALUES (7, 6, 'y'); INSERT INTO foo VALUES (8, 7, 'z'); INSERT INTO foo VALUES (9, 7, 'Z'); DROP FUNCTION name2oid(TEXT); CREATE FUNCTION name2oid(TEXT) RETURNS INTEGER LANGUAGE 'plpgsql' STABLE AS ' DECLARE comp TEXT; path TEXT; oid INTEGER; BEGIN RAISE NOTICE ''name2oid(%)'', $1; path := $1; IF substr(path, 1, 1) != ''/'' THEN RAISE EXCEPTION ''name2oid(%): path not starting with slash'', $1; END IF; oid := (SELECT id FROM foo WHERE name = '''' AND parent = id); IF oid IS NULL THEN RAISE EXCEPTION ''name2oid(%): root path component not found'', $1; END IF; path := substr(path, 2); -- RAISE NOTICE ''name2oid: "/" -> %'', oid; WHILE path != '''' LOOP comp := substring(path from ''^([^/]+)/*''); path := substring(path from ''^[^/]+/*(.*)$''); oid := (SELECT id FROM foo WHERE name = comp AND parent = oid); IF oid IS NULL THEN RAISE EXCEPTION ''name2oid(%): path component "%" not found'', $1, comp, path; END IF; -- RAISE NOTICE ''name2oid: "%" -> %'', comp, oid; END LOOP; RAISE NOTICE ''name2oid(%) = %'', $1, oid; RETURN oid; END; '; DROP FUNCTION oid2name(TEXT); CREATE FUNCTION oid2name(TEXT) RETURNS TEXT LANGUAGE 'plpgsql' AS ' DECLARE oid INTEGER; name TEXT; obj RECORD; BEGIN RAISE NOTICE ''oid2name(%)'', $1; oid := $1; name := ''''; LOOP SELECT * INTO obj FROM foo WHERE id = oid; IF NOT FOUND THEN RAISE EXCEPTION ''oid2name(%): object % not found'', $1, oid; END IF; -- RAISE NOTICE ''oid2name: % -> "%"'', oid, obj.name; IF obj.parent = oid THEN EXIT; END IF; name := ''/'' || obj.name || name; oid := obj.parent; END LOOP; IF name = '''' THEN name = ''/''; END IF; RAISE NOTICE ''oid2name(%) = %'', $1, name; RETURN name; END; '; SELECT * FROM foo WHERE id = (SELECT name2oid('/')); SELECT * FROM foo WHERE id = (SELECT name2oid('/a/b/c')); SELECT * FROM foo WHERE id = (SELECT name2oid('/x/y/z')); SELECT oid2name(1); SELECT oid2name(4); SELECT oid2name(8); SELECT *,oid2name(id) from foo; BEGIN TRANSACTION; SELECT * FROM foo WHERE id = name2oid('/x/y/z'); SELECT * FROM foo WHERE id = name2oid('/x/y/z'); COMMIT; DROP FUNCTION fuck(TEXT); CREATE FUNCTION fuck(TEXT) RETURNS TEXT LANGUAGE 'plpgsql' STABLE AS ' DECLARE foo RECORD; BEGIN RAISE NOTICE ''fuck''; SELECT * INTO foo FROM foo; RETURN foo.name; END; '; BEGIN TRANSACTION; SELECT * FROM foo WHERE fuck('foo') != 'fuck'; SELECT * FROM foo WHERE fuck('foo') != 'fuck'; SELECT * FROM foo WHERE fuck('foo') != 'fuck'; COMMIT;