Feotov Daniil 10 лет назад
Родитель
Сommit
9881839b78
3 измененных файлов с 250 добавлено и 242 удалено
  1. 94 92
      src/epgsql_types.erl
  2. 133 135
      src/ewkb.erl
  3. 23 15
      src/pgsql_binary.erl

+ 94 - 92
src/epgsql_types.erl

@@ -2,98 +2,99 @@
 
 -export([oid2type/1, type2oid/1]).
 
-oid2type(16)   -> bool;
-oid2type(17)   -> bytea;
-oid2type(18)   -> char;
-oid2type(19)   -> name;
-oid2type(20)   -> int8;
-oid2type(21)   -> int2;
-oid2type(22)   -> int2vector;
-oid2type(23)   -> int4;
-oid2type(24)   -> regproc;
-oid2type(25)   -> text;
-oid2type(26)   -> oid;
-oid2type(27)   -> tid;
-oid2type(28)   -> xid;
-oid2type(29)   -> cid;
-oid2type(30)   -> oidvector;
-oid2type(71)   -> pg_type_reltype;
-oid2type(75)   -> pg_attribute_reltype;
-oid2type(81)   -> pg_proc_reltype;
-oid2type(83)   -> pg_class_reltype;
-oid2type(142)  -> xml;
-oid2type(600)  -> point;
-oid2type(601)  -> lseg;
-oid2type(602)  -> path;
-oid2type(603)  -> box;
-oid2type(604)  -> polygon;
-oid2type(628)  -> line;
-oid2type(700)  -> float4;
-oid2type(701)  -> float8;
-oid2type(702)  -> abstime;
-oid2type(703)  -> reltime;
-oid2type(704)  -> tinterval;
-oid2type(705)  -> unknown;
-oid2type(718)  -> circle;
-oid2type(790)  -> cash;
-oid2type(829)  -> macaddr;
-oid2type(869)  -> inet;
-oid2type(650)  -> cidr;
-oid2type(1000) -> {array, bool};
-oid2type(1005) -> {array, int2};
-oid2type(1007) -> {array, int4};
-oid2type(1009) -> {array, text};
-oid2type(1014) -> {array, char};
-oid2type(1015) -> {array, varchar};
-oid2type(1016) -> {array, int8};
-oid2type(1021) -> {array, float4};
-oid2type(1022) -> {array, float8};
-oid2type(1033) -> aclitem;
-oid2type(1263) -> {array, cstring};
-oid2type(1042) -> bpchar;
-oid2type(1043) -> varchar;
-oid2type(1082) -> date;
-oid2type(1083) -> time;
-oid2type(1114) -> timestamp;
-oid2type(1115) -> {array, timestamp};
-oid2type(1182) -> {array, date};
-oid2type(1183) -> {array, time};
-oid2type(1184) -> timestamptz;
-oid2type(1185) -> {array, timestamptz};
-oid2type(1186) -> interval;
-oid2type(1187) -> {array, interval};
-oid2type(1266) -> timetz;
-oid2type(1270) -> {array, timetz};
-oid2type(1560) -> bit;
-oid2type(1562) -> varbit;
-oid2type(1700) -> numeric;
-oid2type(1790) -> refcursor;
-oid2type(2202) -> regprocedure;
-oid2type(2203) -> regoper;
-oid2type(2204) -> regoperator;
-oid2type(2205) -> regclass;
-oid2type(2206) -> regtype;
-oid2type(2211) -> {array, regtype};
-oid2type(3614) -> tsvector;
-oid2type(3642) -> gtsvector;
-oid2type(3615) -> tsquery;
-oid2type(3734) -> regconfig;
-oid2type(3769) -> regdictionary;
-oid2type(2249) -> record;
-oid2type(2275) -> cstring;
-oid2type(2276) -> any;
-oid2type(2277) -> {array, any};
-oid2type(2278) -> void;
-oid2type(2279) -> trigger;
-oid2type(2280) -> language_handler;
-oid2type(2281) -> internal;
-oid2type(2282) -> opaque;
-oid2type(2283) -> anyelement;
-oid2type(2776) -> anynonarray;
-oid2type(2950) -> uuid;
-oid2type(2951) -> {array, uuid};
-oid2type(3500) -> anyenum;
-oid2type(Oid)  -> {unknown_oid, Oid}.
+oid2type(16)    -> bool;
+oid2type(17)    -> bytea;
+oid2type(18)    -> char;
+oid2type(19)    -> name;
+oid2type(20)    -> int8;
+oid2type(21)    -> int2;
+oid2type(22)    -> int2vector;
+oid2type(23)    -> int4;
+oid2type(24)    -> regproc;
+oid2type(25)    -> text;
+oid2type(26)    -> oid;
+oid2type(27)    -> tid;
+oid2type(28)    -> xid;
+oid2type(29)    -> cid;
+oid2type(30)    -> oidvector;
+oid2type(71)    -> pg_type_reltype;
+oid2type(75)    -> pg_attribute_reltype;
+oid2type(81)    -> pg_proc_reltype;
+oid2type(83)    -> pg_class_reltype;
+oid2type(142)   -> xml;
+oid2type(600)   -> point;
+oid2type(601)   -> lseg;
+oid2type(602)   -> path;
+oid2type(603)   -> box;
+oid2type(604)   -> polygon;
+oid2type(628)   -> line;
+oid2type(700)   -> float4;
+oid2type(701)   -> float8;
+oid2type(702)   -> abstime;
+oid2type(703)   -> reltime;
+oid2type(704)   -> tinterval;
+oid2type(705)   -> unknown;
+oid2type(718)   -> circle;
+oid2type(790)   -> cash;
+oid2type(829)   -> macaddr;
+oid2type(869)   -> inet;
+oid2type(650)   -> cidr;
+oid2type(1000)  -> {array, bool};
+oid2type(1005)  -> {array, int2};
+oid2type(1007)  -> {array, int4};
+oid2type(1009)  -> {array, text};
+oid2type(1014)  -> {array, char};
+oid2type(1015)  -> {array, varchar};
+oid2type(1016)  -> {array, int8};
+oid2type(1021)  -> {array, float4};
+oid2type(1022)  -> {array, float8};
+oid2type(1033)  -> aclitem;
+oid2type(1263)  -> {array, cstring};
+oid2type(1042)  -> bpchar;
+oid2type(1043)  -> varchar;
+oid2type(1082)  -> date;
+oid2type(1083)  -> time;
+oid2type(1114)  -> timestamp;
+oid2type(1115)  -> {array, timestamp};
+oid2type(1182)  -> {array, date};
+oid2type(1183)  -> {array, time};
+oid2type(1184)  -> timestamptz;
+oid2type(1185)  -> {array, timestamptz};
+oid2type(1186)  -> interval;
+oid2type(1187)  -> {array, interval};
+oid2type(1266)  -> timetz;
+oid2type(1270)  -> {array, timetz};
+oid2type(1560)  -> bit;
+oid2type(1562)  -> varbit;
+oid2type(1700)  -> numeric;
+oid2type(1790)  -> refcursor;
+oid2type(2202)  -> regprocedure;
+oid2type(2203)  -> regoper;
+oid2type(2204)  -> regoperator;
+oid2type(2205)  -> regclass;
+oid2type(2206)  -> regtype;
+oid2type(2211)  -> {array, regtype};
+oid2type(3614)  -> tsvector;
+oid2type(3642)  -> gtsvector;
+oid2type(3615)  -> tsquery;
+oid2type(3734)  -> regconfig;
+oid2type(3769)  -> regdictionary;
+oid2type(2249)  -> record;
+oid2type(2275)  -> cstring;
+oid2type(2276)  -> any;
+oid2type(2277)  -> {array, any};
+oid2type(2278)  -> void;
+oid2type(2279)  -> trigger;
+oid2type(2280)  -> language_handler;
+oid2type(2281)  -> internal;
+oid2type(2282)  -> opaque;
+oid2type(2283)  -> anyelement;
+oid2type(2776)  -> anynonarray;
+oid2type(2950)  -> uuid;
+oid2type(2951)  -> {array, uuid};
+oid2type(3500)  -> anyenum;
+oid2type(26256) -> geometry;
+oid2type(Oid)   -> {unknown_oid, Oid}.
 
 type2oid(bool)                  -> 16;
 type2oid(bytea)                 -> 17;
