Browse Source

Cleanup + docstrings

Сергей Прохоров 7 years ago
parent
commit
fac836e1b1
6 changed files with 69 additions and 249 deletions
  1. 1 1
      src/commands/epgsql_cmd_connect.erl
  2. 28 12
      src/epgsql_binary.erl
  3. 12 4
      src/epgsql_oid_db.erl
  4. 2 0
      src/epgsql_sock.erl
  5. 0 207
      src/epgsql_types.erl
  6. 26 25
      src/epgsql_wire.erl

+ 1 - 1
src/commands/epgsql_cmd_connect.erl

@@ -147,7 +147,7 @@ handle_message(?CANCELLATION_KEY, <<Pid:?int32, Key:?int32>>, Sock, _State) ->
 
 %% ReadyForQuery
 handle_message(?READY_FOR_QUERY, _, Sock, _State) ->
-    Codec = epgsql_binary:new_codec(epgsql_oid_db, Sock),
+    Codec = epgsql_binary:new_codec(Sock, []),
     Sock1 = epgsql_sock:set_attr(codec, Codec, Sock),
     {finish, connected, connected, Sock1};
 

+ 28 - 12
src/epgsql_binary.erl

@@ -1,5 +1,5 @@
 %%% Copyright (C) 2008 - Will Glozer.  All rights reserved.
