CREATE OR REPLACE FUNCTION tree_child(integer[2], integer) RETURNS integer[2] AS ' DECLARE node ALIAS FOR $1; child ALIAS FOR $2; BEGIN RETURN ARRAY[ node[1] * (2 << child) + 3 - (2 << child), node[2] * (2 << child) ]; END; ' LANGUAGE plpgsql IMMUTABLE RETURNS NULL ON NULL INPUT; CREATE OR REPLACE FUNCTION tree_parent(integer[2]) RETURNS integer[2] AS ' DECLARE node ALIAS FOR $1; parent integer[2]; BEGIN IF node[1] = 3 THEN RETURN NULL; END IF; parent := ARRAY[ (node[1]-1) >> 1, node[2] >> 1 ]; WHILE (parent[1]-1) % 4 = 0 LOOP parent := ARRAY[ (parent[1]+1) >> 1, parent[2] >> 1 ]; END LOOP; RETURN parent; END; ' LANGUAGE plpgsql IMMUTABLE RETURNS NULL ON NULL INPUT; CREATE OR REPLACE FUNCTION tree_distance(integer[2], integer[2]) RETURNS integer AS ' DECLARE child ALIAS FOR $1; parent ALIAS FOR $2; BEGIN IF child IS NULL THEN RETURN NULL; END IF; IF child[1] = parent[1] AND child[2] = parent[2] THEN RETURN 0; END IF; RETURN 1 + tree_distance( tree_parent(child), parent ); END; ' LANGUAGE plpgsql IMMUTABLE RETURNS NULL ON NULL INPUT;