Browse Source

Merge pull request #125 from okeuday/master

Fix for Erlang/OTP 20.0
David N. Welton 8 years ago
parent
commit
371db09660
7 changed files with 59 additions and 19 deletions
  1. 16 0
      CHANGES
  2. 1 1
      src/epgsql.app.src
  3. 24 0
      src/epgsql_binary.erl
  4. 2 2
      src/epgsql_fdatetime.erl
  5. 2 0
      src/epgsql_types.erl
  6. 1 0
      test/data/test_schema.sql
  7. 13 16
      test/epgsql_tests.erl

+ 16 - 0
CHANGES

@@ -1,3 +1,19 @@
+In 3.3.0
+
+* Streaming replication protocol support (epgsql may act like PostgreSQL slave)
+  https://github.com/epgsql/epgsql/blob/devel/streaming.md
+* Connection options now may be passed as map()
+* More error extra data fields returned in #error{extra}
+  http://www.postgresql.org/docs/current/interactive/protocol-error-fields.html
+* Prefer non-localized severity in #error{severity} when available
+* Added `set_notice_receiver/2` function to dynamically change receiver for asynchronous notifications
+* Asynchronous notifications receiver may be set to registered process name (atom)
+* `get_cmd_status/1` function added
+* Fixed return value of `DELETE ... RETURNING ..` in case when 0 rows were deleted
+  (now returns `{ok, 0, Columns, []}` instead of `{ok, 0}`)
+* TCP socket implicitly closed when epgsql connection process terminates
+* Some typespecs fixed
+
 In 3.2.0:
 In 3.2.0:
 
 
 * #error.codename (more readable errors)
 * #error.codename (more readable errors)

+ 1 - 1
src/epgsql.app.src

