Yet another conversion function. The idea is to reduce the number of steps in the loop, and hence the number of arithmetic operations.
create or replace function hex_to_numeric(str text)
returns numeric
language plpgsql immutable strict as $$
declare
i int;
n int = length(str)/ 8;
res dec = 0;
begin
str := lpad($1, (n+ 1)* 8, '0');
for i in 0..n loop
res:= res * 4294967296; -- hex 100000000
res:= res + concat('x', substr(str, i* 8+ 1, 8))::bit(32)::bigint::dec;
end loop;
return res;
end $$;
Some tests:
select hex, hex_to_numeric(hex)
from (
values ('ff'::text),
('7fffffff'),
('80000000'),
('deadbeef'),
('7fffffffffffffff'),
('8000000000000000'),
('ffffffffffffffff'),
('ffffffffffffffff123'),
('4540a085e7334d6494dd6a7378c579f6')
) t(hex);
hex | hex_to_numeric
----------------------------------+----------------------------------------
ff | 255
7fffffff | 2147483647
80000000 | 2147483648
deadbeef | 3735928559
7fffffffffffffff | 9223372036854775807
8000000000000000 | 9223372036854775808
ffffffffffffffff | 18446744073709551615
ffffffffffffffff123 | 75557863725914323415331
4540a085e7334d6494dd6a7378c579f6 | 92052294502540680826164862654582454774
(9 rows)
The function is 5-10 times faster than the plpgsql functions in the other answers (depending on the length of hex values).