-
+%% XXX: maybe merge this module into epgsql_codec?
 -module(epgsql_binary).
 
 -export([new_codec/2,
@@ -27,27 +27,31 @@
                       epgsql:type_name(),
                       epgsql_codec:state()}.
 
+-type type() :: epgsql:type_name() | {array, epgsql:type_name()}.
+-type maybe_unknown_type() :: type() | {unknown_oid, epgsql_oid_db:oid()}.
 
 -define(RECORD_OID, 2249).
 -define(RECORD_ARRAY_OID, 2287).
 
--spec new_codec(module(), epgsql_sock:pg_sock()) -> codec().
-new_codec(OidDb, PgSock) ->
+%% Codec is used to convert data (result rows and query parameters) between Erlang and postgresql formats
+%% It uses mappings between OID, type names and `epgsql_codec_*' modules (epgsql_oid_db)
+
+-spec new_codec(epgsql_sock:pg_sock(), list()) -> codec().
+new_codec(PgSock, Opts) ->
     Codecs = default_codecs(),
     Oids = default_oids(),
-    new_codec(OidDb, PgSock, Codecs, Oids).
+    new_codec(PgSock, Codecs, Oids, Opts).
 
-new_codec(OidDb, PgSock, Codecs, Oids) ->
+new_codec(PgSock, Codecs, Oids, Opts) ->
     CodecEntries = epgsql_codec:init_mods(Codecs, PgSock),
-    Types = OidDb:join_codecs_oids(Oids, CodecEntries),
-    #codec{oid_db = epgsql_oid_db:from_list(Types)}.
+    Types = epgsql_oid_db:join_codecs_oids(Oids, CodecEntries),
+    #codec{oid_db = epgsql_oid_db:from_list(Types), opts = Opts}.
 
 -spec update_codec([epgsql_oid_db:type_info()], codec()) -> codec().
 update_codec(TypeInfos, #codec{oid_db = Db} = Codec) ->
     Codec#codec{oid_db = epgsql_oid_db:update(TypeInfos, Db)}.
 
--spec oid_to_name(epgsql_oid_db:oid(), codec()) -> Type | {unknown_oid, epgsql_oid_db:oid()} when
-      Type :: epgsql:type_name() | {array, epgsql:type_name()}.
+-spec oid_to_name(epgsql_oid_db:oid(), codec()) -> maybe_unknown_type().
 oid_to_name(Oid, Codec) ->
     case oid_to_info(Oid, Codec) of
         undefined ->
@@ -59,6 +63,7 @@ oid_to_name(Oid, Codec) ->
             end
     end.
 
+-spec type_to_oid(type(), codec()) -> epgsql_oid_db:oid().
 type_to_oid({array, Name}, Codec) ->
     type_to_oid(Name, true, Codec);
 type_to_oid(Name, Codec) ->
@@ -68,9 +73,10 @@ type_to_oid(Name, Codec) ->
 type_to_oid(TypeName, IsArray, #codec{oid_db = Db}) ->
     epgsql_oid_db:oid_by_name(TypeName, IsArray, Db).
 
-type_to_oid_info({array, Name}, Codec) ->
+-spec type_to_type_info(type(), codec()) -> epgsql_oid_db:type_info() | undefined.
+type_to_type_info({array, Name}, Codec) ->
     type_to_info(Name, true, Codec);
-type_to_oid_info(Name, Codec) ->
+type_to_type_info(Name, Codec) ->
     type_to_info(Name, false, Codec).
 
 -spec oid_to_info(epgsql_oid_db:oid(), codec()) -> epgsql_oid_db:type_info() | undefined.
@@ -81,6 +87,8 @@ oid_to_info(Oid, #codec{oid_db = Db}) ->
 type_to_info(TypeName, IsArray, #codec{oid_db = Db}) ->
     epgsql_oid_db:find_by_name(TypeName, IsArray, Db).
 
+-spec typeinfo_to_name_array(Unknown | epgsql_oid_db:type_info(), _) -> Unknown | type() when
+      Unknown :: {unknown_oid, epgsql_oid_db:oid()}.
 typeinfo_to_name_array({unknown_oid, _} = Unknown, _) -> Unknown;
 typeinfo_to_name_array(TypeInfo, _) ->
     case epgsql_oid_db:type_to_oid_info(TypeInfo) of
@@ -88,6 +96,9 @@ typeinfo_to_name_array(TypeInfo, _) ->
         {_, Name, true} -> {array, Name}
     end.
 
+-spec typeinfo_to_oid_info(Unknown | epgsql_oid_db:type_info(), _) ->
+                                  Unknown | epgsql_oid_db:oid_info() when
+      Unknown :: {unknown_oid, epgsql_oid_db:oid()}.
 typeinfo_to_oid_info({unknown_oid, _} = Unknown, _) -> Unknown;
 typeinfo_to_oid_info(TypeInfo, _) ->
     epgsql_oid_db:type_to_oid_info(TypeInfo).
@@ -96,10 +107,12 @@ typeinfo_to_oid_info(TypeInfo, _) ->
 %% Decode
 %%
 
+%% @doc decode single cell
 -spec decode(binary(), decoder()) -> any().
 decode(Bin, {Fun, TypeName, State}) ->
     Fun(Bin, TypeName, State).
 
+%% @doc generate decoder to decode PG binary of datatype specified as OID
 -spec oid_to_decoder(epgsql_oid_db:oid(), binary | text, codec()) -> decoder().
 oid_to_decoder(?RECORD_OID, binary, Codec) ->
     {fun ?MODULE:decode_record/3, record, Codec};
@@ -201,9 +214,11 @@ decode_record1(<<Oid:?int32, Len:?int32, ValueBin:Len/binary, Rest/binary>>, Siz
 %%
 %% Encode
 %%
+
+%% Convert erlang value to PG binary of type, specified by type name
 -spec encode(epgsql:type_name() | {array, epgsql:type_name()}, any(), codec()) -> iolist().
 encode(TypeName, Value, Codec) ->
-    Type = type_to_oid_info(TypeName, Codec),
+    Type = type_to_type_info(TypeName, Codec),
     encode_with_type(Type, Value).
 
 encode_with_type(Type, Value) ->
@@ -251,6 +266,7 @@ supports(Oid, #codec{oid_db = Db}) ->
     epgsql_oid_db:find_by_oid(Oid, Db) =/= undefined.
 
 %% Default codec set
+%% XXX: maybe move to application env?
 -spec default_codecs() -> [epgsql_codec:codec_entry()].
 default_codecs() ->
     [{epgsql_codec_boolean,[]},

+ 12 - 4
src/epgsql_oid_db.erl

@@ -51,7 +51,7 @@ build_query(TypeNames) ->
        "FROM pg_type "
        "WHERE typname IN (">>, Types, <<") ORDER BY typname">>].
 
-%% Parse result of `squery(build_query(...))'
+%% @doc Parse result of `squery(build_query(...))'
 -spec parse_rows(ordsets:ordset({binary(), binary(), binary()})) ->
                         ordsets:ordset(oid_entry()).
 parse_rows(Rows) ->
@@ -60,7 +60,7 @@ parse_rows(Rows) ->
       binary_to_integer(ArrayOid)}
      || {TypeName, Oid, ArrayOid} <- Rows].
 
-%% Build list of #type{}'s by merging oid and codec lists by type name.
+%% @doc Build list of #type{}'s by merging oid and codec lists by type name.
 -spec join_codecs_oids(ordsets:ordset(oid_entry()),
                        ordsets:ordset(epgsql_codec:codec_entry())) -> [type_info()].
 join_codecs_oids(Oids, Codecs) ->
@@ -99,6 +99,8 @@ from_list(Types) ->
 to_list(#oid_db{by_oid = Dict}) ->
     [Type || {_Oid, Type} <- kv_to_list(Dict)].
 
+%% @doc update DB adding new type definitions.
+%% If some of type definitions already exist, old ones will be overwritten by new ones
 -spec update([type_info()], db()) -> db().
 update(Types, #oid_db{by_oid = OldByOid, by_name = OldByName} = Store) ->
     #oid_db{by_oid = NewByOid, by_name = NewByName} = from_list(Types),
@@ -107,35 +109,41 @@ update(Types, #oid_db{by_oid = OldByOid, by_name = OldByName} = Store) ->
     Store#oid_db{by_oid = ByOid,
                  by_name = ByName}.
 
+%% @doc find type by OID
 -spec find_by_oid(oid(), db()) -> type_info() | undefined.
 %% find_by_oid(?RECORD_OID, _) ->
 %%     '$record';
 find_by_oid(Oid, #oid_db{by_oid = Dict}) ->
     kv_get(Oid, Dict, undefined).
 
+%% @doc find type by type name
 -spec find_by_name(epgsql:type_name(), boolean(), db()) -> type_info().
 find_by_name(Name, IsArray, #oid_db{by_oid = ByOid} = Db) ->
     Oid = oid_by_name(Name, IsArray, Db),
     kv_get(Oid, ByOid).                  % or maybe find_by_oid(Oid, Store)
 
+%% @doc lookup OID by type name. May fall
 -spec oid_by_name(epgsql:type_name(), boolean(), db()) -> oid().
 oid_by_name(Name, IsArray, #oid_db{by_name = ByName}) ->
     kv_get({Name, IsArray}, ByName).
 
+%% @doc convert type to codec_entry()
 -spec type_to_codec_entry(type_info()) -> epgsql_codec:codec_entry().
 type_to_codec_entry(#type{name = Name, codec = Codec, codec_state = State}) ->
     {Name, Codec, State}.
 
+%% @doc Convert type tp oid_info()
 -spec type_to_oid_info(type_info()) -> oid_info().
 type_to_oid_info(#type{name = Name, is_array = IsArray, oid = Oid}) ->
     {Oid, Name, IsArray}.
 
+%% @doc For array types return its element's OID
 -spec type_to_element_oid(type_info()) -> oid() | undefined.
-type_to_element_oid(#type{array_element_oid = ElementOid}) ->
+type_to_element_oid(#type{array_element_oid = ElementOid, is_array = true}) ->
     ElementOid.
 
 %% Internal
-
+%% TODO: replace by Erlang >=19 lists:join/2
 join(_Sep, []) -> [];
 join(Sep, [H | T]) -> [H | join_prepend(Sep, T)].
 

+ 2 - 0
src/epgsql_sock.erl

@@ -340,6 +340,8 @@ setopts(#state{mod = Mod, sock = Sock}, Opts) ->
         ssl     -> ssl:setopts(Sock, Opts)
     end.
 
+%% This one only used in connection initiation to send client's
+%% `StartupMessage' and `SSLRequest' packets
 -spec send(pg_sock(), iodata()) -> ok | {error, any()}.
 send(#state{mod = Mod, sock = Sock}, Data) ->
     do_send(Mod, Sock, epgsql_wire:encode(Data)).

+ 0 - 207
src/epgsql_types.erl

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

+ 26 - 25
src/epgsql_wire.erl

@@ -37,18 +37,18 @@ decode_message(<<Type:8, Len:?int32, Rest/binary>> = Bin) ->
 decode_message(Bin) ->
     Bin.
 
-%% decode a single null-terminated string
+%% @doc decode a single null-terminated string
 -spec decode_string(binary()) -> [binary(), ...].
 decode_string(Bin) ->
     binary:split(Bin, <<0>>).
 
-%% decode multiple null-terminated string
+%% @doc decode multiple null-terminated string
 -spec decode_strings(binary()) -> [binary(), ...].
 decode_strings(Bin) ->
     [<<>> | T] = lists:reverse(binary:split(Bin, <<0>>, [global])),
     lists:reverse(T).
 
-%% decode field
+%% @doc decode error's field
 -spec decode_fields(binary()) -> [{byte(), binary()}].
 decode_fields(Bin) ->
     decode_fields(Bin, []).
@@ -59,7 +59,7 @@ decode_fields(<<Type:8, Rest/binary>>, Acc) ->
     [Str, Rest2] = decode_string(Rest),
     decode_fields(Rest2, [{Type, Str} | Acc]).
 
-%% decode ErrorResponse
+%% @doc decode ErrorResponse
 %% See http://www.postgresql.org/docs/current/interactive/protocol-error-fields.html
 -spec decode_error(binary()) -> #error{}.
 decode_error(Bin) ->
@@ -118,7 +118,7 @@ lower_atom(Str) when is_list(Str) ->
     list_to_atom(string:to_lower(Str)).
 
 
-%% Build decoder for DataRow
+%% @doc Build decoder for DataRow
 -spec build_decoder([epgsql:column()], epgsql_binary:codec()) -> row_decoder().
 build_decoder(Columns, Codec) ->
     Decoders = lists:map(
@@ -131,7 +131,7 @@ build_decoder(Columns, Codec) ->
                  end, Columns),
     {Decoders, Columns, Codec}.
 
-%% decode row data
+%% @doc decode row data
 -spec decode_data(binary(), row_decoder()) -> tuple().
 decode_data(Bin, {Decoders, Columns, Codec}) ->
     list_to_tuple(decode_data(Bin, Decoders, Columns, Codec)).
@@ -143,7 +143,7 @@ decode_data(<<Len:?int32, Value:Len/binary, Rest/binary>>, [Decoder | Decs], [_C
     [epgsql_binary:decode(Value, Decoder)
      | decode_data(Rest, Decs, Cols, Codec)].
 
-%% decode column information
+%% @doc decode column information
 -spec decode_columns(non_neg_integer(), binary(), epgsql_binary:codec()) -> [#column{}].
 decode_columns(0, _Bin, _Codec) -> [];
 decode_columns(Count, Bin, Codec) ->
@@ -161,7 +161,7 @@ decode_columns(Count, Bin, Codec) ->
       format   = Format},
     [Desc | decode_columns(Count - 1, Rest2, Codec)].
 
-%% decode ParameterDescription
+%% @doc decode ParameterDescription
 -spec decode_parameters(binary(), epgsql_binary:codec()) ->
                                [epgsql_oid_db:type_info() | {unknown_oid, epgsql_oid_db:oid()}].
 decode_parameters(<<_Count:?int16, Bin/binary>>, Codec) ->
@@ -170,7 +170,7 @@ decode_parameters(<<_Count:?int16, Bin/binary>>, Codec) ->
          TypeInfo -> TypeInfo
      end || <<Oid:?int32>> <= Bin].
 
-%% decode command complete msg
+%% @doc decode command complete msg
 decode_complete(<<"SELECT", 0>>)        -> select;
 decode_complete(<<"SELECT", _/binary>>) -> select;
 decode_complete(<<"BEGIN", 0>>)         -> 'begin';
@@ -187,7 +187,7 @@ decode_complete(Bin) ->
     end.
 
 
-%% encode types
+%% @doc encode types
 encode_types(Types, Codec) ->
     encode_types(Types, 0, <<>>, Codec).
 
@@ -201,7 +201,7 @@ encode_types([Type | T], Count, Acc, Codec) ->
     end,
     encode_types(T, Count + 1, <<Acc/binary, Oid:?int32>>, Codec).
 
-%% encode expected column formats
+%% @doc encode expected column formats
 -spec encode_formats([#column{}]) -> binary().
 encode_formats(Columns) ->
     encode_formats(Columns, 0, <<>>).
@@ -219,7 +219,7 @@ format(#column{oid = Oid}, Codec) ->
         false -> 0                              %text
     end.
 
-%% encode parameters for 'Bind'
+%% @doc encode parameters for 'Bind'
 -spec encode_parameters([], epgsql_binary:codec()) -> iolist().
 encode_parameters(Parameters, Codec) ->
     encode_parameters(Parameters, 0, <<>>, [], Codec).
@@ -233,8 +233,7 @@ encode_parameters([P | T], Count, Formats, Values, Codec) ->
     Values2 = [Value | Values],
     encode_parameters(T, Count + 1, Formats2, Values2, Codec).
 
-%% encode parameter
-
+%% @doc encode single 'typed' parameter
 -spec encode_parameter({Type, Val :: any()},
                        epgsql_binary:codec()) -> {0..1, iolist()} when
       Type :: epgsql:type_name()
@@ -245,30 +244,32 @@ encode_parameter({T, undefined}, Codec) ->
 encode_parameter({_, null}, _Codec) ->
     {1, <<-1:?int32>>};
 encode_parameter({{unknown_oid, _Oid}, Value}, _Codec) ->
-    encode_text(Value);
+    {0, encode_text(Value)};
 encode_parameter({Type, Value}, Codec) ->
     {1, epgsql_binary:encode(Type, Value, Codec)};
-encode_parameter(Value, _Codec) -> encode_text(Value).
+encode_parameter(Value, _Codec) ->
+    {0, encode_text(Value)}.
 
-encode_text(B) when is_binary(B)  -> {0, encode_bin(B)};
-encode_text(A) when is_atom(A)    -> {0, encode_bin(atom_to_binary(A, utf8))};
-encode_text(I) when is_integer(I) -> {0, encode_bin(integer_to_binary(I))};
-encode_text(F) when is_float(F)   -> {0, encode_bin(float_to_binary(F))};
-encode_text(L) when is_list(L)    -> {0, encode_bin(list_to_binary(L))}.
+encode_text(B) when is_binary(B)  -> encode_bin(B);
+encode_text(A) when is_atom(A)    -> encode_bin(atom_to_binary(A, utf8));
+encode_text(I) when is_integer(I) -> encode_bin(integer_to_binary(I));
+encode_text(F) when is_float(F)   -> encode_bin(float_to_binary(F));
+encode_text(L) when is_list(L)    -> encode_bin(list_to_binary(L)).
 
+encode_bin(Bin) ->
+    <<(byte_size(Bin)):?int32, Bin/binary>>.
 
+%% @doc Encode iodata with size-prefix (used for `StartupMessage' and `SSLRequest' packets)
 encode(Data) ->
     Size = iolist_size(Data),
     [<<(Size + 4):?int32>> | Data].
 
+%% @doc Encode PG command with type and size prefix
 encode(Type, Data) ->
     Size = iolist_size(Data),
     [<<Type:8, (Size + 4):?int32>> | Data].
 
-
-encode_bin(Bin) ->
-    <<(byte_size(Bin)):?int32, Bin/binary>>.
-
+%% @doc encode replication status message
 encode_standby_status_update(ReceivedLSN, FlushedLSN, AppliedLSN) ->
     {MegaSecs, Secs, MicroSecs} = os:timestamp(),
     Timestamp = ((MegaSecs * 1000000 + Secs) * 1000000 + MicroSecs) - 946684800*1000000, %% microseconds since midnight on 2000-01-01