diff --git a/db/ptr.sql b/db/ptr.sql index c7d022c7..0952aec8 100644 --- a/db/ptr.sql +++ b/db/ptr.sql @@ -1,36 +1,20 @@ +-- Reverse DNS name of an address. Plain SQL (no STRICT, no sub-SELECT, only +-- immutable functions) so Postgres inlines it into the calling query; it +-- expands the address from the inet_send() wire bytes (4 header bytes, then +-- the address), so the netmask is ignored. Kept in sync with +-- serveradmin_extras/serveradmin_powerdns/migrations/0006_ptr_function.py. create or replace function public.ptr(intern_ip inet) returns text -immutable strict language plpgsql as $$ -declare - ip_part text; - ip_text text; - ip_arr text[]; - ip_filled boolean; -begin - if family(intern_ip) = 4 then - return ( - select string_agg(part, '.' order by ord desc) || '.in-addr.arpa' - from regexp_split_to_table(host(intern_ip), '\.') with ordinality as s(part, ord) - ); +language sql immutable parallel safe as $$ +select case family(intern_ip) + when 4 then + get_byte(inet_send(intern_ip), 7)::text || '.' || + get_byte(inet_send(intern_ip), 6)::text || '.' || + get_byte(inet_send(intern_ip), 5)::text || '.' || + get_byte(inet_send(intern_ip), 4)::text || '.in-addr.arpa' else - ip_text := ''; - ip_arr := regexp_split_to_array(host(intern_ip), ':'); - ip_filled = false; - - foreach ip_part in array ip_arr loop - if length(ip_part) = 0 and not ip_filled then - ip_text := ip_text || repeat('0', 32 - (array_length(ip_arr, 1) - 1) * 4); - ip_filled = true; - else - ip_text := ip_text || lpad(ip_part, 4, '0'); - end if; - end loop; - - return ( - select string_agg(part[1], '.' order by ord desc) || '.ip6.arpa' - from regexp_matches(ip_text, '.', 'g') with ordinality as s(part, ord) - ); - end if; -end; + regexp_replace(reverse(encode(substring(inet_send(intern_ip) from 5), 'hex')), '(.)', '\1.', 'g') + || 'ip6.arpa' +end $$; create index concurrently server_ptr_idx on public.server(public.ptr(intern_ip) text_pattern_ops);