From 12994f97b854ae8da8f6dcda5498103b0abbbb57 Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 08:49:41 -0400 Subject: [PATCH 01/12] allow extensions to access modifiers --- lib/postgrex/extensions/array.ex | 4 +- lib/postgrex/extensions/timestamp.ex | 25 +-- lib/postgrex/protocol.ex | 46 +++--- lib/postgrex/type_module.ex | 224 ++++++++++++++++++++------- lib/postgrex/utils.ex | 6 +- test/custom_extensions_test.exs | 9 +- test/query_test.exs | 28 ++++ test/test_helper.exs | 1 + 8 files changed, 248 insertions(+), 95 deletions(-) diff --git a/lib/postgrex/extensions/array.ex b/lib/postgrex/extensions/array.ex index 13eefa42..6febad88 100644 --- a/lib/postgrex/extensions/array.ex +++ b/lib/postgrex/extensions/array.ex @@ -28,12 +28,12 @@ defmodule Postgrex.Extensions.Array do def decode(_) do quote location: :keep do - <>, [oid], [type] -> + <>, [oid], [type], mod -> <> = binary # decode_list/2 defined by TypeModule - flat = decode_list(data, type) + flat = decode_list(data, type, mod) unquote(__MODULE__).decode(dims, flat) end diff --git a/lib/postgrex/extensions/timestamp.ex b/lib/postgrex/extensions/timestamp.ex index 63e90347..ac8ac9b5 100644 --- a/lib/postgrex/extensions/timestamp.ex +++ b/lib/postgrex/extensions/timestamp.ex @@ -27,8 +27,9 @@ defmodule Postgrex.Extensions.Timestamp do def decode(infinity?) do quote location: :keep do - <<8::int32(), microsecs::int64()>> -> - unquote(__MODULE__).microsecond_to_elixir(microsecs, unquote(infinity?)) + <<8::int32(), microsecs::int64()>>, precision -> + precision = if precision == -1, do: 6, else: precision + unquote(__MODULE__).microsecond_to_elixir(microsecs, precision, unquote(infinity?)) end end @@ -51,32 +52,32 @@ defmodule Postgrex.Extensions.Timestamp do <<8::int32(), secs * 1_000_000 + usec::int64()>> end - def microsecond_to_elixir(@plus_infinity, infinity?) do + def microsecond_to_elixir(@plus_infinity, _precision, infinity?) do if infinity?, do: :inf, else: raise_infinity("infinity") end - def microsecond_to_elixir(@minus_infinity, infinity?) do + def microsecond_to_elixir(@minus_infinity, _precision, infinity?) do if infinity?, do: :"-inf", else: raise_infinity("-infinity") end - def microsecond_to_elixir(microsecs, _infinity) do - split(microsecs) + def microsecond_to_elixir(microsecs, precision, _infinity) do + split(microsecs, precision) end - defp split(microsecs) when microsecs < 0 and rem(microsecs, 1_000_000) != 0 do + defp split(microsecs, precision) when microsecs < 0 and rem(microsecs, 1_000_000) != 0 do secs = div(microsecs, 1_000_000) - 1 microsecs = 1_000_000 + rem(microsecs, 1_000_000) - split(secs, microsecs) + split(secs, microsecs, precision) end - defp split(microsecs) do + defp split(microsecs, precision) do secs = div(microsecs, 1_000_000) microsecs = rem(microsecs, 1_000_000) - split(secs, microsecs) + split(secs, microsecs, precision) end - defp split(secs, microsecs) do - NaiveDateTime.from_gregorian_seconds(secs + @gs_epoch, {microsecs, 6}) + defp split(secs, microsecs, precision) do + NaiveDateTime.from_gregorian_seconds(secs + @gs_epoch, {microsecs, precision}) end defp raise_infinity(type) do diff --git a/lib/postgrex/protocol.ex b/lib/postgrex/protocol.ex index 3a7f67bb..20bef3c5 100644 --- a/lib/postgrex/protocol.ex +++ b/lib/postgrex/protocol.ex @@ -955,7 +955,7 @@ defmodule Postgrex.Protocol do defp set_search_path_recv(s, status, buffer) do case msg_recv(s, :infinity, buffer) do {:ok, msg_row_desc(fields: fields), buffer} -> - {[@text_type_oid], ["search_path"]} = columns(fields) + {[@text_type_oid], ["search_path"], _} = columns(fields) set_search_path_recv(s, status, buffer) {:ok, msg_data_row(), buffer} -> @@ -1014,7 +1014,7 @@ defmodule Postgrex.Protocol do ) do case msg_recv(s, :infinity, buffer) do {:ok, msg_row_desc(fields: fields), buffer} -> - {[@text_type_oid], ["transaction_read_only"]} = columns(fields) + {[@text_type_oid], ["transaction_read_only"], _} = columns(fields) check_target_server_type_recv(s, status, buffer) {:ok, msg_data_row(values: values), buffer} -> @@ -1611,8 +1611,9 @@ defmodule Postgrex.Protocol do ) when ref == nil or protocol_types != query_types do with {:ok, s, buffer} <- recv_parse(s, status, buffer), - {:ok, param_oids, result_oids, columns, s, buffer} <- recv_describe(s, status, buffer) do - describe(s, query, param_oids, result_oids, columns, buffer) + {:ok, param_oids, result_oids, result_mods, columns, s, buffer} <- + recv_describe(s, status, buffer) do + describe(s, query, param_oids, result_oids, result_mods, columns, buffer) else {:error, %Postgrex.Error{} = error, s, buffer} -> {:error, %{error | query: query.statement}, s, buffer} @@ -1626,13 +1627,13 @@ defmodule Postgrex.Protocol do %Query{param_oids: param_oids, result_oids: result_oids, columns: columns} = query with {:ok, s, buffer} <- recv_parse(s, status, buffer), - {:ok, ^param_oids, ^result_oids, ^columns, s, buffer} <- + {:ok, ^param_oids, ^result_oids, _, ^columns, s, buffer} <- recv_describe(s, status, param_oids, buffer) do query_put(s, query) {:ok, query, s, buffer} else - {:ok, ^param_oids, new_result_oids, new_columns, s, buffer} -> - redescribe(s, query, new_result_oids, new_columns, buffer) + {:ok, ^param_oids, new_result_oids, new_result_mods, new_columns, s, buffer} -> + redescribe(s, query, new_result_oids, new_result_mods, new_columns, buffer) {:error, %Postgrex.Error{}, _, _} = error -> error @@ -1662,14 +1663,14 @@ defmodule Postgrex.Protocol do defp recv_describe(s, status, param_oids \\ [], buffer) do case msg_recv(s, :infinity, buffer) do {:ok, msg_no_data(), buffer} -> - {:ok, param_oids, nil, nil, s, buffer} + {:ok, param_oids, nil, nil, nil, s, buffer} {:ok, msg_parameter_desc(type_oids: param_oids), buffer} -> recv_describe(s, status, param_oids, buffer) {:ok, msg_row_desc(fields: fields), buffer} -> - {result_oids, columns} = columns(fields) - {:ok, param_oids, result_oids, columns, s, buffer} + {result_oids, columns, result_mods} = columns(fields) + {:ok, param_oids, result_oids, result_mods, columns, s, buffer} {:ok, msg_too_many_parameters(len: len, max_len: max), buffer} -> msg = "postgresql protocol can not handle #{len} parameters, the maximum is #{max}" @@ -1688,10 +1689,10 @@ defmodule Postgrex.Protocol do end end - defp describe(s, query, param_oids, result_oids, columns, buffer) do + defp describe(s, query, param_oids, result_oids, result_mods, columns, buffer) do case describe_params(s, query, param_oids) do {:ok, query} -> - redescribe(s, query, result_oids, columns, buffer) + redescribe(s, query, result_oids, result_mods, columns, buffer) {:reload, oids} -> reload_describe_result(s, oids, result_oids, buffer) @@ -1701,8 +1702,8 @@ defmodule Postgrex.Protocol do end end - defp redescribe(s, query, result_oids, columns, buffer) do - with {:ok, query} <- describe_result(s, query, result_oids, columns) do + defp redescribe(s, query, result_oids, result_mods, columns, buffer) do + with {:ok, query} <- describe_result(s, query, result_oids, result_mods, columns) do query_put(s, query) {:ok, query, s, buffer} else @@ -1745,7 +1746,7 @@ defmodule Postgrex.Protocol do end end - defp describe_result(%{types: types}, query, nil, nil) do + defp describe_result(%{types: types}, query, nil, nil, nil) do query = %Query{ query | ref: make_ref(), @@ -1759,9 +1760,10 @@ defmodule Postgrex.Protocol do {:ok, query} end - defp describe_result(%{types: types}, query, result_oids, columns) do + defp describe_result(%{types: types}, query, result_oids, result_mods, columns) do with {:ok, result_info} <- fetch_type_info(result_oids, types), - {result_formats, result_types} = Enum.unzip(result_info) do + {result_formats, result_types} = Enum.unzip(result_info), + result_types = Enum.zip(result_types, result_mods) do query = %Query{ query | ref: make_ref(), @@ -3185,9 +3187,13 @@ defmodule Postgrex.Protocol do end defp columns(fields) do - fields - |> Enum.map(fn row_field(type_oid: oid, name: name) -> {oid, name} end) - |> :lists.unzip() + {oids_mods, names} = + fields + |> Enum.map(fn row_field(type_oid: oid, type_mod: mod, name: name) -> {{oid, mod}, name} end) + |> :lists.unzip() + + {oids, mods} = :lists.unzip(oids_mods) + {oids, names, mods} end defp column_names(fields) do diff --git a/lib/postgrex/type_module.ex b/lib/postgrex/type_module.ex index cb6f4d57..03ab49a7 100644 --- a/lib/postgrex/type_module.ex +++ b/lib/postgrex/type_module.ex @@ -198,7 +198,7 @@ defmodule Postgrex.TypeModule do end defp encode_extension(extension, clause) do - case split_extension(clause) do + case split_extension_encode(clause) do {pattern, guard, body} -> encode_extension(extension, pattern, guard, body) @@ -224,7 +224,7 @@ defmodule Postgrex.TypeModule do end defp encode_super(extension, clause) do - case split_super(clause) do + case split_super_encode(clause) do {pattern, sub_oids, sub_types, guard, body} -> encode_super(extension, pattern, sub_oids, sub_types, guard, body) @@ -382,11 +382,12 @@ defmodule Postgrex.TypeModule do defp decode_row_dispatch(extension, :super_binary, rest, acc, rem, full, rows) do [clause] = quote do - [{unquote(extension), sub_oids, sub_types} | types] -> + [{{unquote(extension), sub_oids, sub_types}, mod} | types] -> unquote(extension)( unquote(rest), sub_oids, sub_types, + mod, types, unquote(acc), unquote(rem), @@ -401,9 +402,10 @@ defmodule Postgrex.TypeModule do defp decode_row_dispatch(extension, _, rest, acc, rem, full, rows) do [clause] = quote do - [unquote(extension) | types2] -> + [{unquote(extension), mod} | types2] -> unquote(extension)( unquote(rest), + mod, types2, unquote(acc), unquote(rem), @@ -442,7 +444,7 @@ defmodule Postgrex.TypeModule do defp decode_simple_dispatch(extension, rest, acc) do quote do - unquote(extension)(unquote(rest), unquote(acc), &decode_simple/2) + unquote(extension)(unquote(rest), nil, unquote(acc), &decode_simple/2) end end @@ -456,8 +458,8 @@ defmodule Postgrex.TypeModule do quote do @doc false - def decode_list(<>, type) do - case type do + def decode_list(<>, type, mod \\ nil) do + case {type, mod} do unquote(dispatch) end end @@ -467,8 +469,8 @@ defmodule Postgrex.TypeModule do defp decode_list_dispatch(extension, :super_binary, rest) do [clause] = quote do - {unquote(extension), sub_oids, sub_types} -> - unquote(extension)(unquote(rest), sub_oids, sub_types, []) + {{unquote(extension), sub_oids, sub_types}, mod} -> + unquote(extension)(unquote(rest), sub_oids, sub_types, mod, []) end clause @@ -477,8 +479,8 @@ defmodule Postgrex.TypeModule do defp decode_list_dispatch(extension, _, rest) do [clause] = quote do - unquote(extension) -> - unquote(extension)(unquote(rest), []) + {unquote(extension), mod} -> + unquote(extension)(unquote(rest), mod, []) end clause @@ -568,6 +570,7 @@ defmodule Postgrex.TypeModule do unquote(rest), sub_oids, sub_types, + nil, unquote(oids), types, unquote(n) + 1, @@ -582,7 +585,14 @@ defmodule Postgrex.TypeModule do [clause] = quote do [unquote(extension) | types] -> - unquote(extension)(unquote(rest), unquote(oids), types, unquote(n) + 1, unquote(acc)) + unquote(extension)( + unquote(rest), + nil, + unquote(oids), + types, + unquote(n) + 1, + unquote(acc) + ) end clause @@ -605,19 +615,44 @@ defmodule Postgrex.TypeModule do end defp decode_extension(extension, clause, dispatch, rest, acc, rem, full, rows) do - case split_extension(clause) do - {pattern, guard, body} -> - decode_extension(extension, pattern, guard, body, dispatch, rest, acc, rem, full, rows) + case split_extension_decode(clause) do + {pattern, mod, guard, body} -> + decode_extension( + extension, + pattern, + mod, + guard, + body, + dispatch, + rest, + acc, + rem, + full, + rows + ) - {pattern, body} -> - decode_extension(extension, pattern, body, dispatch, rest, acc, rem, full, rows) + {pattern, mod, body} -> + decode_extension(extension, pattern, mod, body, dispatch, rest, acc, rem, full, rows) end end - defp decode_extension(extension, pattern, guard, body, dispatch, rest, acc, rem, full, rows) do + defp decode_extension( + extension, + pattern, + mod, + guard, + body, + dispatch, + rest, + acc, + rem, + full, + rows + ) do quote do defp unquote(extension)( <>, + unquote(mod), types, acc, unquote(rem), @@ -632,27 +667,40 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<>, acc) + defp unquote(extension)(<>, mod = unquote(mod), acc) when unquote(guard) do - unquote(extension)(rest, [unquote(body) | acc]) + unquote(extension)(rest, mod, [unquote(body) | acc]) end - defp unquote(extension)(<>, acc, callback) + defp unquote(extension)( + <>, + nil = unquote(mod), + acc, + callback + ) when unquote(guard) do - unquote(extension)(rest, [unquote(body) | acc], callback) + unquote(extension)(rest, nil, [unquote(body) | acc], callback) end - defp unquote(extension)(<>, oids, types, n, acc) + defp unquote(extension)( + <>, + nil = unquote(mod), + oids, + types, + n, + acc + ) when unquote(guard) do decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end end - defp decode_extension(extension, pattern, body, dispatch, rest, acc, rem, full, rows) do + defp decode_extension(extension, pattern, mod, body, dispatch, rest, acc, rem, full, rows) do quote do defp unquote(extension)( <>, + unquote(mod), types, acc, unquote(rem), @@ -666,17 +714,29 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<>, acc) do + defp unquote(extension)(<>, mod = unquote(mod), acc) do decoded = unquote(body) - unquote(extension)(rest, [decoded | acc]) + unquote(extension)(rest, mod, [decoded | acc]) end - defp unquote(extension)(<>, acc, callback) do + defp unquote(extension)( + <>, + nil = unquote(mod), + acc, + callback + ) do decoded = unquote(body) - unquote(extension)(rest, [decoded | acc], callback) + unquote(extension)(rest, nil, [decoded | acc], callback) end - defp unquote(extension)(<>, oids, types, n, acc) do + defp unquote(extension)( + <>, + nil = unquote(mod), + oids, + types, + n, + acc + ) do decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end @@ -686,6 +746,7 @@ defmodule Postgrex.TypeModule do quote do defp unquote(extension)( <<-1::int32(), unquote(rest)::binary>>, + _mod, types, acc, unquote(rem), @@ -699,29 +760,29 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<<-1::int32(), rest::binary>>, acc) do - unquote(extension)(rest, [@null | acc]) + defp unquote(extension)(<<-1::int32(), rest::binary>>, mod, acc) do + unquote(extension)(rest, mod, [@null | acc]) end - defp unquote(extension)(<<>>, acc) do + defp unquote(extension)(<<>>, _, acc) do acc end - defp unquote(extension)(<<-1::int32(), rest::binary>>, acc, callback) do - unquote(extension)(rest, [@null | acc], callback) + defp unquote(extension)(<<-1::int32(), rest::binary>>, nil, acc, callback) do + unquote(extension)(rest, nil, [@null | acc], callback) end - defp unquote(extension)(<>, acc, callback) do + defp unquote(extension)(<>, _, acc, callback) do callback.(rest, acc) end - defp unquote(extension)(<<-1::int32(), rest::binary>>, oids, types, n, acc) do + defp unquote(extension)(<<-1::int32(), rest::binary>>, nil, oids, types, n, acc) do decode_tuple(rest, oids, types, n, acc) end end end - defp split_extension({:->, _, [head, body]}) do + defp split_extension_encode({:->, _, [head, body]}) do case head do [{:when, _, [pattern, guard]}] -> {pattern, guard, body} @@ -731,14 +792,31 @@ defmodule Postgrex.TypeModule do end end + defp split_extension_decode({:->, _, [head, body]}) do + case head do + [{:when, _, [pattern, guard]}] -> + {pattern, quote(do: _), guard, body} + + [pattern] -> + {pattern, quote(do: _), body} + + [{:when, _, [pattern, modifier, guard]}] -> + {pattern, modifier, guard, body} + + [pattern, modifier] -> + {pattern, modifier, body} + end + end + defp decode_super(extension, clause, dispatch, rest, acc, rem, full, rows) do - case split_super(clause) do - {pattern, oids, types, guard, body} -> + case split_super_decode(clause) do + {pattern, oids, types, mod, guard, body} -> decode_super( extension, pattern, oids, types, + mod, guard, body, dispatch, @@ -749,8 +827,21 @@ defmodule Postgrex.TypeModule do rows ) - {pattern, oids, types, body} -> - decode_super(extension, pattern, oids, types, body, dispatch, rest, acc, rem, full, rows) + {pattern, oids, types, mod, body} -> + decode_super( + extension, + pattern, + oids, + types, + mod, + body, + dispatch, + rest, + acc, + rem, + full, + rows + ) end end @@ -759,6 +850,7 @@ defmodule Postgrex.TypeModule do pattern, sub_oids, sub_types, + mod, guard, body, dispatch, @@ -773,6 +865,7 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + unquote(mod), types, acc, unquote(rem), @@ -791,17 +884,19 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + mod = unquote(mod), acc ) when unquote(guard) do acc = [unquote(body) | acc] - unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), acc) + unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), mod, acc) end defp unquote(extension)( <>, unquote(sub_oids), unquote(sub_types), + nil = unquote(mod), oids, types, n, @@ -818,6 +913,7 @@ defmodule Postgrex.TypeModule do pattern, sub_oids, sub_types, + mod, body, dispatch, rest, @@ -831,6 +927,7 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + unquote(mod), types, acc, unquote(rem), @@ -848,16 +945,18 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + mod = unquote(mod), acc ) do acc = [unquote(body) | acc] - unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), acc) + unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), mod, acc) end defp unquote(extension)( <>, unquote(sub_oids), unquote(sub_types), + nil = unquote(mod), oids, types, n, @@ -875,6 +974,7 @@ defmodule Postgrex.TypeModule do <<-1::int32(), unquote(rest)::binary>>, _sub_oids, _sub_types, + _mod, types, acc, unquote(rem), @@ -888,11 +988,11 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<<-1::int32(), rest::binary>>, sub_oids, sub_types, acc) do - unquote(extension)(rest, sub_oids, sub_types, [@null | acc]) + defp unquote(extension)(<<-1::int32(), rest::binary>>, sub_oids, sub_types, mod, acc) do + unquote(extension)(rest, sub_oids, sub_types, mod, [@null | acc]) end - defp unquote(extension)(<<>>, _sub_oid, _sub_types, acc) do + defp unquote(extension)(<<>>, _sub_oid, _sub_types, _mod, acc) do acc end @@ -900,6 +1000,7 @@ defmodule Postgrex.TypeModule do <<-1::int32(), rest::binary>>, _sub_oids, _sub_types, + nil, oids, types, n, @@ -910,7 +1011,7 @@ defmodule Postgrex.TypeModule do end end - defp split_super({:->, _, [head, body]}) do + defp split_super_encode({:->, _, [head, body]}) do case head do [{:when, _, [pattern, sub_oids, sub_types, guard]}] -> {pattern, sub_oids, sub_types, guard, body} @@ -920,9 +1021,28 @@ defmodule Postgrex.TypeModule do end end - defp configure(extensions, opts) do - defaults = Postgrex.Utils.default_extensions(opts) - Enum.map(extensions ++ defaults, &configure/1) + defp split_super_decode({:->, _, [head, body]}) do + case head do + [{:when, _, [pattern, sub_oids, sub_types, guard]}] -> + {pattern, sub_oids, sub_types, quote(do: _), guard, body} + + [pattern, sub_oids, sub_types] -> + {pattern, sub_oids, sub_types, quote(do: _), body} + + [{:when, _, [pattern, sub_oids, sub_types, modifier, guard]}] -> + {pattern, sub_oids, sub_types, modifier, guard, body} + + [pattern, sub_oids, sub_types, modifier] -> + {pattern, sub_oids, sub_types, modifier, body} + end + end + + defp configure(customs, opts) do + defaults = Postgrex.Utils.default_extensions() + + Enum.map(customs ++ defaults, fn extension -> + configure({extension, opts}) + end) end defp configure({extension, opts}) do @@ -932,10 +1052,6 @@ defmodule Postgrex.TypeModule do {extension, {state, matching, format}} end - defp configure(extension) do - configure({extension, []}) - end - defp define_inline(module, config, opts) do quoted = [ directives(config, opts), diff --git a/lib/postgrex/utils.ex b/lib/postgrex/utils.ex index e227c346..6877f31a 100644 --- a/lib/postgrex/utils.ex +++ b/lib/postgrex/utils.ex @@ -57,9 +57,9 @@ defmodule Postgrex.Utils do @doc """ List all default extensions. """ - @spec default_extensions(Keyword.t()) :: [{module(), Keyword.t()}] - def default_extensions(opts \\ []) do - Enum.map(@extensions, &{&1, opts}) + @spec default_extensions() :: [module()] + def default_extensions() do + @extensions end @doc """ diff --git a/test/custom_extensions_test.exs b/test/custom_extensions_test.exs index b66f8cb9..5ee34801 100644 --- a/test/custom_extensions_test.exs +++ b/test/custom_extensions_test.exs @@ -10,8 +10,9 @@ defmodule CustomExtensionsTest do defmodule BinaryExtension do @behaviour Postgrex.Extension - def init([]), - do: [] + def init(_opts) do + [] + end def matching([]), do: [send: "int4send"] @@ -36,7 +37,7 @@ defmodule CustomExtensionsTest do defmodule TextExtension do @behaviour Postgrex.Extension - def init([]), + def init(_opts), do: {} def matching({}), @@ -63,7 +64,7 @@ defmodule CustomExtensionsTest do defmodule BadExtension do @behaviour Postgrex.Extension - def init([]), + def init(_opts), do: [] def matching([]), diff --git a/test/query_test.exs b/test/query_test.exs index 312d2f38..458e9320 100644 --- a/test/query_test.exs +++ b/test/query_test.exs @@ -1746,4 +1746,32 @@ defmodule QueryTest do {:ok, pid} = P.start_link(database: "postgrex_test", search_path: ["public", "test_schema"]) %{rows: [[1, "foo"]]} = P.query!(pid, "SELECT * from test_table", []) end + + test "timestamp precision", context do + :ok = + query( + """ + INSERT INTO timestamps (micro, milli, sec, sec_arr) + VALUES ('2000-01-01', '2000-01-01', '2000-01-01', '{2000-01-01, 2000-01-02}'), + ('3000-01-01', '3000-01-01', '3000-01-01', '{3000-01-01, 3000-01-02}') + """, + [] + ) + + assert [row1, row2] = query("SELECT * FROM timestamps", []) + + assert [ + %{microsecond: {_, 6}}, + %{microsecond: {_, 3}}, + %{microsecond: {_, 0}}, + [%{microsecond: {_, 0}}, %{microsecond: {_, 0}}] + ] = row1 + + assert [ + %{microsecond: {_, 6}}, + %{microsecond: {_, 3}}, + %{microsecond: {_, 0}}, + [%{microsecond: {_, 0}}, %{microsecond: {_, 0}}] + ] = row2 + end end diff --git a/test/test_helper.exs b/test/test_helper.exs index 7513db6c..a0d25c25 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -96,6 +96,7 @@ DROP TYPE IF EXISTS enum1; CREATE TYPE enum1 AS ENUM ('elixir', 'erlang'); CREATE TABLE uniques (a int UNIQUE); +CREATE TABLE timestamps (micro timestamp, milli timestamp(3), sec timestamp(0), sec_arr timestamp(0)[]); DROP TABLE IF EXISTS missing_oid; DROP TYPE IF EXISTS missing_enum; From 269c80798088fe28491ced76f6f16678af90b7d3 Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 08:57:08 -0400 Subject: [PATCH 02/12] cleanup --- lib/postgrex/type_module.ex | 13 +++++++------ lib/postgrex/utils.ex | 6 +++--- test/custom_extensions_test.exs | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/postgrex/type_module.ex b/lib/postgrex/type_module.ex index 03ab49a7..7e04c895 100644 --- a/lib/postgrex/type_module.ex +++ b/lib/postgrex/type_module.ex @@ -1037,12 +1037,9 @@ defmodule Postgrex.TypeModule do end end - defp configure(customs, opts) do - defaults = Postgrex.Utils.default_extensions() - - Enum.map(customs ++ defaults, fn extension -> - configure({extension, opts}) - end) + defp configure(extensions, opts) do + defaults = Postgrex.Utils.default_extensions(opts) + Enum.map(extensions ++ defaults, &configure/1) end defp configure({extension, opts}) do @@ -1052,6 +1049,10 @@ defmodule Postgrex.TypeModule do {extension, {state, matching, format}} end + defp configure(extension) do + configure({extension, []}) + end + defp define_inline(module, config, opts) do quoted = [ directives(config, opts), diff --git a/lib/postgrex/utils.ex b/lib/postgrex/utils.ex index 6877f31a..02b8d3e2 100644 --- a/lib/postgrex/utils.ex +++ b/lib/postgrex/utils.ex @@ -57,9 +57,9 @@ defmodule Postgrex.Utils do @doc """ List all default extensions. """ - @spec default_extensions() :: [module()] - def default_extensions() do - @extensions + @spec default_extensions(Keyword.t()) :: [module()] + def default_extensions(opts) do + Enum.map(@extensions, &{&1, opts}) end @doc """ diff --git a/test/custom_extensions_test.exs b/test/custom_extensions_test.exs index 5ee34801..2070c684 100644 --- a/test/custom_extensions_test.exs +++ b/test/custom_extensions_test.exs @@ -10,7 +10,7 @@ defmodule CustomExtensionsTest do defmodule BinaryExtension do @behaviour Postgrex.Extension - def init(_opts) do + def init([]) do [] end @@ -37,7 +37,7 @@ defmodule CustomExtensionsTest do defmodule TextExtension do @behaviour Postgrex.Extension - def init(_opts), + def init([]), do: {} def matching({}), @@ -64,7 +64,7 @@ defmodule CustomExtensionsTest do defmodule BadExtension do @behaviour Postgrex.Extension - def init(_opts), + def init([]), do: [] def matching([]), From dd748697e0bad0f708119ec4dc1e76934e85de2b Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 08:59:01 -0400 Subject: [PATCH 03/12] cleanup --- test/custom_extensions_test.exs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/custom_extensions_test.exs b/test/custom_extensions_test.exs index 2070c684..b66f8cb9 100644 --- a/test/custom_extensions_test.exs +++ b/test/custom_extensions_test.exs @@ -10,9 +10,8 @@ defmodule CustomExtensionsTest do defmodule BinaryExtension do @behaviour Postgrex.Extension - def init([]) do - [] - end + def init([]), + do: [] def matching([]), do: [send: "int4send"] From 5557326751981494867914e797750b0fc5d7793e Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 08:59:28 -0400 Subject: [PATCH 04/12] cleanup --- lib/postgrex/utils.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/postgrex/utils.ex b/lib/postgrex/utils.ex index 02b8d3e2..d4a7b57d 100644 --- a/lib/postgrex/utils.ex +++ b/lib/postgrex/utils.ex @@ -58,7 +58,7 @@ defmodule Postgrex.Utils do List all default extensions. """ @spec default_extensions(Keyword.t()) :: [module()] - def default_extensions(opts) do + def default_extensions(opts \\ []) do Enum.map(@extensions, &{&1, opts}) end From f85f28cd16ec570681d0db01ab04f60fd9baa4d4 Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 09:17:41 -0400 Subject: [PATCH 05/12] cleanup test --- test/query_test.exs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/test/query_test.exs b/test/query_test.exs index 458e9320..ad1071c2 100644 --- a/test/query_test.exs +++ b/test/query_test.exs @@ -1760,18 +1760,10 @@ defmodule QueryTest do assert [row1, row2] = query("SELECT * FROM timestamps", []) - assert [ - %{microsecond: {_, 6}}, - %{microsecond: {_, 3}}, - %{microsecond: {_, 0}}, - [%{microsecond: {_, 0}}, %{microsecond: {_, 0}}] - ] = row1 - - assert [ - %{microsecond: {_, 6}}, - %{microsecond: {_, 3}}, - %{microsecond: {_, 0}}, - [%{microsecond: {_, 0}}, %{microsecond: {_, 0}}] - ] = row2 + assert [6, 3, 0, [0, 0]] = precision(row1) + assert [6, 3, 0, [0, 0]] = precision(row2) end + + defp precision([_ | _] = dts), do: Enum.map(dts, &precision(&1)) + defp precision(%NaiveDateTime{microsecond: {_, p}}), do: p end From f5c8b2970d9eb1e5c98942f33746c2cb41380817 Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 09:20:38 -0400 Subject: [PATCH 06/12] cleanup --- lib/postgrex/utils.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/postgrex/utils.ex b/lib/postgrex/utils.ex index d4a7b57d..e227c346 100644 --- a/lib/postgrex/utils.ex +++ b/lib/postgrex/utils.ex @@ -57,7 +57,7 @@ defmodule Postgrex.Utils do @doc """ List all default extensions. """ - @spec default_extensions(Keyword.t()) :: [module()] + @spec default_extensions(Keyword.t()) :: [{module(), Keyword.t()}] def default_extensions(opts \\ []) do Enum.map(@extensions, &{&1, opts}) end From c44df85be82dd58a1bd663dde8bd5583abca35d8 Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 12:55:41 -0400 Subject: [PATCH 07/12] more tests --- lib/postgrex/extensions/timestamp.ex | 5 ++++- test/query_test.exs | 23 +++++++++++++++++++++++ test/stream_test.exs | 25 +++++++++++++++++++++++++ test/test_helper.exs | 1 + 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/postgrex/extensions/timestamp.ex b/lib/postgrex/extensions/timestamp.ex index ac8ac9b5..0bc6779c 100644 --- a/lib/postgrex/extensions/timestamp.ex +++ b/lib/postgrex/extensions/timestamp.ex @@ -8,6 +8,7 @@ defmodule Postgrex.Extensions.Timestamp do @min_year -4_713 @plus_infinity 9_223_372_036_854_775_807 @minus_infinity -9_223_372_036_854_775_808 + @default_precision 6 def init(opts), do: Keyword.get(opts, :allow_infinite_timestamps, false) @@ -28,7 +29,6 @@ defmodule Postgrex.Extensions.Timestamp do def decode(infinity?) do quote location: :keep do <<8::int32(), microsecs::int64()>>, precision -> - precision = if precision == -1, do: 6, else: precision unquote(__MODULE__).microsecond_to_elixir(microsecs, precision, unquote(infinity?)) end end @@ -77,6 +77,9 @@ defmodule Postgrex.Extensions.Timestamp do end defp split(secs, microsecs, precision) do + # use the default precision if the precision modifier from postgres is -1 (this means no precision specified) + # or if the precision is missing because we are in a super type which does not give us the sub-type's modifier + precision = if precision in [-1, nil], do: @default_precision, else: precision NaiveDateTime.from_gregorian_seconds(secs + @gs_epoch, {microsecs, precision}) end diff --git a/test/query_test.exs b/test/query_test.exs index ad1071c2..023720af 100644 --- a/test/query_test.exs +++ b/test/query_test.exs @@ -418,6 +418,29 @@ defmodule QueryTest do } ] ] = query("SELECT '[,]'::daterange", []) + + assert [ + [ + %Postgrex.Range{ + lower: %NaiveDateTime{ + year: 2014, + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0 + }, + upper: %NaiveDateTime{ + year: 2014, + month: 12, + day: 31, + hour: 0, + minute: 0, + second: 0 + } + } + ] + ] = query("SELECT '[2014-1-1,2014-12-31)'::tsrange", []) end @tag min_pg_version: "14.0" diff --git a/test/stream_test.exs b/test/stream_test.exs index 9d32431f..4a4afc60 100644 --- a/test/stream_test.exs +++ b/test/stream_test.exs @@ -775,4 +775,29 @@ defmodule StreamTest do assert [[42]] = query("SELECT 42", []) end + + test "stream with type modifier", context do + :ok = + query( + """ + INSERT INTO timestamps_stream (micro, milli, sec, sec_arr) + VALUES ('2000-01-01', '2000-01-01', '2000-01-01', '{2000-01-01, 2000-01-02}'), + ('3000-01-01', '3000-01-01', '3000-01-01', '{3000-01-01, 3000-01-02}') + """, + [] + ) + + query = prepare("", "SELECT * FROM timestamps_stream") + + transaction(fn conn -> + [[row1], [row2], []] = + stream(query, [], max_rows: 1) |> Enum.map(fn %Result{rows: rows} -> rows end) + + assert [6, 3, 0, [0, 0]] = precision(row1) + assert [6, 3, 0, [0, 0]] = precision(row2) + end) + end + + defp precision([_ | _] = dts), do: Enum.map(dts, &precision(&1)) + defp precision(%NaiveDateTime{microsecond: {_, p}}), do: p end diff --git a/test/test_helper.exs b/test/test_helper.exs index a0d25c25..5ad2e812 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -97,6 +97,7 @@ CREATE TYPE enum1 AS ENUM ('elixir', 'erlang'); CREATE TABLE uniques (a int UNIQUE); CREATE TABLE timestamps (micro timestamp, milli timestamp(3), sec timestamp(0), sec_arr timestamp(0)[]); +CREATE TABLE timestamps_stream (micro timestamp, milli timestamp(3), sec timestamp(0), sec_arr timestamp(0)[]); DROP TABLE IF EXISTS missing_oid; DROP TYPE IF EXISTS missing_enum; From 7057e83fe6fcf5a7ad4e68f4348b1f78e8bb3da9 Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 18:26:23 -0400 Subject: [PATCH 08/12] review comments --- lib/postgrex/extensions/array.ex | 8 +++++++- lib/postgrex/extensions/multirange.ex | 9 ++++++++- lib/postgrex/extensions/range.ex | 9 ++++++++- lib/postgrex/extensions/record.ex | 4 ++-- lib/postgrex/protocol.ex | 29 ++++++++++++++++----------- lib/postgrex/type_module.ex | 14 ++++--------- 6 files changed, 46 insertions(+), 27 deletions(-) diff --git a/lib/postgrex/extensions/array.ex b/lib/postgrex/extensions/array.ex index 6febad88..b180b9aa 100644 --- a/lib/postgrex/extensions/array.ex +++ b/lib/postgrex/extensions/array.ex @@ -33,7 +33,13 @@ defmodule Postgrex.Extensions.Array do data::binary>> = binary # decode_list/2 defined by TypeModule - flat = decode_list(data, type, mod) + type = + case type do + {extension, sub_oids, sub_types} -> {extension, sub_oids, sub_types, mod} + extension -> {extension, mod} + end + + flat = decode_list(data, type) unquote(__MODULE__).decode(dims, flat) end diff --git a/lib/postgrex/extensions/multirange.ex b/lib/postgrex/extensions/multirange.ex index abcbba7d..52cdfd7b 100644 --- a/lib/postgrex/extensions/multirange.ex +++ b/lib/postgrex/extensions/multirange.ex @@ -27,9 +27,16 @@ defmodule Postgrex.Extensions.Multirange do def decode(_) do quote location: :keep do - <>, [_oid], [type] -> + <>, [_oid], [type], _ -> <<_num_ranges::int32(), ranges::binary>> = data + # decode_list/2 defined by TypeModule + type = + case type do + {extension, sub_oids, sub_types} -> {extension, sub_oids, sub_types, nil} + extension -> {extension, nil} + end + bound_decoder = &decode_list(&1, type) unquote(__MODULE__).decode(ranges, bound_decoder, []) end diff --git a/lib/postgrex/extensions/range.ex b/lib/postgrex/extensions/range.ex index fa26a92e..69b1b5ac 100644 --- a/lib/postgrex/extensions/range.ex +++ b/lib/postgrex/extensions/range.ex @@ -35,9 +35,16 @@ defmodule Postgrex.Extensions.Range do def decode(_) do quote location: :keep do - <>, [_oid], [type] -> + <>, [_oid], [type], _ -> <> = binary + # decode_list/2 defined by TypeModule + type = + case type do + {extension, sub_oids, sub_types} -> {extension, sub_oids, sub_types, nil} + extension -> {extension, nil} + end + case decode_list(data, type) do [upper, lower] -> unquote(__MODULE__).decode(flags, [lower, upper]) diff --git a/lib/postgrex/extensions/record.ex b/lib/postgrex/extensions/record.ex index f436c671..26a8d614 100644 --- a/lib/postgrex/extensions/record.ex +++ b/lib/postgrex/extensions/record.ex @@ -31,12 +31,12 @@ defmodule Postgrex.Extensions.Record do def decode(_) do quote location: :keep do - <>, nil, types -> + <>, nil, types, _ -> <> = binary # decode_tuple/3 defined by TypeModule decode_tuple(data, count, types) - <>, oids, types -> + <>, oids, types, _ -> <<_::int32(), data::binary>> = binary # decode_tuple/3 defined by TypeModule decode_tuple(data, oids, types) diff --git a/lib/postgrex/protocol.ex b/lib/postgrex/protocol.ex index 20bef3c5..74bd82dd 100644 --- a/lib/postgrex/protocol.ex +++ b/lib/postgrex/protocol.ex @@ -1716,8 +1716,9 @@ defmodule Postgrex.Protocol do end defp describe_params(%{types: types}, query, param_oids) do - with {:ok, param_info} <- fetch_type_info(param_oids, types), - {param_formats, param_types} = Enum.unzip(param_info) do + with {:ok, param_info} <- fetch_type_info(param_oids, types) do + {param_formats, param_types} = Enum.unzip(param_info) + query = %Query{ query | param_oids: param_oids, @@ -1761,9 +1762,17 @@ defmodule Postgrex.Protocol do end defp describe_result(%{types: types}, query, result_oids, result_mods, columns) do - with {:ok, result_info} <- fetch_type_info(result_oids, types), - {result_formats, result_types} = Enum.unzip(result_info), - result_types = Enum.zip(result_types, result_mods) do + with {:ok, result_info} <- fetch_type_info(result_oids, types) do + {result_formats, result_types} = Enum.unzip(result_info) + + result_types = + result_types + |> Enum.zip(result_mods) + |> Enum.map(fn + {{extension, sub_oids, sub_types}, mod} -> {extension, sub_oids, sub_types, mod} + {extension, mod} -> {extension, mod} + end) + query = %Query{ query | ref: make_ref(), @@ -3187,13 +3196,9 @@ defmodule Postgrex.Protocol do end defp columns(fields) do - {oids_mods, names} = - fields - |> Enum.map(fn row_field(type_oid: oid, type_mod: mod, name: name) -> {{oid, mod}, name} end) - |> :lists.unzip() - - {oids, mods} = :lists.unzip(oids_mods) - {oids, names, mods} + fields + |> Enum.map(fn row_field(type_oid: oid, type_mod: mod, name: name) -> {oid, name, mod} end) + |> :lists.unzip3() end defp column_names(fields) do diff --git a/lib/postgrex/type_module.ex b/lib/postgrex/type_module.ex index 7e04c895..2c53ead6 100644 --- a/lib/postgrex/type_module.ex +++ b/lib/postgrex/type_module.ex @@ -382,7 +382,7 @@ defmodule Postgrex.TypeModule do defp decode_row_dispatch(extension, :super_binary, rest, acc, rem, full, rows) do [clause] = quote do - [{{unquote(extension), sub_oids, sub_types}, mod} | types] -> + [{unquote(extension), sub_oids, sub_types, mod} | types] -> unquote(extension)( unquote(rest), sub_oids, @@ -458,8 +458,8 @@ defmodule Postgrex.TypeModule do quote do @doc false - def decode_list(<>, type, mod \\ nil) do - case {type, mod} do + def decode_list(<>, type) do + case type do unquote(dispatch) end end @@ -469,7 +469,7 @@ defmodule Postgrex.TypeModule do defp decode_list_dispatch(extension, :super_binary, rest) do [clause] = quote do - {{unquote(extension), sub_oids, sub_types}, mod} -> + {unquote(extension), sub_oids, sub_types, mod} -> unquote(extension)(unquote(rest), sub_oids, sub_types, mod, []) end @@ -1023,12 +1023,6 @@ defmodule Postgrex.TypeModule do defp split_super_decode({:->, _, [head, body]}) do case head do - [{:when, _, [pattern, sub_oids, sub_types, guard]}] -> - {pattern, sub_oids, sub_types, quote(do: _), guard, body} - - [pattern, sub_oids, sub_types] -> - {pattern, sub_oids, sub_types, quote(do: _), body} - [{:when, _, [pattern, sub_oids, sub_types, modifier, guard]}] -> {pattern, sub_oids, sub_types, modifier, guard, body} From e04c63ddb7767ec2f378fc5b041072136377442f Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 18:27:54 -0400 Subject: [PATCH 09/12] format --- lib/postgrex/protocol.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/postgrex/protocol.ex b/lib/postgrex/protocol.ex index 74bd82dd..81556365 100644 --- a/lib/postgrex/protocol.ex +++ b/lib/postgrex/protocol.ex @@ -1769,8 +1769,8 @@ defmodule Postgrex.Protocol do result_types |> Enum.zip(result_mods) |> Enum.map(fn - {{extension, sub_oids, sub_types}, mod} -> {extension, sub_oids, sub_types, mod} - {extension, mod} -> {extension, mod} + {{extension, sub_oids, sub_types}, mod} -> {extension, sub_oids, sub_types, mod} + {extension, mod} -> {extension, mod} end) query = %Query{ From 049fbd892780bcd82a3809756be3a4796458527c Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 19:30:29 -0400 Subject: [PATCH 10/12] var! method --- lib/postgrex/extensions/array.ex | 6 +- lib/postgrex/extensions/multirange.ex | 2 +- lib/postgrex/extensions/range.ex | 2 +- lib/postgrex/extensions/record.ex | 4 +- lib/postgrex/extensions/timestamp.ex | 4 +- lib/postgrex/type_module.ex | 110 +++++++++----------------- 6 files changed, 48 insertions(+), 80 deletions(-) diff --git a/lib/postgrex/extensions/array.ex b/lib/postgrex/extensions/array.ex index b180b9aa..92d3a959 100644 --- a/lib/postgrex/extensions/array.ex +++ b/lib/postgrex/extensions/array.ex @@ -28,15 +28,15 @@ defmodule Postgrex.Extensions.Array do def decode(_) do quote location: :keep do - <>, [oid], [type], mod -> + <>, [oid], [type] -> <> = binary # decode_list/2 defined by TypeModule type = case type do - {extension, sub_oids, sub_types} -> {extension, sub_oids, sub_types, mod} - extension -> {extension, mod} + {extension, sub_oids, sub_types} -> {extension, sub_oids, sub_types, var!(mod)} + extension -> {extension, var!(mod)} end flat = decode_list(data, type) diff --git a/lib/postgrex/extensions/multirange.ex b/lib/postgrex/extensions/multirange.ex index 52cdfd7b..11bb2c20 100644 --- a/lib/postgrex/extensions/multirange.ex +++ b/lib/postgrex/extensions/multirange.ex @@ -27,7 +27,7 @@ defmodule Postgrex.Extensions.Multirange do def decode(_) do quote location: :keep do - <>, [_oid], [type], _ -> + <>, [_oid], [type] -> <<_num_ranges::int32(), ranges::binary>> = data # decode_list/2 defined by TypeModule diff --git a/lib/postgrex/extensions/range.ex b/lib/postgrex/extensions/range.ex index 69b1b5ac..92c0278f 100644 --- a/lib/postgrex/extensions/range.ex +++ b/lib/postgrex/extensions/range.ex @@ -35,7 +35,7 @@ defmodule Postgrex.Extensions.Range do def decode(_) do quote location: :keep do - <>, [_oid], [type], _ -> + <>, [_oid], [type] -> <> = binary # decode_list/2 defined by TypeModule diff --git a/lib/postgrex/extensions/record.ex b/lib/postgrex/extensions/record.ex index 26a8d614..f436c671 100644 --- a/lib/postgrex/extensions/record.ex +++ b/lib/postgrex/extensions/record.ex @@ -31,12 +31,12 @@ defmodule Postgrex.Extensions.Record do def decode(_) do quote location: :keep do - <>, nil, types, _ -> + <>, nil, types -> <> = binary # decode_tuple/3 defined by TypeModule decode_tuple(data, count, types) - <>, oids, types, _ -> + <>, oids, types -> <<_::int32(), data::binary>> = binary # decode_tuple/3 defined by TypeModule decode_tuple(data, oids, types) diff --git a/lib/postgrex/extensions/timestamp.ex b/lib/postgrex/extensions/timestamp.ex index 0bc6779c..27184109 100644 --- a/lib/postgrex/extensions/timestamp.ex +++ b/lib/postgrex/extensions/timestamp.ex @@ -28,8 +28,8 @@ defmodule Postgrex.Extensions.Timestamp do def decode(infinity?) do quote location: :keep do - <<8::int32(), microsecs::int64()>>, precision -> - unquote(__MODULE__).microsecond_to_elixir(microsecs, precision, unquote(infinity?)) + <<8::int32(), microsecs::int64()>> -> + unquote(__MODULE__).microsecond_to_elixir(microsecs, var!(mod), unquote(infinity?)) end end diff --git a/lib/postgrex/type_module.ex b/lib/postgrex/type_module.ex index 2c53ead6..41504e70 100644 --- a/lib/postgrex/type_module.ex +++ b/lib/postgrex/type_module.ex @@ -198,7 +198,7 @@ defmodule Postgrex.TypeModule do end defp encode_extension(extension, clause) do - case split_extension_encode(clause) do + case split_extension(clause) do {pattern, guard, body} -> encode_extension(extension, pattern, guard, body) @@ -224,7 +224,7 @@ defmodule Postgrex.TypeModule do end defp encode_super(extension, clause) do - case split_super_encode(clause) do + case split_super(clause) do {pattern, sub_oids, sub_types, guard, body} -> encode_super(extension, pattern, sub_oids, sub_types, guard, body) @@ -615,12 +615,11 @@ defmodule Postgrex.TypeModule do end defp decode_extension(extension, clause, dispatch, rest, acc, rem, full, rows) do - case split_extension_decode(clause) do - {pattern, mod, guard, body} -> + case split_extension(clause) do + {pattern, guard, body} -> decode_extension( extension, pattern, - mod, guard, body, dispatch, @@ -631,15 +630,14 @@ defmodule Postgrex.TypeModule do rows ) - {pattern, mod, body} -> - decode_extension(extension, pattern, mod, body, dispatch, rest, acc, rem, full, rows) + {pattern, body} -> + decode_extension(extension, pattern, body, dispatch, rest, acc, rem, full, rows) end end defp decode_extension( extension, pattern, - mod, guard, body, dispatch, @@ -652,7 +650,7 @@ defmodule Postgrex.TypeModule do quote do defp unquote(extension)( <>, - unquote(mod), + var!(mod), types, acc, unquote(rem), @@ -667,24 +665,24 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<>, mod = unquote(mod), acc) + defp unquote(extension)(<>, var!(mod) = mod, acc) when unquote(guard) do unquote(extension)(rest, mod, [unquote(body) | acc]) end defp unquote(extension)( <>, - nil = unquote(mod), + var!(mod) = mod, acc, callback ) when unquote(guard) do - unquote(extension)(rest, nil, [unquote(body) | acc], callback) + unquote(extension)(rest, mod, [unquote(body) | acc], callback) end defp unquote(extension)( <>, - nil = unquote(mod), + var!(mod), oids, types, n, @@ -696,11 +694,11 @@ defmodule Postgrex.TypeModule do end end - defp decode_extension(extension, pattern, mod, body, dispatch, rest, acc, rem, full, rows) do + defp decode_extension(extension, pattern, body, dispatch, rest, acc, rem, full, rows) do quote do defp unquote(extension)( <>, - unquote(mod), + var!(mod), types, acc, unquote(rem), @@ -714,24 +712,24 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<>, mod = unquote(mod), acc) do + defp unquote(extension)(<>, var!(mod), acc) do decoded = unquote(body) - unquote(extension)(rest, mod, [decoded | acc]) + unquote(extension)(rest, var!(mod), [decoded | acc]) end defp unquote(extension)( <>, - nil = unquote(mod), + var!(mod), acc, callback ) do decoded = unquote(body) - unquote(extension)(rest, nil, [decoded | acc], callback) + unquote(extension)(rest, var!(mod), [decoded | acc], callback) end defp unquote(extension)( <>, - nil = unquote(mod), + var!(mod), oids, types, n, @@ -760,29 +758,29 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<<-1::int32(), rest::binary>>, mod, acc) do - unquote(extension)(rest, mod, [@null | acc]) + defp unquote(extension)(<<-1::int32(), rest::binary>>, var!(mod), acc) do + unquote(extension)(rest, var!(mod), [@null | acc]) end defp unquote(extension)(<<>>, _, acc) do acc end - defp unquote(extension)(<<-1::int32(), rest::binary>>, nil, acc, callback) do - unquote(extension)(rest, nil, [@null | acc], callback) + defp unquote(extension)(<<-1::int32(), rest::binary>>, var!(mod), acc, callback) do + unquote(extension)(rest, var!(mod), [@null | acc], callback) end defp unquote(extension)(<>, _, acc, callback) do callback.(rest, acc) end - defp unquote(extension)(<<-1::int32(), rest::binary>>, nil, oids, types, n, acc) do + defp unquote(extension)(<<-1::int32(), rest::binary>>, _mod, oids, types, n, acc) do decode_tuple(rest, oids, types, n, acc) end end end - defp split_extension_encode({:->, _, [head, body]}) do + defp split_extension({:->, _, [head, body]}) do case head do [{:when, _, [pattern, guard]}] -> {pattern, guard, body} @@ -792,31 +790,14 @@ defmodule Postgrex.TypeModule do end end - defp split_extension_decode({:->, _, [head, body]}) do - case head do - [{:when, _, [pattern, guard]}] -> - {pattern, quote(do: _), guard, body} - - [pattern] -> - {pattern, quote(do: _), body} - - [{:when, _, [pattern, modifier, guard]}] -> - {pattern, modifier, guard, body} - - [pattern, modifier] -> - {pattern, modifier, body} - end - end - defp decode_super(extension, clause, dispatch, rest, acc, rem, full, rows) do - case split_super_decode(clause) do - {pattern, oids, types, mod, guard, body} -> + case split_super(clause) do + {pattern, oids, types, guard, body} -> decode_super( extension, pattern, oids, types, - mod, guard, body, dispatch, @@ -827,13 +808,12 @@ defmodule Postgrex.TypeModule do rows ) - {pattern, oids, types, mod, body} -> + {pattern, oids, types, body} -> decode_super( extension, pattern, oids, types, - mod, body, dispatch, rest, @@ -850,7 +830,6 @@ defmodule Postgrex.TypeModule do pattern, sub_oids, sub_types, - mod, guard, body, dispatch, @@ -865,7 +844,7 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), - unquote(mod), + var!(mod), types, acc, unquote(rem), @@ -884,19 +863,19 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), - mod = unquote(mod), + var!(mod), acc ) when unquote(guard) do acc = [unquote(body) | acc] - unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), mod, acc) + unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), var!(mod), acc) end defp unquote(extension)( <>, unquote(sub_oids), unquote(sub_types), - nil = unquote(mod), + var!(mod), oids, types, n, @@ -913,7 +892,6 @@ defmodule Postgrex.TypeModule do pattern, sub_oids, sub_types, - mod, body, dispatch, rest, @@ -927,7 +905,7 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), - unquote(mod), + var!(mod), types, acc, unquote(rem), @@ -945,18 +923,18 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), - mod = unquote(mod), + var!(mod), acc ) do acc = [unquote(body) | acc] - unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), mod, acc) + unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), var!(mod), acc) end defp unquote(extension)( <>, unquote(sub_oids), unquote(sub_types), - nil = unquote(mod), + var!(mod), oids, types, n, @@ -988,8 +966,8 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<<-1::int32(), rest::binary>>, sub_oids, sub_types, mod, acc) do - unquote(extension)(rest, sub_oids, sub_types, mod, [@null | acc]) + defp unquote(extension)(<<-1::int32(), rest::binary>>, sub_oids, sub_types, var!(mod), acc) do + unquote(extension)(rest, sub_oids, sub_types, var!(mod), [@null | acc]) end defp unquote(extension)(<<>>, _sub_oid, _sub_types, _mod, acc) do @@ -1000,7 +978,7 @@ defmodule Postgrex.TypeModule do <<-1::int32(), rest::binary>>, _sub_oids, _sub_types, - nil, + _mod, oids, types, n, @@ -1011,7 +989,7 @@ defmodule Postgrex.TypeModule do end end - defp split_super_encode({:->, _, [head, body]}) do + defp split_super({:->, _, [head, body]}) do case head do [{:when, _, [pattern, sub_oids, sub_types, guard]}] -> {pattern, sub_oids, sub_types, guard, body} @@ -1021,16 +999,6 @@ defmodule Postgrex.TypeModule do end end - defp split_super_decode({:->, _, [head, body]}) do - case head do - [{:when, _, [pattern, sub_oids, sub_types, modifier, guard]}] -> - {pattern, sub_oids, sub_types, modifier, guard, body} - - [pattern, sub_oids, sub_types, modifier] -> - {pattern, sub_oids, sub_types, modifier, body} - end - end - defp configure(extensions, opts) do defaults = Postgrex.Utils.default_extensions(opts) Enum.map(extensions ++ defaults, &configure/1) From 4bf1b9b41ced08ae619ee4eec2ec027a7f25597c Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Mon, 1 Jul 2024 20:57:59 -0400 Subject: [PATCH 11/12] get rid of warnings --- lib/postgrex/type_module.ex | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/postgrex/type_module.ex b/lib/postgrex/type_module.ex index 41504e70..bd80c2d7 100644 --- a/lib/postgrex/type_module.ex +++ b/lib/postgrex/type_module.ex @@ -658,6 +658,7 @@ defmodule Postgrex.TypeModule do unquote(rows) ) when unquote(guard) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -665,9 +666,10 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<>, var!(mod) = mod, acc) + defp unquote(extension)(<>, var!(mod), acc) when unquote(guard) do - unquote(extension)(rest, mod, [unquote(body) | acc]) + _ = var!(mod) + unquote(extension)(rest, var!(mod), [unquote(body) | acc]) end defp unquote(extension)( @@ -677,6 +679,7 @@ defmodule Postgrex.TypeModule do callback ) when unquote(guard) do + _ = var!(mod) unquote(extension)(rest, mod, [unquote(body) | acc], callback) end @@ -689,6 +692,7 @@ defmodule Postgrex.TypeModule do acc ) when unquote(guard) do + _ = var!(mod) decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end @@ -705,6 +709,7 @@ defmodule Postgrex.TypeModule do unquote(full), unquote(rows) ) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -713,6 +718,7 @@ defmodule Postgrex.TypeModule do end defp unquote(extension)(<>, var!(mod), acc) do + _ = var!(mod) decoded = unquote(body) unquote(extension)(rest, var!(mod), [decoded | acc]) end @@ -723,6 +729,7 @@ defmodule Postgrex.TypeModule do acc, callback ) do + _ = var!(mod) decoded = unquote(body) unquote(extension)(rest, var!(mod), [decoded | acc], callback) end @@ -735,6 +742,7 @@ defmodule Postgrex.TypeModule do n, acc ) do + _ = var!(mod) decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end @@ -852,6 +860,7 @@ defmodule Postgrex.TypeModule do unquote(rows) ) when unquote(guard) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -867,6 +876,7 @@ defmodule Postgrex.TypeModule do acc ) when unquote(guard) do + _ = var!(mod) acc = [unquote(body) | acc] unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), var!(mod), acc) end @@ -882,6 +892,7 @@ defmodule Postgrex.TypeModule do acc ) when unquote(guard) do + _ = var!(mod) decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end @@ -912,6 +923,7 @@ defmodule Postgrex.TypeModule do unquote(full), unquote(rows) ) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -926,6 +938,7 @@ defmodule Postgrex.TypeModule do var!(mod), acc ) do + _ = var!(mod) acc = [unquote(body) | acc] unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), var!(mod), acc) end @@ -940,6 +953,7 @@ defmodule Postgrex.TypeModule do n, acc ) do + _ = var!(mod) acc = [{n, unquote(body)} | acc] decode_tuple(rest, oids, types, n, acc) end From bc3fbdab4ba02bc8de6974eb9c648deea981c906 Mon Sep 17 00:00:00 2001 From: Greg Rychlewski Date: Tue, 2 Jul 2024 09:00:29 -0400 Subject: [PATCH 12/12] small cleanup --- lib/postgrex/type_module.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/postgrex/type_module.ex b/lib/postgrex/type_module.ex index bd80c2d7..502c7022 100644 --- a/lib/postgrex/type_module.ex +++ b/lib/postgrex/type_module.ex @@ -674,13 +674,13 @@ defmodule Postgrex.TypeModule do defp unquote(extension)( <>, - var!(mod) = mod, + var!(mod), acc, callback ) when unquote(guard) do _ = var!(mod) - unquote(extension)(rest, mod, [unquote(body) | acc], callback) + unquote(extension)(rest, var!(mod), [unquote(body) | acc], callback) end defp unquote(extension)(