Browse Source

Merge branch 'net_types_conversion' of git://github.com/tnt-dev/epgsql into tnt-dev-net_types_conversion

Conflicts:
	src/epgsql_binary.erl
	src/epgsql_types.erl
David N. Welton 10 years ago
parent
commit
c6c510372c
4 changed files with 54 additions and 6 deletions
  1. 39 2
      src/epgsql_binary.erl
  2. 5 1
      src/epgsql_types.erl
  3. 7 2
      test/epgsql_tests.erl
  4. 3 1
      test_data/test_schema.sql

+ 39 - 2
src/epgsql_binary.erl

@@ -16,6 +16,13 @@
 
 
 -define(datetime, (get(datetime_mod))).
 -define(datetime, (get(datetime_mod))).
 
 
+-define(INET, 2).
+-define(INET6, 3).
+-define(IP_SIZE, 4).
+-define(IP6_SIZE, 16).
+-define(MAX_IP_MASK, 32).
+-define(MAX_IP6_MASK, 128).
+
 new_codec([]) -> #codec{}.
 new_codec([]) -> #codec{}.
 
 
 update_type_cache(TypeInfos, Codec) ->
 update_type_cache(TypeInfos, Codec) ->
@@ -67,6 +74,8 @@ encode({array, Type}, L, Codec) when is_list(L) -> encode_array(Type, type2oid(T
 encode(hstore, {L}, _) when is_list(L)      -> encode_hstore(L);
 encode(hstore, {L}, _) when is_list(L)      -> encode_hstore(L);
 encode(point, {X,Y}, _)                     -> encode_point({X,Y});
 encode(point, {X,Y}, _)                     -> encode_point({X,Y});
 encode(geometry, Data, _)                   -> encode_geometry(Data);
 encode(geometry, Data, _)                   -> encode_geometry(Data);
+encode(cidr, B, Codec)                      -> encode(bytea, encode_net(B), Codec);
+encode(inet, B, Codec)                      -> encode(bytea, encode_net(B), Codec);
 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}.
 
 
@@ -87,6 +96,8 @@ decode(timestamptz = Type, B, _)               -> ?datetime:decode(Type, B);
 decode(interval = Type, B, _)                  -> ?datetime:decode(Type, B);
 decode(interval = Type, B, _)                  -> ?datetime:decode(Type, B);
 decode(uuid, B, _)                             -> decode_uuid(B);
 decode(uuid, B, _)                             -> decode_uuid(B);
 decode(hstore, Hstore, _)                      -> decode_hstore(Hstore);
 decode(hstore, Hstore, _)                      -> decode_hstore(Hstore);
+decode(inet, B, _)                             -> decode_net(B);
+decode(cidr, B, _)                             -> decode_net(B);
 decode({array, _Type}, B, Codec)               -> decode_array(B, Codec);
 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);
@@ -142,6 +153,19 @@ encode_hstore_string(Str) when is_float(Str) ->
     encode_hstore_string(iolist_to_binary(io_lib:format("~w", [Str])));
     encode_hstore_string(iolist_to_binary(io_lib:format("~w", [Str])));
 encode_hstore_string(Str) when is_binary(Str) -> <<(byte_size(Str)):?int32, Str/binary>>.
 encode_hstore_string(Str) when is_binary(Str) -> <<(byte_size(Str)):?int32, Str/binary>>.
 
 
+encode_net({{_, _, _, _} = IP, Mask}) ->
+    Bin = list_to_binary(tuple_to_list(IP)),
+    <<?INET, Mask, 1, ?IP_SIZE, Bin/binary>>;
+encode_net({{_, _, _, _, _, _, _, _} = IP, Mask}) ->
+    Bin = << <<X:16>> || X <- tuple_to_list(IP) >>,
+    <<?INET6, Mask, 1, ?IP6_SIZE, Bin/binary>>;
+encode_net({_, _, _, _} = IP) ->
+    Bin = list_to_binary(tuple_to_list(IP)),
+    <<?INET, ?MAX_IP_MASK, 0, ?IP_SIZE, Bin/binary>>;
+encode_net({_, _, _, _, _, _, _, _} = IP) ->
+    Bin = << <<X:16>> || X <- tuple_to_list(IP) >>,
+    <<?INET6, ?MAX_IP6_MASK, 0, ?IP6_SIZE, Bin/binary>>.
+
 decode_array(<<NDims:?int32, _HasNull:?int32, Oid:?int32, Rest/binary>>, Codec) ->
 decode_array(<<NDims:?int32, _HasNull:?int32, Oid:?int32, Rest/binary>>, Codec) ->
     {Dims, Data} = erlang:split_binary(Rest, NDims * 2 * 4),
     {Dims, Data} = erlang:split_binary(Rest, NDims * 2 * 4),
     Lengths = [Len || <<Len:?int32, _LBound:?int32>> <= Dims],
     Lengths = [Len || <<Len:?int32, _LBound:?int32>> <= Dims],
