Browse Source

Fix dialyzer errors. #109

Сергей Прохоров 7 years ago
parent
commit
566060dc00

+ 2 - 6
include/epgsql.hrl

@@ -1,10 +1,6 @@
--type epgsql_type() :: epgsql:type_name()
-                      | {array, epgsql:type_name()}
-                      | {unknown_oid, integer()}.
-
 -record(column, {
     name :: binary(),
-    type :: epgsql_type(),
+    type :: epgsql:epgsql_type(),
     oid :: integer(),
     size :: -1 | pos_integer(),
     modifier :: -1 | pos_integer(),
@@ -14,7 +10,7 @@
 -record(statement, {
     name :: string(),
     columns :: [#column{}],
-    types :: [epgsql_type()],
+    types :: [epgsql:epgsql_type()],
     parameter_info :: [epgsql_oid_db:oid_entry()]
 }).
 

+ 7 - 10
src/commands/epgsql_cmd_connect.erl

@@ -5,13 +5,15 @@
 -module(epgsql_cmd_connect).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).
--export_type([response/0]).
+-export_type([response/0, connect_error/0]).
 
 -type response() :: connected
-                  | {error,
-                     invalid_authorization_specification
-                     | invalid_password
-                     | epgsql:query_error()}.
+                  | {error, connect_error()}.
+-type connect_error() ::
+        invalid_authorization_specification
+      | invalid_password
+      | {unsupported_auth_method, integer()}
+      | epgsql:query_error().
 
 -include("epgsql.hrl").
 -include("protocol.hrl").
@@ -145,11 +147,6 @@ handle_message(?CANCELLATION_KEY, <<Pid:?int32, Key:?int32>>, Sock, _State) ->
 
 %% ReadyForQuery
 handle_message(?READY_FOR_QUERY, _, Sock, _State) ->
-    %% TODO decode dates to now() format
-    case epgsql_sock:get_parameter_internal(<<"integer_datetimes">>, Sock) of
-        <<"on">>  -> put(datetime_mod, epgsql_idatetime);
-        <<"off">> -> put(datetime_mod, epgsql_fdatetime)
-    end,
     Codec = epgsql_binary:new_codec(epgsql_oid_db, Sock),
     Sock1 = epgsql_sock:set_attr(codec, Codec, Sock),
     {finish, connected, connected, Sock1};

+ 6 - 2
src/commands/epgsql_cmd_describe_statement.erl

@@ -49,8 +49,12 @@ handle_message(?ROW_DESCRIPTION, <<Count:?int16, Bin/binary>>, Sock,
                              parameter_info = Params,
                              columns = Columns2}},
     {finish, Result, {columns, Columns2}, Sock};
-handle_message(?NO_DATA, <<>>, Sock, #desc_stmt{name = Name, parameter_descr = Params}) ->
-    Result = {ok, #statement{name = Name, types = Params, columns = []}},
+handle_message(?NO_DATA, <<>>, Sock, #desc_stmt{name = Name, parameter_descr = Params,
+                                                parameter_typenames = TypeNames}) ->
+    Result = {ok, #statement{name = Name,
+                             types = TypeNames,
+                             parameter_info = Params,
+                             columns = []}},
     {finish, Result, no_data, Sock};
 handle_message(?ERROR, Error, _Sock, _State) ->
     Result = {error, Error},

+ 1 - 1
src/commands/epgsql_cmd_execute.erl

@@ -8,7 +8,7 @@
 
 -type response() :: {ok, Count :: non_neg_integer(), Rows :: [tuple()]}
                   | {ok, Count :: non_neg_integer()}
-                  | {ok, Rows :: [tuple()]}
+                  | {ok | partial, Rows :: [tuple()]}
                   | {error, epgsql:query_error()}.
 
 -include("epgsql.hrl").

+ 2 - 2
src/commands/epgsql_cmd_update_type_cache.erl

@@ -12,8 +12,8 @@
 
 -record(upd,
         {codecs :: [{epgsql_codec:codec_mod(), Opts :: any()}],
-         codec_entries :: [epgsql_codec:codec_entry()],
-         decoder}).
+         codec_entries :: [epgsql_codec:codec_entry()] | undefined,
+         decoder :: epgsql_wire:row_decoder() | undefined}).
 
 init(Codecs) ->
     #upd{codecs = Codecs}.

+ 1 - 0
src/datatypes/epgsql_codec_hstore.erl

@@ -30,6 +30,7 @@ init(_, _) -> [].
 names() ->
     [hstore].
 