@@ -186,4 +187,5 @@ type2oid(anynonarray)           -> 2776;
 type2oid(uuid)                  -> 2950;
 type2oid({array, uuid})         -> 2951;
 type2oid(anyenum)               -> 3500;
+type2oid(geometry)              -> 26256;
 type2oid(Type)                  -> {unknown_type, Type}.

+ 133 - 135
src/ewkb.erl

@@ -1,6 +1,6 @@
 -module(ewkb).
 
--export([parse_geometry/1, format_geometry/1]).
+-export([decode_geometry/1, encode_geometry/1]).
 
 -type point_type() :: '2d' | '3d' | '2dm' | '3dm'.
 
@@ -144,43 +144,43 @@
                    | triangle.%
 
 
-parse_geometry(Binary) ->
-  {Geometry, <<>>} = parse_geometry_data(Binary),
+decode_geometry(Binary) ->
+  {Geometry, <<>>} = decode_geometry_data(Binary),
   Geometry.
 
-format_geometry(Geometry) ->
-  Type = format_type(Geometry),
-  PointType = format_point_type(Geometry),
-  Data = format_geometry_data(Geometry),
-  <<"01", Type/binary, PointType/binary, Data/binary>>.
+encode_geometry(Geometry) ->
+  Type = encode_type(Geometry),
+  PointType = encode_point_type(Geometry),
+  Data = encode_geometry_data(Geometry),
+  <<1, Type/binary, PointType/binary, Data/binary>>.
 
