Trying to translate a uint256 number which is encoded as a 64-char / 256-bit hex.
Eventually the result should be stored in a numeric(78,0) which is enough to encode an uint256.
For smaller hex-strings there’s pretty direct ways to encode to int4/int8 but this won’t do here.
Therefore trying to chunk the hex up in 4 64-bit parts, which can all be represented by a int8. Then glue it up with some bitshifting and done.
Unfortunately didn’t realise int8 is signed so that gives me wrong results (code below).
I guess I could chunk the hex up in smaller parts and make it work with a lot of hassle, but by now I’m wondering that there must somehow be a better way. Anyone?
-- 1. Split 256 bits into 4 seperate parts which are represented by int8's which can all hold 64 bits (4 * 64 = 256)
-- 2. cast int8 to numeric(78,0) which can hold a uint256, and some bitshifting (but not really since not supported by numeric) to get all parts
-- 3. add up the parts to arrive at the final number
--
-- WRONG RESULT: since int8 are signed.
select
val_a + val_b + val_c + val_d as value
from(
select
-- concat('x', substr(value, 0, 64))::bit(256) value_as_bits, -- all data as 256 bits
concat('x', substr(value, 0, 16))::bit(64)::int8::numeric(78,0) * 2^48::numeric(78,0) val_a,
concat('x', substr(value, 0 + 16, 16))::bit(64)::int8::numeric(78,0) * 2^32::numeric(78,0) val_b,
concat('x', substr(value, 0 + 32, 16))::bit(64)::int8::numeric(78,0) * 2^16::numeric(78,0) val_c,
concat('x', substr(value, 0 + 48, 16))::bit(64)::int8::numeric(78,0) val_d -- '-8257646570878140416' issue here since int8 is not unsigned
from (
select '000000000000000000000000000000000000000015b19218d66f231d61600000' as value -- hex representation of an unsigned 256 bit number
) as x
) as x;
;
2
Answers
To answer my own question:
I'll be performance testing this and will leave open in the meantime
Introduction
You can do something like
The following sections will cover cases when even
bigint
would not be enough.Sample schema
Explanation:
temp
pk
is aprimary key
which will be useful later to determine the position of each digitch
is a char representing the hexa digitfk
is a foreign key, a one-way vertex towards the original tableind
is an initially uninitialized field, which will turn out to be the inverted digit index in order to be able to determine which power of 16 should we multiply the numeric value ofch
withtemp
table with two rows, using some hard-coded values in our example both for the actual hexa number and the foreign keytemp
in order to compute and store the appropriate value ofind
The query
Explanation:
ch
into a numerical valuefk
in order to make sure that we get the individual value for eachfk
sum
the computed representative digit value for eachfk
groupNote, here we sum the values. If you experience any problems with this, feel free to convert the digits into textual and concat them with
string_agg
. You should aim to the simpler approach if possible and resort to this one only if any easier approach fails.