@@ -197,8 +221,15 @@ encode_geometry(Data) ->
     Size = byte_size(Bin),
     Size = byte_size(Bin),
     <<Size:?int32, Bin/binary>>.
     <<Size:?int32, Bin/binary>>.
 
 
-supports(geometry) -> true;
-supports(point)   -> true;
+decode_net(<<?INET, Mask, 1, ?IP_SIZE, Bin/binary>>) ->
+    {list_to_tuple(binary_to_list(Bin)), Mask};
+decode_net(<<?INET6, Mask, 1, ?IP6_SIZE, Bin/binary>>) ->
+    {list_to_tuple([X || <<X:16>> <= Bin]), Mask};
+decode_net(<<?INET, ?MAX_IP_MASK, 0, ?IP_SIZE, Bin/binary>>) ->
+    list_to_tuple(binary_to_list(Bin));
+decode_net(<<?INET6, ?MAX_IP6_MASK, 0, ?IP6_SIZE, Bin/binary>>) ->
+    list_to_tuple([X || <<X:16>> <= Bin]).
+
 supports(bool)    -> true;
 supports(bool)    -> true;
 supports(bpchar)  -> true;
 supports(bpchar)  -> true;
 supports(int2)    -> true;
 supports(int2)    -> true;
@@ -218,6 +249,10 @@ supports(timestamptz) -> true;
 supports(interval)    -> true;
 supports(interval)    -> true;
 supports(uuid)        -> true;
 supports(uuid)        -> true;
 supports(hstore)      -> true;
 supports(hstore)      -> true;
+supports(cidr)        -> true;
+supports(inet)        -> true;
+supports(geometry)    -> true;
+supports(point)       -> true;
 supports({array, bool})   -> true;
 supports({array, bool})   -> true;
 supports({array, int2})   -> true;
 supports({array, int2})   -> true;
 supports({array, int4})   -> true;
 supports({array, int4})   -> true;
@@ -235,4 +270,6 @@ supports({array, interval})      -> true;
 supports({array, hstore})        -> true;
 supports({array, hstore})        -> true;
 supports({array, varchar}) -> true;
 supports({array, varchar}) -> true;
 supports({array, uuid})   -> true;
 supports({array, uuid})   -> true;
+supports({array, cidr})   -> true;
+supports({array, inet})   -> true;
 supports(_Type)       -> false.
 supports(_Type)       -> false.

+ 5 - 1
src/epgsql_types.erl

@@ -39,6 +39,7 @@ oid2type(790)   -> cash;
 oid2type(829)   -> macaddr;
 oid2type(829)   -> macaddr;
 oid2type(869)   -> inet;
 oid2type(869)   -> inet;
 oid2type(650)   -> cidr;
 oid2type(650)   -> cidr;
+oid2type(651)   -> {array, cidr};
 oid2type(1000)  -> {array, bool};
 oid2type(1000)  -> {array, bool};
 oid2type(1005)  -> {array, int2};
 oid2type(1005)  -> {array, int2};
 oid2type(1007)  -> {array, int4};
 oid2type(1007)  -> {array, int4};
@@ -50,6 +51,7 @@ oid2type(1021)  -> {array, float4};
 oid2type(1022)  -> {array, float8};
 oid2type(1022)  -> {array, float8};
 oid2type(1033)  -> aclitem;
 oid2type(1033)  -> aclitem;
 oid2type(1263)  -> {array, cstring};
 oid2type(1263)  -> {array, cstring};
+oid2type(1041)  -> {array, inet};
 oid2type(1042)  -> bpchar;
 oid2type(1042)  -> bpchar;
 oid2type(1043)  -> varchar;
 oid2type(1043)  -> varchar;
 oid2type(1082)  -> date;
 oid2type(1082)  -> date;
@@ -122,6 +124,8 @@ type2oid(path)                  -> 602;
 type2oid(box)                   -> 603;
 type2oid(box)                   -> 603;
 type2oid(polygon)               -> 604;
 type2oid(polygon)               -> 604;
 type2oid(line)                  -> 628;
 type2oid(line)                  -> 628;
+type2oid(cidr)                  -> 650;
+type2oid({array, cidr})         -> 651;
 type2oid(float4)                -> 700;
 type2oid(float4)                -> 700;
 type2oid(float8)                -> 701;
 type2oid(float8)                -> 701;
 type2oid(abstime)               -> 702;
 type2oid(abstime)               -> 702;
@@ -132,7 +136,6 @@ type2oid(circle)                -> 718;
 type2oid(cash)                  -> 790;
 type2oid(cash)                  -> 790;
 type2oid(macaddr)               -> 829;
 type2oid(macaddr)               -> 829;
 type2oid(inet)                  -> 869;
 type2oid(inet)                  -> 869;
