Packages
postgrex
0.20.0
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.0
0.19.3
0.19.2
0.19.1
0.19.0
0.18.0
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.13
0.15.12
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.13.0-rc.0
0.12.2
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.2
PostgreSQL driver for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/postgrex/extensions/hstore.ex
defmodule Postgrex.Extensions.HStore do
@moduledoc false
import Postgrex.BinaryUtils, warn: false
use Postgrex.BinaryExtension, type: "hstore"
def init(opts), do: Keyword.fetch!(opts, :decode_binary)
def encode(_) do
quote location: :keep do
%{} = map ->
data = unquote(__MODULE__).encode_hstore(map)
[<<IO.iodata_length(data)::int32()>> | data]
other ->
raise DBConnection.EncodeError, Postgrex.Utils.encode_msg(other, "a map")
end
end
def decode(mode) do
quote do
<<len::int32(), data::binary-size(len)>> ->
unquote(__MODULE__).decode_hstore(data, unquote(mode))
end
end
## Helpers
def encode_hstore(hstore_map) do
keys_and_values =
Enum.reduce(hstore_map, "", fn {key, value}, acc ->
[acc, encode_hstore_key(key), encode_hstore_value(value)]
end)
[<<map_size(hstore_map)::int32()>> | keys_and_values]
end
defp encode_hstore_key(key) when is_binary(key) do
encode_hstore_value(key)
end
defp encode_hstore_key(key) when is_nil(key) do
raise ArgumentError, "hstore keys cannot be nil!"
end
defp encode_hstore_value(nil) do
<<-1::int32()>>
end
defp encode_hstore_value(value) when is_binary(value) do
value_byte_size = byte_size(value)
<<value_byte_size::int32()>> <> value
end
def decode_hstore(<<_length::int32(), pairs::binary>>, :reference) do
decode_hstore_ref(pairs, %{})
end
def decode_hstore(<<_length::int32(), pairs::binary>>, :copy) do
decode_hstore_copy(pairs, %{})
end
defp decode_hstore_ref(<<>>, acc) do
acc
end
# in the case of a NULL value, there won't be a length
defp decode_hstore_ref(
<<key_length::int32(), key::binary(key_length), -1::int32(), rest::binary>>,
acc
) do
decode_hstore_ref(rest, Map.put(acc, key, nil))
end
defp decode_hstore_ref(
<<key_length::int32(), key::binary(key_length), value_length::int32(),
value::binary(value_length), rest::binary>>,
acc
) do
decode_hstore_ref(rest, Map.put(acc, key, value))
end
defp decode_hstore_copy(<<>>, acc) do
acc
end
# in the case of a NULL value, there won't be a length
defp decode_hstore_copy(
<<key_length::int32(), key::binary(key_length), -1::int32(), rest::binary>>,
acc
) do
decode_hstore_copy(rest, Map.put(acc, :binary.copy(key), nil))
end
defp decode_hstore_copy(
<<key_length::int32(), key::binary(key_length), value_length::int32(),
value::binary(value_length), rest::binary>>,
acc
) do
decode_hstore_copy(rest, Map.put(acc, :binary.copy(key), :binary.copy(value)))
end
end