So I had previously run into a problem with Postgresql “money” type not being supported by default on postgrex. I solved that by creating a custom type and it has worked without problems for months. The database using this as a field type is not under my control, I just need to connect to it. There are 2 additional ecto repos on my side. I don’t use that type on my databases.
Now I’ve updated to elixir 1.9 (and started using the new releases, previously was using distillery) and I’m getting this error and I can’t figure out why (it also doesn’t seem to be related to that…).
Log:
[3202]: ** (MatchError) no match of right hand side value: false
[3202]: (postgrex) lib/postgrex/types.ex:128: anonymous fn/3 in Postgrex.Types.associate_type_infos/2
[3202]: (elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
[3202]: (postgrex) lib/postgrex/types.ex:127: Postgrex.Types.associate_type_infos/2
[3202]: (postgrex) lib/postgrex/type_server.ex:122: Postgrex.TypeServer.associate/2
[3202]: (stdlib) gen_server.erl:661: :gen_server.try_handle_call/4
[3202]: (stdlib) gen_server.erl:690: :gen_server.handle_msg/6
[3202]: (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
[3202]: Last message (from #PID<0.4393.0>): {:update, #Reference<0.3878870645.4258004993.73469>, [%Postgrex.TypeInfo{array_elem: 0, base_type: 0, comp_elems: [1043], input: "record_in", ....
(truncated it has a very long line of what I guess is type definitions from the db I’m connecting to…)
The type is being defined as such in another module:
Postgrex.Types.define(ExternalDB.PostgresTypes, [{Types.Money, [:decode_copy]}])
And the type itself is:
defmodule Types.Money do
@behaviour Postgrex.Extension
import Postgrex.BinaryUtils, warn: false
@int8_range -9223372036854775808..9223372036854775807
def init(opts) do
Keyword.get(opts, :decode_copy, :copy)
end
def matching(_state), do: [type: "money"]
def format(_state), do: :binary
def encode(_) do
range = Macro.escape(@int8_range)
quote location: :keep do
int when is_integer(int) and int in unquote(range) ->
case int * 100 do
n_int when n_int in unquote(range) ->
<<8 :: int32, int :: int64>>
other ->
raise DBConnection.EncodeError, Postgrex.Utils.encode_msg(other, unquote(range))
end
%Decimal{coef: coef} when is_integer(coef) and coef in unquote(range) ->
<<8 :: int32, coef :: int64>>
float when is_float(float) ->
case Decimal.new(float) do
%Decimal{coef: coef} when is_integer(coef) and coef in unquote(range) ->
<<8 :: int32, coef :: int64>>
%Decimal{coef: coef} ->
raise DBConnection.EncodeError, Postgrex.Utils.encode_msg(coef, unquote(range))
end
other ->
raise DBConnection.EncodeError, Postgrex.Utils.encode_msg(other, unquote(range))
end
end
def decode(_) do
quote location: :keep do
<<8 :: int32, int :: int64>> -> Decimal.div(Decimal.new(int), 100)
end
end
end
Then I set it up in a config that is used when starting a postgrex link.
new_config = %__MODULE__{base_config | table_type: :properties, config: List.keystore(base_config.config, :types, 0, {:types, ExternalDB.PostgresTypes})}
# ... somewhere else
{:ok, pid} = Postgrex.start_link(that_new_config)
Looking at https://github.com/elixir-ecto/postgrex/blob/9f068636277729e7f3314e4df5d7bd61fec6be13/lib/postgrex/types.ex#L133
Seems to indicate it is failing to insert a new ets entry for an oid (??)
for %TypeInfo{oid: oid} = type_info <- type_infos do
true = :ets.insert_new(table, {oid, type_info, nil})
end
This has been working fine for a long time, from ecto 2 to 3 and I can’t understand what is the error.