@@ -1,6 +1,6 @@
 {application, epgsql,
 {application, epgsql,
  [{description, "PostgreSQL Client"},
  [{description, "PostgreSQL Client"},
-  {vsn, "3.2.0"},
+  {vsn, "3.3.0"},
   {modules, []},
   {modules, []},
   {registered, []},
   {registered, []},
   {applications, [kernel,
   {applications, [kernel,

+ 24 - 0
src/epgsql_binary.erl

@@ -81,6 +81,7 @@ encode(geometry, Data, _)                   -> encode_geometry(Data);
 encode(cidr, B, Codec)                      -> encode(bytea, encode_net(B), Codec);
 encode(cidr, B, Codec)                      -> encode(bytea, encode_net(B), Codec);
 encode(inet, B, Codec)                      -> encode(bytea, encode_net(B), Codec);
 encode(inet, B, Codec)                      -> encode(bytea, encode_net(B), Codec);
 encode(int4range, R, _) when is_tuple(R)    -> encode_int4range(R);
 encode(int4range, R, _) when is_tuple(R)    -> encode_int4range(R);
+encode(int8range, R, _) when is_tuple(R)    -> encode_int8range(R);
 encode(Type, L, Codec) when is_list(L)      -> encode(Type, list_to_binary(L), Codec);
 encode(Type, L, Codec) when is_list(L)      -> encode(Type, list_to_binary(L), Codec);
 encode(_Type, _Value, _)                    -> {error, unsupported}.
 encode(_Type, _Value, _)                    -> {error, unsupported}.
 
 
@@ -108,6 +109,7 @@ decode({array, _Type}, B, Codec)               -> decode_array(B, Codec);
 decode(point, B, _)                            -> decode_point(B);
 decode(point, B, _)                            -> decode_point(B);
 decode(geometry, B, _)                         -> ewkb:decode_geometry(B);
 decode(geometry, B, _)                         -> ewkb:decode_geometry(B);
 decode(int4range, B, _)                        -> decode_int4range(B);
 decode(int4range, B, _)                        -> decode_int4range(B);
+decode(int8range, B, _)                        -> decode_int8range(B);
 decode(_Other, Bin, _)                         -> Bin.
 decode(_Other, Bin, _)                         -> Bin.
 
 
 encode_array(Type, Oid, A, Codec) ->
 encode_array(Type, Oid, A, Codec) ->
@@ -253,6 +255,20 @@ encode_int4range({From, To}) ->
     ToInt = to_int(To),
     ToInt = to_int(To),
     <<17:?int32, 2:1/big-signed-unit:8, 4:?int32, FromInt:?int32, 4:?int32, ToInt:?int32>>.
     <<17:?int32, 2:1/big-signed-unit:8, 4:?int32, FromInt:?int32, 4:?int32, ToInt:?int32>>.
 
 
+%% @doc encode an int8range
+encode_int8range({minus_infinity, plus_infinity}) ->
+    <<1:?int32, 24:1/big-signed-unit:8>>;
+encode_int8range({From, plus_infinity}) ->
+    FromInt = to_int(From),
+    <<13:?int32, 18:1/big-signed-unit:8, 8:?int32, FromInt:?int64>>;
+encode_int8range({minus_infinity, To}) ->
+    ToInt = to_int(To),
+    <<13:?int32, 8:1/big-signed-unit:8, 8:?int32, ToInt:?int64>>;
+encode_int8range({From, To}) ->
+    FromInt = to_int(From),
+    ToInt = to_int(To),
+    <<25:?int32, 2:1/big-signed-unit:8, 8:?int32, FromInt:?int64, 8:?int32, ToInt:?int64>>.
+
 to_int(N) when is_integer(N) -> N;
 to_int(N) when is_integer(N) -> N;
 to_int(S) when is_list(S) -> erlang:list_to_integer(S);
 to_int(S) when is_list(S) -> erlang:list_to_integer(S);
 to_int(B) when is_binary(B) -> erlang:binary_to_integer(B).
 to_int(B) when is_binary(B) -> erlang:binary_to_integer(B).
@@ -263,6 +279,12 @@ decode_int4range(<<8:1/big-signed-unit:8, 4:?int32, To:?int32>>) -> {minus_infin
 decode_int4range(<<18:1/big-signed-unit:8, 4:?int32, From:?int32>>) -> {From, plus_infinity};
 decode_int4range(<<18:1/big-signed-unit:8, 4:?int32, From:?int32>>) -> {From, plus_infinity};
 decode_int4range(<<24:1/big-signed-unit:8>>) -> {minus_infinity, plus_infinity}.
 decode_int4range(<<24:1/big-signed-unit:8>>) -> {minus_infinity, plus_infinity}.
 
 
+%% @doc decode an int8range
+decode_int8range(<<2:1/big-signed-unit:8, 8:?int32, From:?int64, 8:?int32, To:?int64>>) -> {From, To};
+decode_int8range(<<8:1/big-signed-unit:8, 8:?int32, To:?int64>>) -> {minus_infinity, To};
+decode_int8range(<<18:1/big-signed-unit:8, 8:?int32, From:?int64>>) -> {From, plus_infinity};
+decode_int8range(<<24:1/big-signed-unit:8>>) -> {minus_infinity, plus_infinity}.
+
 supports(bool)    -> true;
 supports(bool)    -> true;
 supports(bpchar)  -> true;
 supports(bpchar)  -> true;
 supports(int2)    -> true;
 supports(int2)    -> true;
@@ -310,4 +332,6 @@ supports({array, inet})   -> true;
 supports({array, record}) -> true;
 supports({array, record}) -> true;
 supports({array, json})   -> true;
 supports({array, json})   -> true;
 supports({array, jsonb})   -> true;
 supports({array, jsonb})   -> true;
+supports(int4range)       -> true;
+supports(int8range)       -> true;
 supports(_Type)       -> false.
 supports(_Type)       -> false.

+ 2 - 2
src/epgsql_fdatetime.erl

@@ -107,7 +107,7 @@ now2f({MegaSecs, Secs, MicroSecs}) ->
 tmodulo(T, U) ->
 tmodulo(T, U) ->
     Q = case T < 0 of
     Q = case T < 0 of
         true  -> ceiling(T / U);
         true  -> ceiling(T / U);
-        false -> floor(T / U)
+        false -> flooring(T / U)
     end,
     end,
     case Q of
     case Q of
         0 -> {T, Q};
         0 -> {T, Q};
@@ -118,7 +118,7 @@ rint(N)      -> round(N) * 1.0.
 timeround(J) -> rint(J * 10000000000.0) / 10000000000.0.
 timeround(J) -> rint(J * 10000000000.0) / 10000000000.0.
 tsround(J)   -> rint(J * 1000000.0) / 1000000.0.
 tsround(J)   -> rint(J * 1000000.0) / 1000000.0.
 
 
-floor(X) ->
+flooring(X) ->
     T = erlang:trunc(X),
     T = erlang:trunc(X),
     case (X - T) of
     case (X - T) of
         N when N < 0 -> T - 1;
         N when N < 0 -> T - 1;

+ 2 - 0
src/epgsql_types.erl

@@ -101,6 +101,7 @@ oid2type(3500)  -> anyenum;
 oid2type(3802)  -> jsonb;
 oid2type(3802)  -> jsonb;
 oid2type(3807)  -> {array, jsonb};
 oid2type(3807)  -> {array, jsonb};
 oid2type(3904)  -> int4range;
 oid2type(3904)  -> int4range;
+oid2type(3926)  -> int8range;
 oid2type(Oid)   -> {unknown_oid, Oid}.
 oid2type(Oid)   -> {unknown_oid, Oid}.
 
 
 type2oid(bool)                  -> 16;
 type2oid(bool)                  -> 16;
@@ -202,4 +203,5 @@ type2oid(anyenum)               -> 3500;
 type2oid(jsonb)                 -> 3802;
 type2oid(jsonb)                 -> 3802;
 type2oid({array, jsonb})        -> 3807;
 type2oid({array, jsonb})        -> 3807;
 type2oid(int4range)             -> 3904;
 type2oid(int4range)             -> 3904;
+type2oid(int8range)             -> 3926;
 type2oid(Type)                  -> {unknown_type, Type}.
 type2oid(Type)                  -> {unknown_type, Type}.

+ 1 - 0
test/data/test_schema.sql

@@ -65,6 +65,7 @@ CREATE TABLE test_table2 (
   c_cidr cidr,
   c_cidr cidr,
   c_inet inet,
   c_inet inet,
   c_int4range int4range,
   c_int4range int4range,
+  c_int8range int8range,
   c_json json,
   c_json json,
   c_jsonb jsonb);
   c_jsonb jsonb);
 
 

+ 13 - 16
test/epgsql_tests.erl

@@ -959,12 +959,24 @@ range_type_test(Module) ->
       Module,
       Module,
       9.2,
       9.2,
       fun(_C) ->
       fun(_C) ->
-          check_type(Module, int4range, "int4range(10, 20)", <<"[10,20)">>,
+          check_type(Module, int4range, "int4range(10, 20)", {10, 20},
                      [{1, 58}, {-1, 12}, {-985521, 5412687}, {minus_infinity, 0},
                      [{1, 58}, {-1, 12}, {-985521, 5412687}, {minus_infinity, 0},
                       {984655, plus_infinity}, {minus_infinity, plus_infinity}])
                       {984655, plus_infinity}, {minus_infinity, plus_infinity}])
       end,
       end,
       []).
       []).
 
 
+range8_type_test(Module) ->
+    with_min_version(
+      Module,
+      9.2,
+      fun(_C) ->
+          check_type(Module, int8range, "int8range(10, 20)", {10, 20},
+                     [{1, 58}, {-1, 12}, {-9223372036854775808, 5412687},
+                      {minus_infinity, 9223372036854775807},
+                      {984655, plus_infinity}, {minus_infinity, plus_infinity}])
+      end,
+      []).
+
 %% -- run all tests --
 %% -- run all tests --
 
 
 run_tests() ->
 run_tests() ->
@@ -1109,23 +1121,8 @@ compare(Type, V1 = {_, _, MS}, {D2, {H2, M2, S2}}) when Type == timestamp;
                                                         Type == timestamptz ->
                                                         Type == timestamptz ->
     {D1, {H1, M1, S1}} = calendar:now_to_universal_time(V1),
     {D1, {H1, M1, S1}} = calendar:now_to_universal_time(V1),
     ({D1, H1, M1} =:= {D2, H2, M2}) and (abs(S1 + MS/1000000 - S2) < 0.000000000000001);
     ({D1, H1, M1} =:= {D2, H2, M2}) and (abs(S1 + MS/1000000 - S2) < 0.000000000000001);
-compare(int4range, {Lower, Upper}, Result) ->
-  translate_infinities(Lower, Upper) =:= Result;
 compare(_Type, V1, V2)     -> V1 =:= V2.
 compare(_Type, V1, V2)     -> V1 =:= V2.
 
 
-translate_infinities(Lower, Upper) ->
-  iolist_to_binary([lower(Lower), [","], upper(Upper)]).
-
-lower(minus_infinity) ->
-  "(";
-lower(Val) ->
-  io_lib:format("[~p", [Val]).
-
-upper(plus_infinity) ->
-  ")";
-upper(Val) ->
-  io_lib:format("~p)", [Val]).
-
 format_hstore({Hstore}) -> Hstore;
 format_hstore({Hstore}) -> Hstore;
 format_hstore(Hstore) ->
 format_hstore(Hstore) ->
     [{format_hstore_key(Key), format_hstore_value(Value)} || {Key, Value} <- Hstore].
     [{format_hstore_key(Key), format_hstore_value(Value)} || {Key, Value} <- Hstore].