Erlang: binary_to_term explanation

48 Views Asked by At

I've some old elrang (17.1) project on my hand and I need some help understanding some parts of the code.

Using it I'm creating a object in sets table with those values

{:name=>"TestCurrencies", :value=>["usd", " eur", " pln"] (and uuids of course)

(value is stored as a bytea in Postgres DB)

insert_and_return_record(Resource) ->
    #?model_name{account_uuid=AccountUuid, name=Name, value=Value} = Resource,
    Uuid = digits:uuid(AccountUuid),
    LowerValue = to_lower(Value),
    Statement = "INSERT INTO sets(uuid, account_uuid, name, value) VALUES($1, $2, $3, $4)",
    {ok, 1} = bep_db:execute(Statement, [Uuid, AccountUuid, Name, term_to_binary(LowerValue)]),
    get_record(AccountUuid, Uuid).

This code generates this entry in the db

cdbee9cb-fc84-53a9-8e8b-22c90a76b211 | a9dbb489-4a97-5b15-bfcf-ca558e01687c | TestCurrencies | \x836c000000036d000000037573646d00000004206575726d0000000420706c6e6a

And while

get_record(AccountUuid, Uuid) ->
    Statement = "SELECT uuid, account_uuid, name, value FROM sets WHERE account_uuid=$1 AND uuid=$2",
    {ok, _Columns, Rows} = bep_db:execute(Statement, [AccountUuid, Uuid]),
    case Rows of
        [] ->
            {error, no_exists};
        [{Uuid, AccountUuid, Name, Value}] ->
            #?model_name{uuid=Uuid, account_uuid=AccountUuid, name=Name, value=binary_to_term(Value)}
    end.

Does return proper values, but manually running

binary_to_term("\x836c000000036d000000037573646d00000004206575726d0000000420706c6e6a"). returns bad_argument error.

Getting it directly from db with

SELECT encode(value, 'escape') FROM sets WHERE uuid = 'cdbee9cb-fc84-53a9-8e8b-22c90a76b211'; returns

\203l\000\000\000\x03m\000\000\000\x03usdm\000\000\000\x04 eurm\000\000\000\x04 plnj

Could anybody explain to me why is it like that? Is there a way to get the proper value only using SQL?
Other project written in Ruby needs to communicate with the same db and get the proper values, could it be possible?

I've tried searching the issue, tried manually running it in erlang console. I've tried using SQL.

1

There are 1 best solutions below

0
Dogbert On

The notation in the text

\x836c000000036d000000037573646d00000004206575726d0000000420706c6e6a

is \x followed by hex encoded binary data. To decode this manually, you can do remove the \x and pass it to binary:decode_hex as a binary:

1> binary_to_term(binary:decode_hex(<<"836c000000036d000000037573646d00000004206575726d0000000420706c6e6a">>)).
[<<"usd">>,<<" eur">>,<<" pln">>]

To get the same value with raw SQL, you can do encode(value, 'hex'):

SELECT encode(value, 'hex') FROM sets WHERE uuid = 'cdbee9cb-fc84-53a9-8e8b-22c90a76b211';

Other project written in Ruby needs to communicate with the same db and get the proper values, could it be possible?

You would need to either find a library or write a parser that can parse the Erlang External Term Format (https://www.erlang.org/doc/apps/erts/erl_ext_dist.html) for this.