-type2oid(cidr)                  -> 650;
 type2oid({array, bool})         -> 1000;
 type2oid({array, bool})         -> 1000;
 type2oid({array, int2})         -> 1005;
 type2oid({array, int2})         -> 1005;
 type2oid({array, int4})         -> 1007;
 type2oid({array, int4})         -> 1007;
@@ -144,6 +147,7 @@ type2oid({array, float4})       -> 1021;
 type2oid({array, float8})       -> 1022;
 type2oid({array, float8})       -> 1022;
 type2oid(aclitem)               -> 1033;
 type2oid(aclitem)               -> 1033;
 type2oid({array, cstring})      -> 1263;
 type2oid({array, cstring})      -> 1263;
+type2oid({array, inet})         -> 1041;
 type2oid(bpchar)                -> 1042;
 type2oid(bpchar)                -> 1042;
 type2oid(varchar)               -> 1043;
 type2oid(varchar)               -> 1043;
 type2oid(date)                  -> 1082;
 type2oid(date)                  -> 1082;

+ 7 - 2
test/epgsql_tests.erl

@@ -573,6 +573,10 @@ hstore_type_test(Module) ->
     check_type(Module, hstore, "'a => 1, b => 2.0, c => null'",
     check_type(Module, hstore, "'a => 1, b => 2.0, c => null'",
                {[{<<"c">>, null}, {<<"b">>, <<"2.0">>}, {<<"a">>, <<"1">>}]}, Values).
                {[{<<"c">>, null}, {<<"b">>, <<"2.0">>}, {<<"a">>, <<"1">>}]}, Values).
 
 
+net_type_test(Module) ->
+    check_type(Module, cidr, "'127.0.0.1/32'", {{127,0,0,1}, 32}, [{{127,0,0,1}, 32}, {{0,0,0,0,0,0,0,1}, 128}]),
+    check_type(Module, inet, "'127.0.0.1'", {127,0,0,1}, [{127,0,0,1}, {0,0,0,0,0,0,0,1}]).
+
 array_type_test(Module) ->
 array_type_test(Module) ->
     with_connection(
     with_connection(
       Module,
       Module,
@@ -605,7 +609,9 @@ array_type_test(Module) ->
           Select(timestamptz, [{{2008,1,2},{3,4,5.0}}, {{2008,1,2},{3,4,6.0}}]),
           Select(timestamptz, [{{2008,1,2},{3,4,5.0}}, {{2008,1,2},{3,4,6.0}}]),
           Select(interval, [{{1,2,3.1},0,0}, {{1,2,3.2},0,0}]),
           Select(interval, [{{1,2,3.1},0,0}, {{1,2,3.2},0,0}]),
           Select(hstore, [{[{null, null}, {a, 1}, {1, 2}]}]),
           Select(hstore, [{[{null, null}, {a, 1}, {1, 2}]}]),
-          Select(hstore, [[{[{null, null}, {a, 1}, {1, 2}]}, {[]}], [{[{a, 1}]}, {[{null, 2}]}]])
+          Select(hstore, [[{[{null, null}, {a, 1}, {1, 2}]}, {[]}], [{[{a, 1}]}, {[{null, 2}]}]]),
+          Select(cidr, [{{127,0,0,1}, 32}, {{0,0,0,0,0,0,0,1}, 128}]),
+          Select(inet, [{127,0,0,1}, {0,0,0,0,0,0,0,1}])
       end).
       end).
 
 
 text_format_test(Module) ->
 text_format_test(Module) ->
@@ -618,7 +624,6 @@ text_format_test(Module) ->
                                {ok, _Cols, [{V2}]} = Module:equery(C, Query, [V]),
                                {ok, _Cols, [{V2}]} = Module:equery(C, Query, [V]),
                                {ok, _Cols, [{V2}]} = Module:equery(C, Query, [V2])
                                {ok, _Cols, [{V2}]} = Module:equery(C, Query, [V2])
                        end,
                        end,
-              Select("inet", "127.0.0.1"),
               Select("numeric", "123456")
               Select("numeric", "123456")
       end).
       end).
 
 

+ 3 - 1
test_data/test_schema.sql

@@ -59,7 +59,9 @@ CREATE TABLE test_table2 (
   c_timestamp timestamp,
   c_timestamp timestamp,
   c_timestamptz timestamptz,
   c_timestamptz timestamptz,
   c_interval interval,
   c_interval interval,
-  c_hstore hstore);
+  c_hstore hstore,
+  c_cidr cidr,
+  c_inet inet);
 
 
 CREATE LANGUAGE plpgsql;
 CREATE LANGUAGE plpgsql;