diff --git a/lib/postgrex/extensions/array.ex b/lib/postgrex/extensions/array.ex index 13eefa42..92d3a959 100644 --- a/lib/postgrex/extensions/array.ex +++ b/lib/postgrex/extensions/array.ex @@ -33,6 +33,12 @@ defmodule Postgrex.Extensions.Array do data::binary>> = binary # decode_list/2 defined by TypeModule + type = + case type do + {extension, sub_oids, sub_types} -> {extension, sub_oids, sub_types, var!(mod)} + extension -> {extension, var!(mod)} + end + flat = decode_list(data, type) unquote(__MODULE__).decode(dims, flat) diff --git a/lib/postgrex/extensions/multirange.ex b/lib/postgrex/extensions/multirange.ex index abcbba7d..11bb2c20 100644 --- a/lib/postgrex/extensions/multirange.ex +++ b/lib/postgrex/extensions/multirange.ex @@ -29,7 +29,14 @@ defmodule Postgrex.Extensions.Multirange do quote location: :keep do <>, [_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..92c0278f 100644 --- a/lib/postgrex/extensions/range.ex +++ b/lib/postgrex/extensions/range.ex @@ -37,7 +37,14 @@ defmodule Postgrex.Extensions.Range do quote location: :keep do <>, [_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/timestamp.ex b/lib/postgrex/extensions/timestamp.ex index 63e90347..27184109 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,7 @@ 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?)) + unquote(__MODULE__).microsecond_to_elixir(microsecs, var!(mod), unquote(infinity?)) end end @@ -51,32 +52,35 @@ 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 + # 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 defp raise_infinity(type) do diff --git a/lib/postgrex/protocol.ex b/lib/postgrex/protocol.ex index 3a7f67bb..81556365 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 @@ -1715,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, @@ -1745,7 +1747,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 +1761,18 @@ defmodule Postgrex.Protocol do {:ok, query} end - defp describe_result(%{types: types}, query, result_oids, columns) do - with {:ok, result_info} <- fetch_type_info(result_oids, types), - {result_formats, result_types} = Enum.unzip(result_info) do + defp describe_result(%{types: types}, query, result_oids, result_mods, columns) 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(), @@ -3186,8 +3197,8 @@ defmodule Postgrex.Protocol do defp columns(fields) do fields - |> Enum.map(fn row_field(type_oid: oid, name: name) -> {oid, name} end) - |> :lists.unzip() + |> 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 cb6f4d57..502c7022 100644 --- a/lib/postgrex/type_module.ex +++ b/lib/postgrex/type_module.ex @@ -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 @@ -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 @@ -607,17 +617,40 @@ defmodule Postgrex.TypeModule do 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) + decode_extension( + extension, + pattern, + guard, + 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, guard, body, dispatch, rest, acc, rem, full, rows) do + defp decode_extension( + extension, + pattern, + guard, + body, + dispatch, + rest, + acc, + rem, + full, + rows + ) do quote do defp unquote(extension)( <>, + var!(mod), types, acc, unquote(rem), @@ -625,6 +658,7 @@ defmodule Postgrex.TypeModule do unquote(rows) ) when unquote(guard) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -632,18 +666,33 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<>, acc) + defp unquote(extension)(<>, var!(mod), acc) when unquote(guard) do - unquote(extension)(rest, [unquote(body) | acc]) + _ = var!(mod) + unquote(extension)(rest, var!(mod), [unquote(body) | acc]) end - defp unquote(extension)(<>, acc, callback) + defp unquote(extension)( + <>, + var!(mod), + acc, + callback + ) when unquote(guard) do - unquote(extension)(rest, [unquote(body) | acc], callback) + _ = var!(mod) + unquote(extension)(rest, var!(mod), [unquote(body) | acc], callback) end - defp unquote(extension)(<>, oids, types, n, acc) + defp unquote(extension)( + <>, + var!(mod), + oids, + types, + n, + acc + ) when unquote(guard) do + _ = var!(mod) decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end @@ -653,12 +702,14 @@ defmodule Postgrex.TypeModule do quote do defp unquote(extension)( <>, + var!(mod), types, acc, unquote(rem), unquote(full), unquote(rows) ) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -666,17 +717,32 @@ defmodule Postgrex.TypeModule do end end - defp unquote(extension)(<>, acc) do + defp unquote(extension)(<>, var!(mod), acc) do + _ = var!(mod) decoded = unquote(body) - unquote(extension)(rest, [decoded | acc]) + unquote(extension)(rest, var!(mod), [decoded | acc]) end - defp unquote(extension)(<>, acc, callback) do + defp unquote(extension)( + <>, + var!(mod), + acc, + callback + ) do + _ = var!(mod) decoded = unquote(body) - unquote(extension)(rest, [decoded | acc], callback) + unquote(extension)(rest, var!(mod), [decoded | acc], callback) end - defp unquote(extension)(<>, oids, types, n, acc) do + defp unquote(extension)( + <>, + var!(mod), + oids, + types, + n, + acc + ) do + _ = var!(mod) decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end @@ -686,6 +752,7 @@ defmodule Postgrex.TypeModule do quote do defp unquote(extension)( <<-1::int32(), unquote(rest)::binary>>, + _mod, types, acc, unquote(rem), @@ -699,23 +766,23 @@ 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>>, var!(mod), acc) do + unquote(extension)(rest, var!(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>>, var!(mod), acc, callback) do + unquote(extension)(rest, var!(mod), [@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>>, _mod, oids, types, n, acc) do decode_tuple(rest, oids, types, n, acc) end end @@ -750,7 +817,19 @@ defmodule Postgrex.TypeModule do ) {pattern, oids, types, body} -> - decode_super(extension, pattern, oids, types, body, dispatch, rest, acc, rem, full, rows) + decode_super( + extension, + pattern, + oids, + types, + body, + dispatch, + rest, + acc, + rem, + full, + rows + ) end end @@ -773,6 +852,7 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + var!(mod), types, acc, unquote(rem), @@ -780,6 +860,7 @@ defmodule Postgrex.TypeModule do unquote(rows) ) when unquote(guard) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -791,23 +872,27 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + var!(mod), acc ) when unquote(guard) do + _ = var!(mod) acc = [unquote(body) | acc] - unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), acc) + unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), var!(mod), acc) end defp unquote(extension)( <>, unquote(sub_oids), unquote(sub_types), + var!(mod), oids, types, n, acc ) when unquote(guard) do + _ = var!(mod) decode_tuple(rest, oids, types, n, [{n, unquote(body)} | acc]) end end @@ -831,12 +916,14 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + var!(mod), types, acc, unquote(rem), unquote(full), unquote(rows) ) do + _ = var!(mod) unquote(acc) = [unquote(body) | acc] case types do @@ -848,21 +935,25 @@ defmodule Postgrex.TypeModule do <>, unquote(sub_oids), unquote(sub_types), + var!(mod), acc ) do + _ = var!(mod) acc = [unquote(body) | acc] - unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), acc) + unquote(extension)(rest, unquote(sub_oids), unquote(sub_types), var!(mod), acc) end defp unquote(extension)( <>, unquote(sub_oids), unquote(sub_types), + var!(mod), oids, types, n, acc ) do + _ = var!(mod) acc = [{n, unquote(body)} | acc] decode_tuple(rest, oids, types, n, acc) end @@ -875,6 +966,7 @@ defmodule Postgrex.TypeModule do <<-1::int32(), unquote(rest)::binary>>, _sub_oids, _sub_types, + _mod, types, acc, unquote(rem), @@ -888,11 +980,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, var!(mod), acc) do + unquote(extension)(rest, sub_oids, sub_types, var!(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 +992,7 @@ defmodule Postgrex.TypeModule do <<-1::int32(), rest::binary>>, _sub_oids, _sub_types, + _mod, oids, types, n, diff --git a/test/query_test.exs b/test/query_test.exs index 312d2f38..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" @@ -1746,4 +1769,24 @@ 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 [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 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 7513db6c..5ad2e812 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -96,6 +96,8 @@ 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)[]); +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;