+-dialyzer([{nowarn_function, [encode/3]}, no_improper_lists]).
 encode({Hstore}, hstore, _) when is_list(Hstore) ->
     Size = length(Hstore),
     Body = [[encode_key(K) | encode_value(V)]

+ 41 - 60
src/epgsql.erl

@@ -31,7 +31,7 @@
 
 -export_type([connection/0, connect_option/0, connect_opts/0,
               connect_error/0, query_error/0, sql_query/0, column/0,
-              type_name/0]).
+              type_name/0, epgsql_type/0]).
 
 %% Deprecated types
 -export_type([bind_param/0, typed_param/0,
@@ -72,48 +72,25 @@
 -type connect_opts() :: [connect_option()].
 -endif.
 
--type connect_error() ::
-        #error{}
-      | {unsupported_auth_method, atom()}
-      | invalid_authorization_specification
-      | invalid_password.
+-type connect_error() :: epgsql_cmd_connect:connect_error().
 -type query_error() :: #error{}.
 
 
 -type type_name() :: atom().
+-type epgsql_type() :: type_name()
+                     | {array, type_name()}
+                     | {unknown_oid, integer()}.
 
+%% Deprecated
+-type pg_date() :: epgsql_codec_datetime:pg_date().
+-type pg_time() :: epgsql_codec_datetime:pg_time().
+-type pg_datetime() :: epgsql_codec_datetime:pg_datetime().
+-type pg_interval() :: epgsql_codec_datetime:pg_interval().
 
+%% Deprecated
+-type bind_param() :: any().
 
-
-
-%% Ranges are from https://www.postgresql.org/docs/current/static/datatype-datetime.html
--type pg_date() ::
-        {Year :: -4712..294276,
-         Month :: 1..12,
-         Day :: 1..31}.
--type pg_time() ::
-        {Hour :: 0..24,  % Max value is 24:00:00
-         Minute :: 0..59,
-         Second :: 0..59 | float()}.
--type pg_datetime() :: {pg_date(), pg_time()}.
--type pg_interval() :: {pg_time(), Days :: integer(), Months :: integer()}.
-
--type bind_param() ::
-        null
-        | boolean()
-        | string()
-        | binary()
-        | integer()
-        | float()
-        | pg_date()
-        | pg_time()
-        | pg_datetime()
-        | pg_interval()
-        | {list({binary(), binary() | null})}   % hstore
-        | [bind_param()].                       %array (maybe nested)
-
--type typed_param() ::
-    {epgsql_type(), bind_param()}.
+-type typed_param() :: {epgsql_type(), bind_param()}.
 
 -type column() :: #column{}.
 -type squery_row() :: tuple(). % tuple of binary().
@@ -121,7 +98,7 @@
 -type ok_reply(RowType) ::
     {ok, ColumnsDescription :: [column()], RowsValues :: [RowType]} |                            % select
     {ok, Count :: non_neg_integer()} |                                                            % update/insert/delete
-    {ok, Count :: non_neg_integer(), ColumnsDescription :: [#column{}], RowsValues :: [RowType]}. % update/insert/delete + returning
+    {ok, Count :: non_neg_integer(), ColumnsDescription :: [column()], RowsValues :: [RowType]}. % update/insert/delete + returning
 -type error_reply() :: {error, query_error()}.
 -type reply(RowType) :: ok_reply(RowType) | error_reply().
 -type lsn() :: integer().
@@ -181,23 +158,22 @@ connect(C, Host, Username, Password, Opts0) ->
             Error
     end.
 
--spec update_type_cache(connection()) -> ok.
 update_type_cache(C) ->
     update_type_cache(C, [{epgsql_codec_hstore, []},
                           {epgsql_codec_postgis, []}]).
 
 -spec update_type_cache(connection(), [{epgsql_codec:codec_mod(), Opts :: any()}]) ->
-                               {ok, [type_name()]} | {error, empty} | {error, query_error()}.
+                               epgsql_cmd_update_type_cache:response() | {error, empty}.
 update_type_cache(_C, []) ->
     {error, empty};
 update_type_cache(C, Codecs) ->
     %% {error, #error{severity = error,
-    %%                message = <<"column \"typarray\" does not exist in pg_type">>, _}}
+    %%                message = <<"column \"typarray\" does not exist in pg_type">>}}
     %% Do not fail connect if pg_type table in not in the expected
     %% format. Known to happen for Redshift which is based on PG v8.0.2
     epgsql_sock:sync_command(C, epgsql_cmd_update_type_cache, Codecs).
 
-
+%% @doc close connection
 -spec close(connection()) -> ok.
 close(C) ->
     epgsql_sock:close(C).
@@ -221,7 +197,7 @@ set_notice_receiver(C, PidOrName) ->
 get_cmd_status(C) ->
     epgsql_sock:get_cmd_status(C).
 
--spec squery(connection(), sql_query()) -> reply(squery_row()) | [reply(squery_row())].
+-spec squery(connection(), sql_query()) -> epgsql_cmd_squery:response().
 %% @doc runs simple `SqlQuery' via given `Connection'
 squery(Connection, SqlQuery) ->
     epgsql_sock:sync_command(Connection, epgsql_cmd_squery, SqlQuery).
@@ -239,17 +215,19 @@ equery(C, Sql, Parameters) ->
             Error
     end.
 
--spec equery(connection(), string(), sql_query(), [bind_param()]) -> reply(equery_row()).
+-spec equery(connection(), string(), sql_query(), [bind_param()]) ->
+                    epgsql_cmd_equery:response().
 equery(C, Name, Sql, Parameters) ->
     case parse(C, Name, Sql, []) of
         {ok, #statement{types = Types} = S} ->
-            Typed_Parameters = lists:zip(Types, Parameters),
-            epgsql_sock:sync_command(C, epgsql_cmd_equery, {S, Typed_Parameters});
+            TypedParameters = lists:zip(Types, Parameters),
+            epgsql_sock:sync_command(C, epgsql_cmd_equery, {S, TypedParameters});
         Error ->
             Error
     end.
 
--spec prepared_query(C::connection(), Name::string(), Parameters::[bind_param()]) -> reply(equery_row()).
+-spec prepared_query(C::connection(), Name::string(), Parameters::[bind_param()]) ->
+                            epgsql_cmd_prepared_query:response().
 prepared_query(C, Name, Parameters) ->
     case describe(C, statement, Name) of
         {ok, #statement{types = Types} = S} ->
@@ -269,7 +247,7 @@ parse(C, Sql, Types) ->
     parse(C, "", Sql, Types).
 
 -spec parse(connection(), iolist(), sql_query(), [epgsql_type()]) ->
-                   {ok, #statement{}} | {error, query_error()}.
+                   epgsql_cmd_parse:response().
 parse(C, Name, Sql, Types) ->
     sync_on_error(
       C, epgsql_sock:sync_command(
@@ -281,7 +259,7 @@ bind(C, Statement, Parameters) ->
     bind(C, Statement, "", Parameters).
 
 -spec bind(connection(), #statement{}, string(), [bind_param()]) ->
-                  ok | {error, query_error()}.
+                  epgsql_cmd_bind:response().
 bind(C, Statement, PortalName, Parameters) ->
     sync_on_error(
       C,
@@ -296,41 +274,43 @@ execute(C, S) ->
 execute(C, S, N) ->
     execute(C, S, "", N).
 
--spec execute(connection(), #statement{}, string(), non_neg_integer()) -> Reply
-                                                                              when
-      Reply :: {ok | partial, [equery_row()]}
-             | {ok, non_neg_integer()}
-             | {ok, non_neg_integer(), [equery_row()]}
-             | {error, query_error()}.
+-spec execute(connection(), #statement{}, string(), non_neg_integer()) -> Reply when
+      Reply :: epgsql_cmd_execute:response().
 execute(C, S, PortalName, N) ->
     epgsql_sock:sync_command(C, epgsql_cmd_execute, {S, PortalName, N}).
 
--spec execute_batch(connection(), [{#statement{}, [bind_param()]}]) -> [reply(equery_row())].
+-spec execute_batch(connection(), [{#statement{}, [bind_param()]}]) ->
+                           epgsql_cmd_batch:response().
 execute_batch(C, Batch) ->
     epgsql_sock:sync_command(C, epgsql_cmd_batch, Batch).
 
 %% statement/portal functions
-
+-spec describe(connection(), #statement{}) -> epgsql_cmd_describe_statement:response().
 describe(C, #statement{name = Name}) ->
     describe(C, statement, Name).
 
+-spec describe(connection(), portal, iodata()) -> epgsql_cmd_describe_portal:response();
+              (connection(), statement, iodata()) -> epgsql_cmd_describe_statement:response().
 describe(C, statement, Name) ->
     sync_on_error(
       C, epgsql_sock:sync_command(
            C, epgsql_cmd_describe_statement, Name));
 
-%% TODO unknown result format of Describe portal
 describe(C, portal, Name) ->
     sync_on_error(
       C, epgsql_sock:sync_command(
            C, epgsql_cmd_describe_portal, Name)).
 
+%% @doc close statement
+-spec close(connection(), #statement{}) -> epgsql_cmd_close:response().
 close(C, #statement{name = Name}) ->
     close(C, statement, Name).
 
+-spec close(connection(), statement | portal, iodata()) -> epgsql_cmd_close:response().
 close(C, Type, Name) ->
     epgsql_sock:sync_command(C, epgsql_cmd_close, {Type, Name}).
 
+-spec sync(connection()) -> epgsql_cmd_sync:response().
 sync(C) ->
     epgsql_sock:sync_command(C, epgsql_cmd_sync, []).
 
@@ -400,13 +380,14 @@ sync_on_error(C, Error = {error, _}) ->
 sync_on_error(_C, R) ->
     R.
 
--spec standby_status_update(connection(), lsn(), lsn()) -> ok | error_reply().
+-spec standby_status_update(connection(), lsn(), lsn()) -> ok.
 %% @doc sends last flushed and applied WAL positions to the server in a standby status update message via given `Connection'
 standby_status_update(Connection, FlushedLSN, AppliedLSN) ->
     gen_server:call(Connection, {standby_status_update, FlushedLSN, AppliedLSN}).
 
--spec start_replication(connection(), string(), Callback, cb_state(), string(), string()) -> ok | error_reply() when
-    Callback :: module() | pid().
+-spec start_replication(connection(), string(), Callback, cb_state(), string(), string()) -> Response when
+      Response :: epgsql_cmd_start_replication:response(),
+      Callback :: module() | pid().
 %% @doc instructs Postgres server to start streaming WAL for logical replication
 %% where
 %% `Connection'      - connection in replication mode

+ 4 - 8
src/epgsql_binary.erl

@@ -68,7 +68,7 @@ type_to_oid_info({array, Name}, Codec) ->
 type_to_oid_info(Name, Codec) ->
     type_to_info(Name, false, Codec).
 
--spec oid_to_info(epgsql_oid_db:oid(), codec()) -> epgsql_oid_db:type_info().
+-spec oid_to_info(epgsql_oid_db:oid(), codec()) -> epgsql_oid_db:type_info() | undefined.
 oid_to_info(Oid, {OidDb, Db}) ->
     OidDb:find_by_oid(Oid, Db).
 
@@ -196,14 +196,10 @@ decode_record1(<<Oid:?int32, Len:?int32, ValueBin:Len/binary, Rest/binary>>, Siz
 %%
 %% Encode
 %%
--spec encode(epgsql:type_name() | {array, epgsql:type_name()}, any(), codec()) ->
-                    {error, unsupported} | iolist().
+-spec encode(epgsql:type_name() | {array, epgsql:type_name()}, any(), codec()) -> iolist().
 encode(TypeName, Value, {OidDb, _Db} = Codec) ->
-    case type_to_oid_info(TypeName, Codec) of
-        undefined -> {error, unsupported};
-        Type ->
-            encode_with_type(Type, Value, OidDb)
-    end.
+    Type = type_to_oid_info(TypeName, Codec),
+    encode_with_type(Type, Value, OidDb).
 
 encode_with_type(Type, Value, OidDb) ->
     {Name, Mod, State} = OidDb:type_to_codec_entry(Type),

+ 10 - 11
src/epgsql_oid_db.erl

@@ -16,7 +16,7 @@
         {oid :: oid(),
          name :: epgsql:type_name(),
          is_array :: boolean(),
-         array_element_oid :: oid(),
+         array_element_oid :: oid() | undefined,
          codec :: module(),
          codec_state :: any()}).
 -record(oid_db,
@@ -29,7 +29,6 @@
 -opaque db() :: #oid_db{}.
 -opaque type_info() :: #type{}.
 
--define(DICT, dict).
 -define(RECORD_OID, 2249).
 
 
@@ -63,7 +62,7 @@ parse_rows(Rows) ->
 
 %% 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{}].
+                       ordsets:ordset(epgsql_codec:codec_entry())) -> [type_info()].
 join_codecs_oids(Oids, Codecs) ->
     do_join(lists:sort(Oids), lists:sort(Codecs)).
 
@@ -90,21 +89,21 @@ do_join([], _) ->
 
 -spec from_list([type_info()]) -> db().
 from_list(Types) ->
-    #oid_db{by_oid = ?DICT:from_list(
+    #oid_db{by_oid = dict:from_list(
                        [{Oid, Type} || #type{oid = Oid} = Type <- Types]),
-            by_name = ?DICT:from_list(
+            by_name = dict:from_list(
                         [{{Name, IsArray}, Oid}
                          || #type{name = Name, is_array = IsArray, oid = Oid}
                                 <- Types])}.
 
 to_list(#oid_db{by_oid = Dict}) ->
-    [Type || {_Oid, Type} <- ?DICT:to_list(Dict)].
+    [Type || {_Oid, Type} <- dict:to_list(Dict)].
 
 -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),
-    ByOid = ?DICT:merge(fun(_, _, V2) -> V2 end, OldByOid, NewByOid),
-    ByName = ?DICT:merge(fun(_, _, V2) -> V2 end, OldByName, NewByName),
+    ByOid = dict:merge(fun(_, _, V2) -> V2 end, OldByOid, NewByOid),
+    ByName = dict:merge(fun(_, _, V2) -> V2 end, OldByName, NewByName),
     Store#oid_db{by_oid = ByOid,
                  by_name = ByName}.
 
@@ -112,7 +111,7 @@ update(Types, #oid_db{by_oid = OldByOid, by_name = OldByName} = Store) ->
 %% find_by_oid(?RECORD_OID, _) ->
 %%     '$record';
 find_by_oid(Oid, #oid_db{by_oid = Dict}) ->
-    case ?DICT:find(Oid, Dict) of
+    case dict:find(Oid, Dict) of
         {ok, Type} -> Type;
         error -> undefined
     end.
@@ -120,11 +119,11 @@ find_by_oid(Oid, #oid_db{by_oid = Dict}) ->
 -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),
-    ?DICT:fetch(Oid, ByOid).                  % or maybe find_by_oid(Oid, Store)
+    dict:fetch(Oid, ByOid).                  % or maybe find_by_oid(Oid, Store)
 
 -spec oid_by_name(epgsql:type_name(), boolean(), db()) -> oid().
 oid_by_name(Name, IsArray, #oid_db{by_name = ByName}) ->
-    ?DICT:fetch({Name, IsArray}, ByName).
+    dict:fetch({Name, IsArray}, ByName).
 
 -spec type_to_codec_entry(type_info()) -> epgsql_codec:codec_entry().
 type_to_codec_entry(#type{name = Name, codec = Codec, codec_state = State}) ->

+ 1 - 1
src/epgsql_sock.erl

@@ -360,7 +360,7 @@ do_send(gen_tcp, Sock, Bin) ->
             ok
     catch
         error:_Error ->
-            {error,einval}
+            {error, einval}
     end;
 
 do_send(Mod, Sock, Bin) ->

+ 1 - 4
src/epgsql_wire.erl

@@ -247,10 +247,7 @@ encode_parameter({_, null}, _Codec) ->
 encode_parameter({{unknown_oid, _Oid}, Value}, _Codec) ->
     encode_text(Value);
 encode_parameter({Type, Value}, Codec) ->
-    case epgsql_binary:encode(Type, Value, Codec) of
-        {error, unsupported} -> encode_text(Value);
-        Encoded -> {1, Encoded}
-    end;
+    {1, epgsql_binary:encode(Type, Value, Codec)};
 encode_parameter(Value, _Codec) -> encode_text(Value).
 
 encode_text(B) when is_binary(B)  -> {0, encode_bin(B)};

+ 1 - 1
src/epgsqla.erl

@@ -92,7 +92,7 @@ parse(C, Sql) ->
 parse(C, Sql, Types) ->
     parse(C, "", Sql, Types).
 
--spec parse(epgsql:connection(), iolist(), string(), [epgsql_type()]) -> reference().
+-spec parse(epgsql:connection(), iolist(), string(), [epgsql:epgsql_type()]) -> reference().
 parse(C, Name, Sql, Types) ->
     cast(C, epgsql_cmd_parse, {Name, Sql, Types}).
 

+ 1 - 1
src/epgsqli.erl

@@ -91,7 +91,7 @@ parse(C, Sql) ->
 parse(C, Sql, Types) ->
     parse(C, "", Sql, Types).
 
--spec parse(epgsql:connection(), iolist(), string(), [epgsql_type()]) -> reference().
+-spec parse(epgsql:connection(), iolist(), string(), [epgsql:epgsql_type()]) -> reference().
 parse(C, Name, Sql, Types) ->
     incremental(C, epgsql_cmd_parse, {Name, Sql, Types}).