-format_geometry_data(#point{ point_type = '2d', x = X, y = Y }) ->
-  Xbin = format_float64(X),
-  Ybin = format_float64(Y),
+encode_geometry_data(#point{ point_type = '2d', x = X, y = Y }) ->
+  Xbin = encode_float64(X),
+  Ybin = encode_float64(Y),
   <<Xbin/binary, Ybin/binary>>;
-format_geometry_data(#point{ point_type = '2dm', x = X, y = Y, m = M }) ->
-  Xbin = format_float64(X),
-  Ybin = format_float64(Y),
-  Mbin = format_float64(M),
+encode_geometry_data(#point{ point_type = '2dm', x = X, y = Y, m = M }) ->
+  Xbin = encode_float64(X),
+  Ybin = encode_float64(Y),
+  Mbin = encode_float64(M),
   <<Xbin/binary, Ybin/binary, Mbin/binary>>;
-format_geometry_data(#point{ point_type = '3d', x = X, y = Y, z = Z }) ->
-  Xbin = format_float64(X),
-  Ybin = format_float64(Y),
-  Zbin = format_float64(Z),
+encode_geometry_data(#point{ point_type = '3d', x = X, y = Y, z = Z }) ->
+  Xbin = encode_float64(X),
+  Ybin = encode_float64(Y),
+  Zbin = encode_float64(Z),
   <<Xbin/binary, Ybin/binary, Zbin/binary>>;
-format_geometry_data(#point{ point_type = '3dm', x = X, y = Y, z = Z, m = M }) ->
-  Xbin = format_float64(X),
-  Ybin = format_float64(Y),
-  Zbin = format_float64(Z),
-  Mbin = format_float64(M),
+encode_geometry_data(#point{ point_type = '3dm', x = X, y = Y, z = Z, m = M }) ->
+  Xbin = encode_float64(X),
+  Ybin = encode_float64(Y),
+  Zbin = encode_float64(Z),
+  Mbin = encode_float64(M),
   <<Xbin/binary, Ybin/binary, Zbin/binary, Mbin/binary>>;
-format_geometry_data({SimpleCollection, _, Data})
+encode_geometry_data({SimpleCollection, _, Data})
     when SimpleCollection == line_string;
          SimpleCollection == circular_string;
          SimpleCollection == polygon;
          SimpleCollection == triangle ->
-  format_collection(Data);
-format_geometry_data({TypedCollection, _, Data})
+  encode_collection(Data);
+encode_geometry_data({TypedCollection, _, Data})
     when 
         TypedCollection == multi_point;
         TypedCollection == multi_line_string;
@@ -192,26 +192,26 @@ format_geometry_data({TypedCollection, _, Data})
         TypedCollection == geometry_collection;
         TypedCollection == polyhedral_surface;
         TypedCollection == tin ->
-  format_typed_collection(Data).
+  encode_typed_collection(Data).
 
-format_collection(Collection) when is_list(Collection) ->
+encode_collection(Collection) when is_list(Collection) ->
   Length = length(Collection),
-  LengthBin = format_int32(Length),
+  LengthBin = encode_int32(Length),
   CollectionBin = lists:foldl(
     fun(Element, Acc) ->
-      ElementBin = format_geometry_data(Element),
+      ElementBin = encode_geometry_data(Element),
       <<Acc/binary, ElementBin/binary>>
     end,
     <<>>,
     Collection),
   <<LengthBin/binary, CollectionBin/binary>>.
 
-format_typed_collection(Collection) when is_list(Collection) ->
+encode_typed_collection(Collection) when is_list(Collection) ->
   Length = length(Collection),
-  LengthBin = format_int32(Length),
+  LengthBin = encode_int32(Length),
   CollectionBin = lists:foldl(
     fun(Element, Acc) ->
-      ElementBin = format_geometry(Element),
+      ElementBin = encode_geometry(Element),
       <<Acc/binary, ElementBin/binary>>
     end,
     <<>>,
@@ -219,39 +219,37 @@ format_typed_collection(Collection) when is_list(Collection) ->
   <<LengthBin/binary, CollectionBin/binary>>.  
   
 
-format_int32(Int) when is_integer(Int) ->
-  Bin = <<Int:1/little-integer-unit:32>>,
-  bin_to_hex(Bin).
-
-format_float64(Int) when is_number(Int) ->
-  Bin = <<Int:1/little-float-unit:64>>,
-  bin_to_hex(Bin).
-
--spec parse_geometry_data(binary()) -> {geometry(), binary()}.
-parse_geometry_data(Binary) ->
-  <<"01", TypeCode:4/binary, SubtypeCode:4/binary, Data/binary>> = Binary,
-  Type = parse_type(TypeCode),
-  Subtype = parse_point_type(SubtypeCode),
-  parse_geometry_data(Type, Subtype, Data).
-
--spec parse_geometry_data(geom_type(), point_type(), binary()) -> {geometry(), binary()}.
-parse_geometry_data(curve, _, _) -> error({curve, not_supported});
-parse_geometry_data(surface, _, _) -> error({surface, not_supported});
-parse_geometry_data(geometry, _, _) -> error({geometry, not_supported});
-parse_geometry_data(point, PointType, Data) ->
-  parse_point(PointType, Data);
-parse_geometry_data(LineType, PointType, Data) 
+encode_int32(Int) when is_integer(Int) ->
+  <<Int:1/little-integer-unit:32>>.
+
+encode_float64(Int) when is_number(Int) ->
+  <<Int:1/little-float-unit:64>>.
+
+-spec decode_geometry_data(binary()) -> {geometry(), binary()}.
+decode_geometry_data(Binary) ->
+  <<1, TypeCode:2/binary, SubtypeCode:2/binary, Data/binary>> = Binary,
+  Type = decode_type(TypeCode),
+  Subtype = decode_point_type(SubtypeCode),
+  decode_geometry_data(Type, Subtype, Data).
+
+-spec decode_geometry_data(geom_type(), point_type(), binary()) -> {geometry(), binary()}.
+decode_geometry_data(curve, _, _) -> error({curve, not_supported});
+decode_geometry_data(surface, _, _) -> error({surface, not_supported});
+decode_geometry_data(geometry, _, _) -> error({geometry, not_supported});
+decode_geometry_data(point, PointType, Data) ->
+  decode_point(PointType, Data);
+decode_geometry_data(LineType, PointType, Data) 
     when LineType == line_string; 
          LineType == circular_string ->
-  {Points, Rest} = parse_collection(point, PointType, Data),
+  {Points, Rest} = decode_collection(point, PointType, Data),
   {{LineType, PointType, Points}, Rest};
-parse_geometry_data(polygon, PointType, Data) ->
-  {Lines, Rest} = parse_collection(line_string, PointType, Data),
+decode_geometry_data(polygon, PointType, Data) ->
+  {Lines, Rest} = decode_collection(line_string, PointType, Data),
   {#polygon{ point_type = PointType, rings = Lines }, Rest};
-parse_geometry_data(triangle, PointType, Data) ->
-  {#polygon{ rings = Rings }, Rest} = parse_geometry_data(polygon, PointType, Data),
+decode_geometry_data(triangle, PointType, Data) ->
+  {#polygon{ rings = Rings }, Rest} = decode_geometry_data(polygon, PointType, Data),
   {#triangle{ point_type = PointType, rings = Rings }, Rest};
-parse_geometry_data(Collection, PointType, Data)
+decode_geometry_data(Collection, PointType, Data)
     when 
         Collection == multi_point;
         Collection == multi_line_string;
@@ -263,46 +261,46 @@ parse_geometry_data(Collection, PointType, Data)
         Collection == geometry_collection;
         Collection == polyhedral_surface;
         Collection == tin  ->
-    {Lines, Rest} = parse_typed_collection(Data),
+    {Lines, Rest} = decode_typed_collection(Data),
     {{Collection, PointType, Lines}, Rest}.
 
--spec parse_collection(geom_type(), point_type(), binary()) -> {[geometry()], binary()}.
-parse_collection(Type, PointType, Data) ->
-  {Length, CountRest} = parse_int32(Data),
+-spec decode_collection(geom_type(), point_type(), binary()) -> {[geometry()], binary()}.
+decode_collection(Type, PointType, Data) ->
+  {Length, CountRest} = decode_int32(Data),
   lists:foldl(
     fun(_, {Geoms, Rest}) ->
-      {Geom, R} = parse_geometry_data(Type, PointType, Rest),
+      {Geom, R} = decode_geometry_data(Type, PointType, Rest),
       {Geoms ++ [Geom], R}
     end,
     {[], CountRest},
     lists:seq(1, Length)).
 
--spec parse_typed_collection(binary()) -> {[geometry()], binary()}.
-parse_typed_collection(Data) ->
-  {Length, CountRest} = parse_int32(Data),
+-spec decode_typed_collection(binary()) -> {[geometry()], binary()}.
+decode_typed_collection(Data) ->
+  {Length, CountRest} = decode_int32(Data),
   lists:foldl(
     fun(_, {Geoms, Rest}) ->
-      {Geom, R} = parse_geometry_data(Rest),
+      {Geom, R} = decode_geometry_data(Rest),
       {Geoms ++ [Geom], R}
     end,
     {[], CountRest},
     lists:seq(1, Length)).
 
 
--spec parse_int32(binary()) -> {integer(), binary()}.
-parse_int32(<<Hex:8/binary, Rest/binary>>) ->
-  <<Int:1/little-integer-unit:32>> = hex_to_bin(Hex),
+-spec decode_int32(binary()) -> {integer(), binary()}.
+decode_int32(<<Hex:4/binary, Rest/binary>>) ->
+  <<Int:1/little-integer-unit:32>> = Hex,
   {Int, Rest}.
 
--spec parse_float64(binary()) -> {float(), binary()}.
-parse_float64(<<Hex:16/binary, Rest/binary>>) ->
-  <<Float:1/little-float-unit:64>> = hex_to_bin(Hex),
+-spec decode_float64(binary()) -> {float(), binary()}.
+decode_float64(<<Hex:8/binary, Rest/binary>>) ->
+  <<Float:1/little-float-unit:64>> = Hex,
   {Float, Rest}.
 
-parse_point(PointType, Data) ->
+decode_point(PointType, Data) ->
   {Values, Rest} = lists:foldl(
     fun(_, {Values, Rest}) ->
-      {Value, R} = parse_float64(Rest),
+      {Value, R} = decode_float64(Rest),
       {Values ++ [Value], R}
     end,
     {[], Data},
@@ -325,62 +323,62 @@ point_size('2dm') -> 3;
 point_size('3d')  -> 3;
 point_size('3dm') -> 4.
 
--spec parse_type(binary()) -> geom_type().
-parse_type(<<"0000">>) -> geometry;
-parse_type(<<"0100">>) -> point;
-parse_type(<<"0200">>) -> line_string;
-parse_type(<<"0300">>) -> polygon;
-parse_type(<<"0400">>) -> multi_point;
-parse_type(<<"0500">>) -> multi_line_string;
-parse_type(<<"0600">>) -> multi_polygon;
-parse_type(<<"0700">>) -> geometry_collection;
-parse_type(<<"0800">>) -> circular_string;
-parse_type(<<"0900">>) -> compound_curve;
-parse_type(<<"0A00">>) -> curve_polygon;
-parse_type(<<"0B00">>) -> multi_curve;
-parse_type(<<"0C00">>) -> multi_surface;
-parse_type(<<"0D00">>) -> curve;
-parse_type(<<"0E00">>) -> surface;
-parse_type(<<"0F00">>) -> polyhedral_surface;
-parse_type(<<"1000">>) -> tin;
-parse_type(<<"1100">>) -> triangle.
-
--spec format_type(geometry() | geom_type()) -> binary().
-format_type(Geometry) when is_tuple(Geometry) ->
-  format_type(element(1, Geometry));
-format_type(geometry)            -> <<"0000">>;
-format_type(point)               -> <<"0100">>;
-format_type(line_string)         -> <<"0200">>;
-format_type(polygon)             -> <<"0300">>;
-format_type(multi_point)         -> <<"0400">>;
-format_type(multi_line_string)   -> <<"0500">>;
-format_type(multi_polygon)       -> <<"0600">>;
-format_type(geometry_collection) -> <<"0700">>;
-format_type(circular_string)     -> <<"0800">>;
-format_type(compound_curve)      -> <<"0900">>;
-format_type(curve_polygon)       -> <<"0A00">>;
-format_type(multi_curve)         -> <<"0B00">>;
-format_type(multi_surface)       -> <<"0C00">>;
-format_type(curve)               -> <<"0D00">>;
-format_type(surface)             -> <<"0E00">>;
-format_type(polyhedral_surface)  -> <<"0F00">>;
-format_type(tin)                 -> <<"1000">>;
-format_type(triangle)            -> <<"1100">>.
-
-
--spec parse_point_type(binary()) -> point_type().
-parse_point_type(<<"0000">>) -> '2d';
-parse_point_type(<<"0080">>) -> '3d';
-parse_point_type(<<"0040">>) -> '2dm';
-parse_point_type(<<"00c0">>) -> '3dm'.
-
--spec format_point_type(geometry() | point_type()) -> binary().
-format_point_type(Geometry) when is_tuple(Geometry) ->
-  format_point_type(element(2, Geometry));
-format_point_type('2d') -> <<"0000">>;
-format_point_type('3d') -> <<"0080">>;
-format_point_type('2dm') -> <<"0040">>;
-format_point_type('3dm') -> <<"00c0">>.
+-spec decode_type(binary()) -> geom_type().
+decode_type(<<0,0>>) -> geometry;
+decode_type(<<1,0>>) -> point;
+decode_type(<<2,0>>) -> line_string;
+decode_type(<<3,0>>) -> polygon;
+decode_type(<<4,0>>) -> multi_point;
+decode_type(<<5,0>>) -> multi_line_string;
+decode_type(<<6,0>>) -> multi_polygon;
+decode_type(<<7,0>>) -> geometry_collection;
+decode_type(<<8,0>>) -> circular_string;
+decode_type(<<9,0>>) -> compound_curve;
+decode_type(<<10,0>>) -> curve_polygon;
+decode_type(<<11,0>>) -> multi_curve;
+decode_type(<<12,0>>) -> multi_surface;
+decode_type(<<13,0>>) -> curve;
+decode_type(<<14,0>>) -> surface;
+decode_type(<<15,0>>) -> polyhedral_surface;
+decode_type(<<16,0>>) -> tin;
+decode_type(<<17,0>>) -> triangle.
+
+-spec encode_type(geometry() | geom_type()) -> binary().
+encode_type(Geometry) when is_tuple(Geometry) ->
+  encode_type(element(1, Geometry));
+encode_type(geometry)            -> <<00, 0>>;
+encode_type(point)               -> <<01, 0>>;
+encode_type(line_string)         -> <<02, 0>>;
+encode_type(polygon)             -> <<03, 0>>;
+encode_type(multi_point)         -> <<04, 0>>;
+encode_type(multi_line_string)   -> <<05, 0>>;
+encode_type(multi_polygon)       -> <<06, 0>>;
+encode_type(geometry_collection) -> <<07, 0>>;
+encode_type(circular_string)     -> <<08, 0>>;
+encode_type(compound_curve)      -> <<09, 0>>;
+encode_type(curve_polygon)       -> <<10, 0>>;
+encode_type(multi_curve)         -> <<11, 0>>;
+encode_type(multi_surface)       -> <<12, 0>>;
+encode_type(curve)               -> <<13, 0>>;
+encode_type(surface)             -> <<14, 0>>;
+encode_type(polyhedral_surface)  -> <<15, 0>>;
+encode_type(tin)                 -> <<16, 0>>;
+encode_type(triangle)            -> <<17, 0>>.
+
+
+-spec decode_point_type(binary()) -> point_type().
+decode_point_type(<<0,0>>) -> '2d';
+decode_point_type(<<0, 64>>) -> '2dm';
+decode_point_type(<<0, 128>>) -> '3d';
+decode_point_type(<<0, 192>>) -> '3dm'.
+
+-spec encode_point_type(geometry() | point_type()) -> binary().
+encode_point_type(Geometry) when is_tuple(Geometry) ->
+  encode_point_type(element(2, Geometry));
+encode_point_type('2d') -> <<0,0>>;
+encode_point_type('2dm') -> <<0,64>>;
+encode_point_type('3d') -> <<0,128>>;
+encode_point_type('3dm') -> <<0,192>>.
 
 hex_to_bin(<<C:2/binary>>) ->
   Int = binary_to_integer(C, 16),

+ 23 - 15
src/pgsql_binary.erl

@@ -31,6 +31,7 @@ encode(uuid, B) when is_binary(B)           -> encode_uuid(B);
 encode({array, char}, L) when is_list(L)    -> encode_array(bpchar, L);
 encode({array, Type}, L) when is_list(L)    -> encode_array(Type, L);
 encode(point, {X,Y})                        -> encode_point({X,Y});
+encode(geometry, Data)                      -> encode_geometry(Data);
 encode(Type, L) when is_list(L)             -> encode(Type, list_to_binary(L));
 encode(_Type, _Value)                       -> {error, unsupported}.
 
@@ -52,6 +53,7 @@ decode(interval = Type, B)                  -> ?datetime:decode(Type, B);
 decode(uuid, B)                             -> decode_uuid(B);
 decode({array, _Type}, B)                   -> decode_array(B);
 decode(point, B)                            -> decode_point(B);
+decode(geometry, B)                         -> ewkb:decode_geometry(B);
 decode(_Other, Bin)                         -> Bin.
 
 encode_array(Type, A) ->
@@ -126,21 +128,27 @@ encode_point({X, Y}) when is_number(X), is_number(Y) ->
 decode_point(<<X:1/big-float-unit:64, Y:1/big-float-unit:64>>) ->
     {X, Y}.
 
-supports(point)   -> true;
-supports(bool)    -> true;
-supports(bpchar)  -> true;
-supports(int2)    -> true;
-supports(int4)    -> true;
-supports(int8)    -> true;
-supports(float4)  -> true;
-supports(float8)  -> true;
-supports(bytea)   -> true;
-supports(text)    -> true;
-supports(varchar) -> true;
-supports(record)  -> true;
-supports(date)    -> true;
-supports(time)    -> true;
-supports(timetz)  -> true;
+encode_geometry(Data) ->
+    Bin = ewkb:encode_geometry(Data),
+    Size = byte_size(Bin),
+    <<Size:?int32, Bin/binary>>.
+
+supports(geometry) -> true;
+supports(point)    -> true;
+supports(bool)     -> true;
+supports(bpchar)   -> true;
+supports(int2)     -> true;
+supports(int4)     -> true;
+supports(int8)     -> true;
+supports(float4)   -> true;
+supports(float8)   -> true;
+supports(bytea)    -> true;
+supports(text)     -> true;
+supports(varchar)  -> true;
+supports(record)   -> true;
+supports(date)     -> true;
+supports(time)     -> true;
+supports(timetz)   -> true;
 supports(timestamp)   -> true;
 supports(timestamptz) -> true;
 supports(interval)    -> true;