Browse Source

Merge pull request #214 from seriyps/edoc

Cleanup edocs. Fixes #213
Sergey Prokhorov 5 years ago
parent
commit
2d4d1ada05
49 changed files with 403 additions and 121 deletions
  1. 3 0
      .gitignore
  2. 1 0
      .travis.yml
  3. 7 0
      Makefile
  4. 4 4
      README.md
  5. 57 0
      doc/overview.edoc
  6. 0 0
      doc/pluggable_commands.md
  7. 0 0
      doc/pluggable_types.md
  8. 0 0
      doc/streaming.md
  9. 2 1
      rebar.config
  10. 11 0
      src/commands/epgsql_cmd_batch.erl
  11. 6 0
      src/commands/epgsql_cmd_bind.erl
  12. 4 0
      src/commands/epgsql_cmd_close.erl
  13. 4 2
      src/commands/epgsql_cmd_connect.erl
  14. 5 1
      src/commands/epgsql_cmd_describe_portal.erl
  15. 7 2
      src/commands/epgsql_cmd_describe_statement.erl
  16. 9 0
      src/commands/epgsql_cmd_equery.erl
  17. 8 0
      src/commands/epgsql_cmd_execute.erl
  18. 4 0
      src/commands/epgsql_cmd_parse.erl
  19. 5 1
      src/commands/epgsql_cmd_prepared_query.erl
  20. 7 0
      src/commands/epgsql_cmd_squery.erl
  21. 5 0
      src/commands/epgsql_cmd_start_replication.erl
  22. 5 0
      src/commands/epgsql_cmd_sync.erl
  23. 1 1
      src/commands/epgsql_cmd_update_type_cache.erl
  24. 5 2
      src/datatypes/epgsql_codec_boolean.erl
  25. 12 5
      src/datatypes/epgsql_codec_bpchar.erl
  26. 11 4
      src/datatypes/epgsql_codec_datetime.erl
  27. 5 2
      src/datatypes/epgsql_codec_float.erl
  28. 9 3
      src/datatypes/epgsql_codec_geometric.erl
  29. 7 5
      src/datatypes/epgsql_codec_hstore.erl
  30. 6 3
      src/datatypes/epgsql_codec_integer.erl
  31. 7 2
      src/datatypes/epgsql_codec_intrange.erl
  32. 8 3
      src/datatypes/epgsql_codec_json.erl
  33. 6 3
      src/datatypes/epgsql_codec_net.erl
  34. 1 0
      src/datatypes/epgsql_codec_noop.erl
  35. 9 2
      src/datatypes/epgsql_codec_postgis.erl
  36. 13 4
      src/datatypes/epgsql_codec_text.erl
  37. 7 2
      src/datatypes/epgsql_codec_timerange.erl
  38. 6 3
      src/datatypes/epgsql_codec_uuid.erl
  39. 56 40
      src/epgsql.erl
  40. 7 1
      src/epgsql_binary.erl
  41. 3 0
      src/epgsql_codec.erl
  42. 4 2
      src/epgsql_command.erl
  43. 3 3
      src/epgsql_oid_db.erl
  44. 7 5
      src/epgsql_scram.erl
  45. 26 12
      src/epgsql_sock.erl
  46. 9 1
      src/epgsql_wire.erl
  47. 7 0
      src/epgsqla.erl
  48. 7 0
      src/epgsqli.erl
  49. 7 2
      src/ewkb.erl

+ 3 - 0
.gitignore

@@ -1,3 +1,6 @@
 _build
 rebar3
 datadir/
+doc/*
+!doc/overview.edoc
+!doc/*.md

+ 1 - 0
.travis.yml

@@ -20,4 +20,5 @@ matrix:
 script:
   - '[ "$TRAVIS_OTP_RELEASE" = "18.3" ] || make elvis' # TODO: remove the guard when OTP18 support is dropped
   - make test
+  - make edoc
   - make dialyzer

+ 7 - 0
Makefile

@@ -12,6 +12,10 @@ compile: src/epgsql_errcodes.erl $(REBAR)
 
 clean: $(REBAR)
 	@$(REBAR) clean
+	@rm -f doc/*.html
+	@rm -f doc/erlang.png
+	@rm -f doc/stylesheet.css
+	@rm -f doc/edoc-info
 
 src/epgsql_errcodes.erl:
 	./generate_errcodes_src.sh > src/epgsql_errcodes.erl
@@ -34,4 +38,7 @@ dialyzer: compile
 elvis: $(REBAR)
 	@$(REBAR) as lint lint
 
+edoc: $(REBAR)
+	@$(REBAR) edoc
+
 .PHONY: all compile clean common-test eunit cover test dialyzer elvis

+ 4 - 4
README.md

@@ -442,7 +442,7 @@ item will be `{error, #error{}}` and no more results will be produced.
 
 ## Data Representation
 
-Data representation may be configured using [pluggable datatype codecs](pluggable_types.md),
+Data representation may be configured using [pluggable datatype codecs](doc/pluggable_types.md),
 so following is just default mapping:
 
 PG type       | Representation
@@ -618,15 +618,15 @@ Parameter's value may change during connection's lifetime.
 
 ## Streaming replication protocol
 
-See [streaming.md](streaming.md).
+See [streaming.md](doc/streaming.md).
 
 ## Pluggable commands
 
-See [pluggable_commands.md](pluggable_commands.md)
+See [pluggable_commands.md](doc/pluggable_commands.md)
 
 ## Pluggable datatype codecs
 
-See [pluggable_types.md](pluggable_types.md)
+See [pluggable_types.md](doc/pluggable_types.md)
 
 ## Mailing list
 

+ 57 - 0
doc/overview.edoc

@@ -0,0 +1,57 @@
+@title epgsql - PostgreSQL driver for Erlang, internal documentation
+@doc
+This document is made mostly as internal documentation. It can be useful
+if you plan to contribute some patches to epgsql, want to implement
+custom datatypes or commands or to better understand epgsql internals.
+
+End-user interface is described in <a href="https://github.com/epgsql/epgsql#readme">README.md</a>.
+
+== Interfaces ==
+Epgsql has 3 end-user API interfaces:
+
+<ul>
+  <li>{@link epgsql} - synchronous</li>
+  <li>{@link epgsqla} - asynchronous</li>
+  <li>{@link epgsqli} - incremental</li>
+</ul>
+
+== Internals ==
+
+All 3 interfaces communicate with {@link epgsql_sock} gen_server, which holds all
+the connection state. While `epgsql_sock' holds all the state, it doesn't know
+much about Client-Server communication protocol.
+All the communication logic between epgsql and PostgreSQL server is implemented
+as a {@section Commands} and `epgsql_sock' acts as an executor for those commands.
+
+PostgreSQL binary communication protocol is represented by 2 modules:
+<ul>
+  <li>{@link epgsql_wire} - codecs for on-wire communication protocol messages</li>
+  <li>{@link epgsql_binary} - interface to PostgreSQL binary data encoding protocol(see {@section Datatypes})</li>
+</ul>
+
+`epgsql_sock' holds an internal state of `epgsql_binary' codecs as well. The
+main contents of this state is the mapping between PostgreSQL unique numeric
+datatype IDs (OIDs) and callbacks which will be used to decode this datatype.
+This mapping is handled by {@link epgsql_oid_db} module and is populated at
+connection set-up time by {@link epgsql_cmd_connect}.
+
+Most of the connection initialization (network connection, authentication, codecs)
+is performed by {@link epgsql_cmd_connect} command, wich is just a regualr command
+(but quite complex one) and can be replaced by own implementation if needed.
+
+== Commands ==
+
+Client can execute a number of built-in commands as well as define their own.
+See {@link epgsql_command} and all the `epgsql_cmd_*' pages.
+There exists a <a href="pluggable_commands.md">manual</a> that explains how to
+implement your own command.
+
+== Datatypes ==
+
+Epgsql supports both PostgreSQL <a href="https://www.postgresql.org/docs/current/protocol-overview.html#PROTOCOL-FORMAT-CODES">text and binary</a>
+data encodings to transfer the data (query placeholder parameters and result rows).
+There are a bunch of built-in codecs and it's possible to
+implement custom ones as well as fine-tune some of built-ins.
+See {@link epgsql_codec} and all the `epgsql_codec_*' pages for more details.
+There exists a <a href="pluggable_types.md">manual</a> that explains how to
+implement your own datatype codec.

+ 0 - 0
pluggable_commands.md → doc/pluggable_commands.md


+ 0 - 0
pluggable_types.md → doc/pluggable_types.md


+ 0 - 0
streaming.md → doc/streaming.md


+ 2 - 1
rebar.config

@@ -3,7 +3,8 @@
 {eunit_opts, [verbose]}.
 
 {cover_enabled, true}.
-{cover_print_enabled, true}.
+
+{edoc_opts, [{preprocess, true}]}.
 
 {profiles, [
     {test, [

+ 11 - 0
src/commands/epgsql_cmd_batch.erl

@@ -1,3 +1,12 @@
+%% @doc Execute multiple extended queries in a single network round-trip
+%%
+%% There are 2 kinds of interface:
+%% <ol>
+%%  <li>To execute multiple queries, each with it's own `statement()'</li>
+%%  <li>To execute multiple queries, but by binding different parameters to the
+%%  same `statement()'</li>
+%% </ol>
+%% ```
 %% > {Bind
 %% <  BindComplete
 %% >  Execute
@@ -5,6 +14,7 @@
 %% <  CommandComplete}*
 %% > Sync
 %% < ReadyForQuery
+%% '''
 -module(epgsql_cmd_batch).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).
@@ -57,6 +67,7 @@ execute(Sock, #batch{batch = Batch,
                                             types = Types}} = State) ->
     Codec = epgsql_sock:get_codec(Sock),
     BinFormats = epgsql_wire:encode_formats(Columns),
+    %% TODO: build some kind of encoder and reuse it for each batch item
     Commands =
         lists:foldr(
           fun(Parameters, Acc) ->

+ 6 - 0
src/commands/epgsql_cmd_bind.erl

@@ -1,5 +1,11 @@
+%% @doc Binds placeholder parameters to prepared statement
+%%
+%% ```
 %% > Bind
 %% < BindComplete
+%% '''
+%% @see epgsql_cmd_parse
+%% @see epgsql_cmd_execute
 -module(epgsql_cmd_bind).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 4 - 0
src/commands/epgsql_cmd_close.erl

@@ -1,5 +1,9 @@
+%% @doc Closes statement / portal
+%%
+%% ```
 %% > Close
 %% < CloseComplete
+%% '''
 -module(epgsql_cmd_close).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 4 - 2
src/commands/epgsql_cmd_connect.erl

@@ -1,6 +1,8 @@
+%%% @doc Connects to the server and performs all the necessary handshakes.
+%%%
 %%% Special kind of command - it's exclusive: no other commands can run until
 %%% this one finishes.
-%%% It also uses some 'private' epgsql_sock's APIs
+%%% It also uses some "private" epgsql_sock's APIs
 %%%
 -module(epgsql_cmd_connect).
 -behaviour(epgsql_command).
@@ -105,7 +107,7 @@ opts_hide_password(Opts) -> Opts.
 
 
 %% @doc this function wraps plaintext password to a lambda function, so, if
-%% epgsql_sock process crashes when executing `connect` command, password will
+%% epgsql_sock process crashes when executing `connect' command, password will
 %% not appear in a crash log
 -spec hide_password(iodata()) -> fun( () -> iodata() ).
 hide_password(Password) when is_list(Password);

+ 5 - 1
src/commands/epgsql_cmd_describe_portal.erl

@@ -1,5 +1,9 @@
-%% > Describe
+%% @doc Asks the server to provide description of portal's results columns
+%%
+%% ```
+%% > Describe(PORTAL)
 %% < RowDescription | NoData
+%% '''
 -module(epgsql_cmd_describe_portal).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 7 - 2
src/commands/epgsql_cmd_describe_statement.erl

@@ -1,7 +1,12 @@
-%% Almost the same as "parse"
-%% > Describe
+%% @doc Asks server to provide input parameter and result rows information.
+%%
+%% Almost the same as {@link epgsql_cmd_parse}.
+%%
+%% ```
+%% > Describe(STATEMENT)
 %% < ParameterDescription
 %% < RowDescription | NoData
+%% '''
 -module(epgsql_cmd_describe_statement).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 9 - 0
src/commands/epgsql_cmd_equery.erl

@@ -1,3 +1,10 @@
+%% @doc Performs 2nd stage of
+%% <a href="https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY">
+%% extended query protocol.</a>
+%%
+%% Takes prepared `statement()' and bind-parameters for placeholders and produces
+%% query results.
+%% ```
 %% > Bind
 %% < BindComplete
 %% > Execute
@@ -7,6 +14,8 @@
 %% < CloseComplete
 %% > Sync
 %% < ReadyForQuery
+%% '''
+%% @see epgsql_cmd_parse
 -module(epgsql_cmd_equery).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 8 - 0
src/commands/epgsql_cmd_execute.erl

@@ -1,6 +1,14 @@
+%% @doc Executes a portal.
+%%
+%% It's possible to tell the server to only return limited number of rows by
+%% providing non-zero `MaxRows' parameter.
+%% ```
 %% > Execute
 %% < DataRow*
 %% < CommandComplete | PortalSuspended
+%% '''
+%% @see epgsql_cmd_parse
+%% @see epgsql_cmd_bind
 -module(epgsql_cmd_execute).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 4 - 0
src/commands/epgsql_cmd_parse.erl

@@ -1,8 +1,12 @@
+%% @doc Asks server to parse SQL query and send information aboud bind-parameters and result columns.
+%%
+%% ```
 %% > Parse
 %% < ParseComplete
 %% > Describe
 %% < ParameterDescription
 %% < RowDescription | NoData
+%% '''
 -module(epgsql_cmd_parse).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 5 - 1
src/commands/epgsql_cmd_prepared_query.erl

@@ -1,4 +1,7 @@
-%% Almost the same as equery, but don't execute 'CLOSE'
+%% @doc Almost the same as equery, but don't execute 'CLOSE'
+%%
+%% So, statement can be reused multiple times.
+%% ```
 %% > Bind
 %% < BindComplete
 %% > Execute
@@ -6,6 +9,7 @@
 %% < CommandComplete
 %% > Sync
 %% < ReadyForQuery
+%% '''
 -module(epgsql_cmd_prepared_query).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 7 - 0
src/commands/epgsql_cmd_squery.erl

@@ -1,4 +1,10 @@
+%% @doc Executes SQL query(es) using
+%% <a href="https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.4">
+%% simple query protocol</a>
+%%
+%% Squery can not have placeholders.
 %% Squery may contain many semicolon-separated queries
+%% ```
 %% > Query
 %% < (RowDescription?
 %% <  DataRow*
@@ -8,6 +14,7 @@
 %% > Query when len(strip(Query)) == 0
 %% < EmptyQueryResponse
 %% < ReadyForQuery
+%% '''
 -module(epgsql_cmd_squery).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 5 - 0
src/commands/epgsql_cmd_start_replication.erl

@@ -1,5 +1,10 @@
+%% @doc Requests server to start sending replication packets
+%%
+%% See {@link epgsql:connect/1} `replication' parameter.
+%% ```
 %% > SimpleQuery "START_REPLICATION ..."
 %% < CopyBothResponse | Error
+%% '''
 -module(epgsql_cmd_start_replication).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 5 - 0
src/commands/epgsql_cmd_sync.erl

@@ -1,5 +1,10 @@
+%% @doc Synchronize client and server states for multi-command combinations
+%%
+%% Should be executed if APIs start to return `{error, sync_required}'.
+%% ```
 %% > Sync
 %% < ReadyForQuery
+%% '''
 -module(epgsql_cmd_sync).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 1 - 1
src/commands/epgsql_cmd_update_type_cache.erl

@@ -1,4 +1,4 @@
-%% Special command. Executes Squery over pg_type table and updates codecs.
+%% @doc Special command. Executes Squery over pg_type table and updates codecs.
 -module(epgsql_cmd_update_type_cache).
 -behaviour(epgsql_command).
 -export([init/1, execute/2, handle_message/4]).

+ 5 - 2
src/datatypes/epgsql_codec_boolean.erl

@@ -1,8 +1,11 @@
 %%% @doc
 %%% Codec for `bool'.
+%%%
 %%% `unknown' is represented by `null'.
-%%% https://www.postgresql.org/docs/current/static/datatype-boolean.html
-%%% $PG$/src/backend/utils/adt/bool.c
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/datatype-boolean.html]</li>
+%%%  <li>$PG$/src/backend/utils/adt/bool.c</li>
+%%% </ul>
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 12 - 5
src/datatypes/epgsql_codec_bpchar.erl

@@ -1,9 +1,16 @@
 %%% @doc
-%%% Codec for `bpchar', `char' (CHAR(N), char).
-%%% ```SELECT 1::char''' ```SELECT 'abc'::char(10)'''
-%%% For 'text', 'varchar' see epgsql_codec_text.erl.
-%%% https://www.postgresql.org/docs/10/static/datatype-character.html
-%%% $PG$/src/backend/utils/adt/varchar.c
+%%% Codec for blank-padded fixed-size character type
+%%%
+%%% `CHAR' (single-byte) is represented as `byte()';
+%%% `CHARACTER(N) / CHAR(N)' as binary string
+%%%
+%%% <code>SELECT 1::char;</code> <code>SELECT 'abc'::char(10)</code>
+%%%
+%%% For 'text', 'varchar' see {@link epgsql_codec_text}.
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/10/static/datatype-character.html]</li>
+%%%  <li>$PG$/src/backend/utils/adt/varchar.c</li>
+%%% </ul>
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 11 - 4
src/datatypes/epgsql_codec_datetime.erl

@@ -1,9 +1,16 @@
 %%% @doc
 %%% Codec for `time', `timetz', `date', `timestamp', `timestamptz', `interval'
-%%% https://www.postgresql.org/docs/current/static/datatype-datetime.html
-%%% $PG$/src/backend/utils/adt/timestamp.c // `timestamp', `timestamptz', `interval'
-%%% $PG$/src/backend/utils/adt/datetime.c // helpers
-%%% $PG$/src/backend/utils/adt/date.c // `time', `timetz', `date'
+%%%
+%%% It supports both integer and float datetime representations (see
+%%% [https://www.postgresql.org/docs/current/runtime-config-preset.html#GUC-INTEGER-DATETIMES]).
+%%% But float representation support might be eventually removed.
+%%%
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/datatype-datetime.html]</li>
+%%%  <li>$PG$/src/backend/utils/adt/timestamp.c // `timestamp', `timestamptz', `interval'</li>
+%%%  <li>$PG$/src/backend/utils/adt/datetime.c // helpers</li>
+%%%  <li>$PG$/src/backend/utils/adt/date.c // `time', `timetz', `date'</li>
+%%% </ul>
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 5 - 2
src/datatypes/epgsql_codec_float.erl

@@ -1,7 +1,10 @@
 %%% @doc
 %%% Codec for `float4', `float8' (real, double precision).
-%%% https://www.postgresql.org/docs/current/static/datatype-numeric.html#datatype-float
-%%% $PG$/src/backend/utils/adt/float.c
+%%%
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/datatype-numeric.html#datatype-float]</li>
+%%%  <li>$PG$/src/backend/utils/adt/float.c</li>
+%%% </ul>
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 9 - 3
src/datatypes/epgsql_codec_geometric.erl

@@ -1,8 +1,14 @@
 %%% @doc
 %%% Codec for `point'.
-%%% https://www.postgresql.org/docs/current/static/datatype-geometric.html
-%%% $PG$/src/backend/utils/adt/geo_ops.c
-%%% XXX: it's not PostGIS!
+%%%
+%%% Codecs for other geometric datatypes (line, box, path, polygon, circle) can
+%%% be added later.
+%%%
+%%% XXX: it's not PostGIS! For PostGIS see {@link epgsql_codec_postgis}.
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/datatype-geometric.html]</li>
+%%%  <li>$PG$/src/backend/utils/adt/geo_ops.c</li>
+%%% </ul>
 %%% @end
 %%% Created : 14 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 %%% TODO: line, lseg, box, path, polygon, circle

+ 7 - 5
src/datatypes/epgsql_codec_hstore.erl

@@ -1,10 +1,12 @@
 %%% @doc
 %%% Codec for `hstore' type.
-%%% https://www.postgresql.org/docs/current/static/hstore.html
-%%% XXX: hstore not a part of postgresql builtin datatypes, it's in contrib.
-%%% It should be enabled in postgresql by command
-%%% `CREATE EXTENSION hstore`
-%%% $PG$/contrib/hstore/
+%%%
+%%% XXX: hstore is not a part of postgresql builtin datatypes, it's in contrib.
+%%% It should be enabled in postgresql by command `CREATE EXTENSION hstore'.
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/hstore.html]</li>
+%%%  <li>$PG$/contrib/hstore/</li>
+%%% </ul>
 %%% @end
 %%% Created : 14 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 6 - 3
src/datatypes/epgsql_codec_integer.erl

@@ -1,8 +1,11 @@
 %%% @doc
 %%% Codec for `int2', `int4', `int8' (smallint, integer, bigint).
-%%% https://www.postgresql.org/docs/current/static/datatype-numeric.html#datatype-int
-%%% $PG$/src/backend/utils/adt/int.c
-%%% $PG$/src/backend/utils/adt/int8.c
+%%%
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/datatype-numeric.html#datatype-int]</li>
+%%%  <li>$PG$/src/backend/utils/adt/int.c</li>
+%%%  <li>$PG$/src/backend/utils/adt/int8.c</li>
+%%% </ul>
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 7 - 2
src/datatypes/epgsql_codec_intrange.erl

@@ -1,7 +1,12 @@
 %%% @doc
 %%% Codec for `int4range', `int8range' types.
-%%% https://www.postgresql.org/docs/current/static/rangetypes.html#rangetypes-builtin
-%%% $PG$/src/backend/utils/adt/rangetypes.c
+%%%
+%%% <ul>
+%%%   <li>[https://www.postgresql.org/docs/current/static/rangetypes.html#rangetypes-builtin]</li>
+%%%   <li>$PG$/src/backend/utils/adt/rangetypes.c</li>
+%%% </ul>
+%%% @end
+%%% @see epgsql_codec_integer
 %%% @end
 %%% Created : 14 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 %%% TODO: universal range, based on pg_range table

+ 8 - 3
src/datatypes/epgsql_codec_json.erl

@@ -1,8 +1,13 @@
 %%% @doc
 %%% Codec for `json', `jsonb'
-%%% https://www.postgresql.org/docs/current/static/datatype-json.html
-%%% $PG$/src/backend/utils/adt/json.c // `json'
-%%% $PG$/src/backend/utils/adt/jsonb.c // `jsonb'
+%%%
+%%% It is possible to instruct the codec to do JSON encoding/decoding to Erlang
+%%% terms by providing callback module name, see {@link json_mod()}.
+%%% <ul>
+%%%   <li>[https://www.postgresql.org/docs/current/static/datatype-json.html]</li>
+%%%   <li>$PG$/src/backend/utils/adt/json.c // `json'</li>
+%%%   <li>$PG$/src/backend/utils/adt/jsonb.c // `jsonb'</li>
+%%% </ul>
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 6 - 3
src/datatypes/epgsql_codec_net.erl

@@ -1,9 +1,12 @@
 %%% @doc
 %%% Codec for `inet', `cidr'
-%%% https://www.postgresql.org/docs/10/static/datatype-net-types.html
-%%% $PG$/src/backend/utils/adt/network.c
 %%%
-%%% TIP: use `inet:ntoa/1' to convert `ip()' to string.
+%%% TIP: use {@link inet:ntoa/1} and {@link inet:parse_address/1} to convert
+%%% between {@link ip()} and `string()'.
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/10/static/datatype-net-types.html]</li>
+%%%  <li>$PG$/src/backend/utils/adt/network.c</li>
+%%% </ul>
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 -module(epgsql_codec_net).

+ 1 - 0
src/datatypes/epgsql_codec_noop.erl

@@ -1,3 +1,4 @@
+%%% @private
 %%% @doc
 %%% Dummy codec. Used internally
 %%% @end

+ 9 - 2
src/datatypes/epgsql_codec_postgis.erl

@@ -1,7 +1,14 @@
 %%% @doc
 %%% Codec for `geometry' PostGIS umbrella datatype.
-%%% http://postgis.net/docs/manual-2.4/geometry.html
-%%% $POSTGIS$/postgis/lwgeom_inout.c
+%%%
+%%% XXX: PostGIS is not a Postgres's built-in datatype! It should be instaled
+%%% separately and enabled via `CREATE EXTENSION postgis'.
+%%% <ul>
+%%%  <li>[http://postgis.net/docs/manual-2.4/geometry.html]</li>
+%%%  <li>$POSTGIS$/postgis/lwgeom_inout.c</li>
+%%% </ul>
+%%% @end
+%%% @see ewkb
 %%% @end
 %%% Created : 14 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 13 - 4
src/datatypes/epgsql_codec_text.erl

@@ -1,9 +1,18 @@
 %%% @doc
 %%% Codec for `text', `varchar', `bytea'.
-%%% For 'char' see epgsql_codec_bpchar.erl.
-%%% https://www.postgresql.org/docs/10/static/datatype-character.html
-%%% $PG$/src/backend/utils/adt/varchar.c
-%%% $PG$/src/backend/utils/adt/varlena.c
+%%%
+%%% If input for `text' or `varchar' is provided as a list, not binary, and it
+%%% contains not just `byte()', an attempt to perform unicode conversion will be made.
+%%%
+%%% Also, `integer()', `float()' and `atom()' are automatically converted to
+%%% strings, but this kind of conversion might be eventualy removed.
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/10/static/datatype-character.html]</li>
+%%%  <li>$PG$/src/backend/utils/adt/varchar.c</li>
+%%%  <li>$PG$/src/backend/utils/adt/varlena.c</li>
+%%% </ul>
+%%% @end
+%%% @see epgsql_codec_bpchar. epgsql_codec_bpchar - for 'char' and 'char(N)'
 %%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 7 - 2
src/datatypes/epgsql_codec_timerange.erl

@@ -1,7 +1,12 @@
 %%% @doc
 %%% Codec for `tsrange', `tstzrange', `daterange' types.
-%%% https://www.postgresql.org/docs/current/static/rangetypes.html#rangetypes-builtin
-%%% $PG$/src/backend/utils/adt/rangetypes.c
+%%%
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/rangetypes.html#rangetypes-builtin]</li>
+%%%  <li>$PG$/src/backend/utils/adt/rangetypes.c</li>
+%%% </ul>
+%%% @end
+%%% @see epgsql_codec_datetime
 %%% @end
 %%% Created : 16 Jul 2018 by Vladimir Sekissov <eryx67@gmail.com>
 %%% TODO: universal range, based on pg_range table

+ 6 - 3
src/datatypes/epgsql_codec_uuid.erl

@@ -1,9 +1,12 @@
 %%% @doc
 %%% Codec for `uuid' type.
-%%% Input expected to be in hex string, eg
+%%%
+%%% Input is expected to be in hex `string()' / `binary()', eg
 %%% `<<"550e8400-e29b-41d4-a716-446655440000">>'.
-%%% https://www.postgresql.org/docs/current/static/datatype-uuid.html
-%%% $PG$/src/backend/utils/adt/uuid.c
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/datatype-uuid.html]</li>
+%%%  <li>$PG$/src/backend/utils/adt/uuid.c</li>
+%%% </ul>
 %%% @end
 %%% Created : 14 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 

+ 56 - 40
src/epgsql.erl

@@ -1,3 +1,7 @@
+%%% @doc Synchronous interface.
+%%%
+%%% All functions block (with infinite timeout) until full result is available.
+%%% @end
 %%% Copyright (C) 2008 - Will Glozer.  All rights reserved.
 %%% Copyright (C) 2011 - Anton Lebedevich.  All rights reserved.
 
@@ -42,7 +46,7 @@
 
 -include("epgsql.hrl").
 
--type sql_query() :: iodata().
+-type sql_query() :: iodata(). % SQL query text
 -type host() :: inet:ip_address() | inet:hostname().
 -type password() :: string() | iodata() | fun( () -> iodata() ).
 -type connection() :: pid().
@@ -76,7 +80,7 @@
           replication => string()}.
 
 -type connect_error() :: epgsql_cmd_connect:connect_error().
--type query_error() :: #error{}.
+-type query_error() :: #error{}.              % Error report generated by server
 
 
 -type type_name() :: atom().
@@ -90,15 +94,15 @@
 -type pg_datetime() :: epgsql_codec_datetime:pg_datetime().
 -type pg_interval() :: epgsql_codec_datetime:pg_interval().
 
-%% Deprecated
 -type bind_param() :: any().
+%% Value to be bound to placeholder (`$1', `$2' etc)
 
 -type typed_param() :: {epgsql_type(), bind_param()}.
 
 -type column() :: #column{}.
 -type statement() :: #statement{}.
 -type squery_row() :: tuple(). % tuple of binary().
--type equery_row() :: tuple(). % tuple of bind_param().
+-type equery_row() :: tuple(). % tuple of any().
 -type ok_reply(RowType) ::
         %% select
     {ok, ColumnsDescription :: [column()], RowsValues :: [RowType]} |
@@ -126,6 +130,7 @@
 %% -------------
 
 %% -- client interface --
+%% @doc connects to the server and performs all the necessary handshakes
 -spec connect(connect_opts())
         -> {ok, Connection :: connection()} | {error, Reason :: connect_error()}.
 connect(Opts) ->
@@ -140,13 +145,13 @@ connect(Host, Username, Opts) ->
 
 -spec connect(host(), string(), password(), connect_opts())
         -> {ok, Connection :: connection()} | {error, Reason :: connect_error()}.
-%% @doc connects to Postgres
-%% where
-%% `Host'     - host to connect to
-%% `Username' - username to connect as, defaults to `$USER'
-%% `Password' - optional password to authenticate with
-%% `Opts'     - proplist or map of extra options
-%% returns `{ok, Connection}' otherwise `{error, Reason}'
+%% @doc connects to the server and performs all the necessary handshakes (legacy interface)
+%% @param Host     host to connect to
+%% @param Username username to connect as, defaults to `$USER'
+%% @param Password optional password to authenticate with
+%% @param Opts     proplist or map of extra options
+%% @returns `{ok, Connection}' otherwise `{error, Reason}'
+%% @see connect/1
 connect(Host, Username, Password, Opts) ->
     {ok, C} = epgsql_sock:start_link(),
     connect(C, Host, Username, Password, Opts).
@@ -216,10 +221,10 @@ get_parameter(C, Name) ->
 set_notice_receiver(C, PidOrName) ->
     epgsql_sock:set_notice_receiver(C, PidOrName).
 
-%% @doc Returns last command status message
-%% If multiple queries were executed using `squery/2', separated by semicolon,
+%% @doc Returns last command status message.
+%% If multiple queries were executed using {@link squery/2}, separated by semicolon,
 %% only the last query's status will be available.
-%% See https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQCMDSTATUS
+%% See [https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQCMDSTATUS]
 -spec get_cmd_status(connection()) -> {ok, Status}
                                           when
       Status :: undefined | atom() | {atom(), integer()}.
@@ -228,24 +233,23 @@ get_cmd_status(C) ->
 
 -spec squery(connection(), sql_query()) -> epgsql_cmd_squery:response().
 %% @doc runs simple `SqlQuery' via given `Connection'
+%% @see epgsql_cmd_squery
 squery(Connection, SqlQuery) ->
     epgsql_sock:sync_command(Connection, epgsql_cmd_squery, SqlQuery).
 
 equery(C, Sql) ->
     equery(C, Sql, []).
 
-%% TODO add fast_equery command that doesn't need parsed statement
 -spec equery(connection(), sql_query(), [bind_param()]) ->
                     epgsql_cmd_equery:response().
 equery(C, Sql, Parameters) ->
-    case parse(C, "", Sql, []) of
-        {ok, #statement{types = Types} = S} ->
-            TypedParameters = lists:zip(Types, Parameters),
-            epgsql_sock:sync_command(C, epgsql_cmd_equery, {S, TypedParameters});
-        Error ->
-            Error
-    end.
+    equery(C, "", Sql, Parameters).
 
+%% @doc Executes extended query
+%% @end
+%% @see epgsql_cmd_equery
+%% @end
+%% TODO add fast_equery command that doesn't need parsed statement
 -spec equery(connection(), string(), sql_query(), [bind_param()]) ->
                     epgsql_cmd_equery:response().
 equery(C, Name, Sql, Parameters) ->
@@ -257,6 +261,8 @@ equery(C, Name, Sql, Parameters) ->
             Error
     end.
 
+%% @doc Similar to {@link equery/3}, but uses prepared statement that can be reused multiple times.
+%% @see epgsql_cmd_prepared_query
 -spec prepared_query(C::connection(), string() | statement(), Parameters::[bind_param()]) ->
                             epgsql_cmd_prepared_query:response().
 prepared_query(C, #statement{types = Types} = S, Parameters) ->
@@ -312,11 +318,15 @@ execute(C, S, N) ->
 execute(C, S, PortalName, N) ->
     epgsql_sock:sync_command(C, epgsql_cmd_execute, {S, PortalName, N}).
 
+%% @doc Executes batch of `{statement(), [bind_param()]}' extended queries
+%% @see epgsql_cmd_batch
 -spec execute_batch(connection(), [{statement(), [bind_param()]}]) ->
                            epgsql_cmd_batch:response().
 execute_batch(C, Batch) ->
     epgsql_sock:sync_command(C, epgsql_cmd_batch, Batch).
 
+%% @doc Executes same statement() extended query with each parameter list of a `Batch'
+%% @see epgsql_cmd_batch
 -spec execute_batch(connection(), statement() | sql_query(), [ [bind_param()] ]) ->
                            {[column()], epgsql_cmd_batch:response()}.
 execute_batch(C, #statement{columns = Cols} = Statement, Batch) ->
@@ -352,6 +362,7 @@ describe(C, portal, Name) ->
 close(C, #statement{name = Name}) ->
     close(C, statement, Name).
 
+%% @doc close statement or portal
 -spec close(connection(), statement | portal, iodata()) -> epgsql_cmd_close:response().
 close(C, Type, Name) ->
     epgsql_sock:sync_command(C, epgsql_cmd_close, {Type, Name}).
@@ -360,6 +371,7 @@ close(C, Type, Name) ->
 sync(C) ->
     epgsql_sock:sync_command(C, epgsql_cmd_sync, []).
 
+%% @doc cancel currently executing command
 -spec cancel(connection()) -> ok.
 cancel(C) ->
     epgsql_sock:cancel(C).
@@ -375,15 +387,20 @@ with_transaction(C, F) ->
 %% @doc Execute callback function with connection in a transaction.
 %% Transaction will be rolled back in case of exception.
 %% Options (proplist or map):
-%% - reraise (true): when set to true, exception will be re-thrown, otherwise
-%%   {rollback, ErrorReason} will be returned
-%% - ensure_comitted (false): even when callback returns without exception,
+%% <dl>
+%%  <dt>reraise</dt>
+%%  <dd>when set to true, exception will be re-thrown, otherwise
+%%   `{rollback, ErrorReason}' will be returned. Default: `true'</dd>
+%%  <dt>ensure_comitted</dt>
+%%  <dd>even when callback returns without exception,
 %%   check that transaction was comitted by checking CommandComplete status
 %%   of "COMMIT" command. In case when transaction was rolled back, status will be
-%%   "rollback" instead of "commit".
-%% - begin_opts (""): append extra options to "BEGIN" command (see
+%%   "rollback" instead of "commit". Default: `false'</dd>
+%%  <dt>begin_opts</dt>
+%%  <dd>append extra options to "BEGIN" command (see
 %%   https://www.postgresql.org/docs/current/static/sql-begin.html)
-%%   Beware of SQL injections! No escaping is made on begin_opts!
+%%   Beware of SQL injections! No escaping is made on begin_opts! Default: `""'</dd>
+%% </dl>
 -spec with_transaction(
         connection(), fun((connection()) -> Reply), Opts) -> Reply | {rollback, any()} | no_return() when
       Reply :: any(),
@@ -448,18 +465,17 @@ handle_x_log_data(Mod, StartLSN, EndLSN, WALRecord, Repl) ->
     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
-%% `ReplicationSlot' - the name of the replication slot to stream changes from
-%% `Callback'        - Callback module which should have the callback functions implemented for message processing.
-%%                      or a process which should be able to receive replication messages.
-%% `CbInitState'     - Callback Module's initial state
-%% `WALPosition'     - the WAL position XXX/XXX to begin streaming at.
-%%                      "0/0" to let the server determine the start point.
-%% `PluginOpts'      - optional options passed to the slot's logical decoding plugin.
-%%                      For example: "option_name1 'value1', option_name2 'value2'"
-%% `Opts'            - options of logical replication
-%% returns `ok' otherwise `{error, Reason}'
+%% @param Connection      connection in replication mode
+%% @param ReplicationSlot the name of the replication slot to stream changes from
+%% @param Callback        Callback module which should have the callback functions implemented for message processing.
+%%                        or a process which should be able to receive replication messages.
+%% @param CbInitState     Callback Module's initial state
+%% @param WALPosition     the WAL position XXX/XXX to begin streaming at.
+%%                        "0/0" to let the server determine the start point.
+%% @param PluginOpts      optional options passed to the slot's logical decoding plugin.
+%%                        For example: "option_name1 'value1', option_name2 'value2'"
+%% @param Opts            options of logical replication
+%% @returns `ok' otherwise `{error, Reason}'
 start_replication(Connection, ReplicationSlot, Callback, CbInitState, WALPosition, PluginOpts, Opts) ->
     Command = {ReplicationSlot, Callback, CbInitState, WALPosition, PluginOpts, to_map(Opts)},
     epgsql_sock:sync_command(Connection, epgsql_cmd_start_replication, Command).

+ 7 - 1
src/epgsql_binary.erl

@@ -1,5 +1,11 @@
+%%% @doc
+%%% Interface to encoder/decoder for binary postgres data representation
+%%% @end
+%%% @see epgsql_codec
+%%% @see epgsql_wire
+%%% @end
 %%% Copyright (C) 2008 - Will Glozer.  All rights reserved.
-%% XXX: maybe merge this module into epgsql_codec?
+%%% XXX: maybe merge this module into epgsql_codec?
 -module(epgsql_binary).
 
 -export([new_codec/2,

+ 3 - 0
src/epgsql_codec.erl

@@ -1,9 +1,12 @@
 %%% @doc
 %%% Behaviour for postgresql datatype codecs.
+%%%
 %%% XXX: this module and callbacks "know nothing" about OIDs.
 %%% XXX: state of codec shouldn't leave epgsql_sock process. If you need to
 %%% return "pointer" to data type/codec, it's better to return OID or type name.
 %%% @end
+%%% @see epgsql_binary
+%%% @end
 %%% Created : 12 Oct 2017 by Sergey Prokhorov <me@seriyps.ru>
 
 -module(epgsql_codec).

+ 4 - 2
src/epgsql_command.erl

@@ -1,5 +1,5 @@
-%%% Behaviour module for epgsql_sock commands.
-%%%
+%%% @doc Behaviour module for epgsql_sock commands.
+%%% @end
 %%% Copyright (C) 2017 - Sergey Prokhorov.  All rights reserved.
 
 -module(epgsql_command).
@@ -16,6 +16,7 @@
 -type execute_return() ::
         {ok, epgsql_sock:pg_sock(), state()}
       | {stop, Reason :: any(), Response :: any(), epgsql_sock:pg_sock()}.
+
 %% Execute command. It should send commands to socket.
 %% May be called many times if 'handle_message' will return 'requeue'.
 -callback execute(epgsql_sock:pg_sock(), state()) -> execute_return().
@@ -48,6 +49,7 @@
         %% Unknown packet. Terminate `epgsql_sock' process
       | unknown.
 %% Handle incoming packet
+
 -callback handle_message(Type :: byte(), Payload :: binary() | epgsql:query_error(),
                          epgsql_sock:pg_sock(), state()) -> handle_message_return().
 

+ 3 - 3
src/epgsql_oid_db.erl

@@ -1,7 +1,7 @@
 %%% @author Sergey Prokhorov <me@seriyps.ru>
 %%% @doc
-%%% Holds Oid <-> Type mappings (forward and reverse).
-%%% See https://www.postgresql.org/docs/current/static/catalog-pg-type.html
+%%% Holds Oid to Type mappings (forward and reverse).
+%%% See [https://www.postgresql.org/docs/current/static/catalog-pg-type.html].
 %%% @end
 
 -module(epgsql_oid_db).
@@ -36,7 +36,7 @@
 %% pg_type Data preparation
 %%
 
-%% @doc build query to fetch OID<->type_name information from PG server
+%% @doc build query to fetch OID to type_name information from PG server
 -spec build_query([epgsql:type_name() | binary()]) -> iolist().
 build_query(TypeNames) ->
     %% TODO: lists:join/2, ERL 19+

+ 7 - 5
src/epgsql_scram.erl

@@ -1,11 +1,13 @@
 %%% coding: utf-8
 %%% @doc
 %%% SCRAM--SHA-256 helper functions
-%%% See
-%%% https://www.postgresql.org/docs/current/static/sasl-authentication.html
-%%% https://en.wikipedia.org/wiki/Salted_Challenge_Response_Authentication_Mechanism
-%%% https://tools.ietf.org/html/rfc7677
-%%% https://tools.ietf.org/html/rfc5802
+%%%
+%%% <ul>
+%%%  <li>[https://www.postgresql.org/docs/current/static/sasl-authentication.html]</li>
+%%%  <li>[https://en.wikipedia.org/wiki/Salted_Challenge_Response_Authentication_Mechanism]</li>
+%%%  <li>[https://tools.ietf.org/html/rfc7677]</li>
+%%%  <li>[https://tools.ietf.org/html/rfc5802]</li>
+%%% </ul>
 %%% @end
 
 -module(epgsql_scram).

+ 26 - 12
src/epgsql_sock.erl

@@ -1,25 +1,39 @@
-%%% Copyright (C) 2009 - Will Glozer.  All rights reserved.
-%%% Copyright (C) 2011 - Anton Lebedevich.  All rights reserved.
-
-%%% @doc GenServer holding all connection state (including socket).
+%%% @doc GenServer holding all the connection state (including socket).
+%%%
+%%% See [https://www.postgresql.org/docs/current/static/protocol-flow.html]
 %%%
-%%% See https://www.postgresql.org/docs/current/static/protocol-flow.html
-%%% Commands in PostgreSQL are pipelined: you don't need to wait for reply to
-%%% be able to send next command.
+%%% Commands in PostgreSQL protocol are pipelined: you don't have to wait for
+%%% reply to be able to send next command.
 %%% Commands are processed (and responses to them are generated) in FIFO order.
 %%% eg, if you execute 2 SimpleQuery: #1 and #2, first you get all response
 %%% packets for #1 and then all for #2:
+%%% ```
 %%% > SQuery #1
 %%% > SQuery #2
 %%% < RowDescription #1
-%%% < DataRow #1
+%%% < DataRow #1.1
+%%% < ...
+%%% < DataRow #1.N
 %%% < CommandComplete #1
 %%% < RowDescription #2
-%%% < DataRow #2
+%%% < DataRow #2.1
+%%% < ...
+%%% < DataRow #2.N
 %%% < CommandComplete #2
-%%%
-%%% See epgsql_cmd_connect for network connection and authentication setup
-
+%%% '''
+%%% `epgsql_sock' is capable of utilizing the pipelining feature - as soon as
+%%% it receives a new command, it sends it to the server immediately and then
+%%% it puts command's callbacks and state into internal queue of all the commands
+%%% which were sent to the server and waiting for response. So it knows in which
+%%% order it should call each pipelined command's `handle_message' callback.
+%%% But it can be easily broken if high-level command is poorly implemented or
+%%% some conflicting low-level commands (such as `parse', `bind', `execute') are
+%%% executed in a wrong order. In this case server and epgsql states become out of
+%%% sync and {@link epgsql_cmd_sync} have to be executed in order to recover.
+%%% @see epgsql_cmd_connect. epgsql_cmd_connect for network connection and authentication setup
+%%% @end
+%%% Copyright (C) 2009 - Will Glozer.  All rights reserved.
+%%% Copyright (C) 2011 - Anton Lebedevich.  All rights reserved.
 
 -module(epgsql_sock).
 

+ 9 - 1
src/epgsql_wire.erl

@@ -1,3 +1,9 @@
+%%% @doc
+%%% Interface to encoder/decoder for postgresql
+%%% <a href="https://www.postgresql.org/docs/current/protocol-message-formats.html">wire-protocol</a>
+%%%
+%%% See also `include/protocol.hrl'.
+%%% @end
 %%% Copyright (C) 2009 - Will Glozer.  All rights reserved.
 %%% Copyright (C) 2011 - Anton Lebedevich.  All rights reserved.
 
@@ -25,6 +31,7 @@
 
 -opaque row_decoder() :: {[epgsql_binary:decoder()], [epgsql:column()], epgsql_binary:codec()}.
 
+%% @doc tries to extract single postgresql packet from TCP stream
 -spec decode_message(binary()) -> {byte(), binary(), binary()} | binary().
 decode_message(<<Type:8, Len:?int32, Rest/binary>> = Bin) ->
     Len2 = Len - 4,
@@ -65,7 +72,7 @@ decode_fields(<<Type:8, Rest/binary>>, Acc) ->
     decode_fields(Rest2, [{Type, Str} | Acc]).
 
 %% @doc decode ErrorResponse
-%% See http://www.postgresql.org/docs/current/interactive/protocol-error-fields.html
+%% See [http://www.postgresql.org/docs/current/interactive/protocol-error-fields.html]
 -spec decode_error(binary()) -> epgsql:query_error().
 decode_error(Bin) ->
     Fields = decode_fields(Bin),
@@ -219,6 +226,7 @@ encode_formats([], Count, Acc) ->
 encode_formats([#column{format = Format} | T], Count, Acc) ->
     encode_formats(T, Count + 1, <<Acc/binary, Format:?int16>>).
 
+%% @doc Returns 1 if Codec knows how to decode binary format of the type provided and 0 otherwise
 format({unknown_oid, _}, _) -> 0;
 format(#column{oid = Oid}, Codec) ->
     case epgsql_binary:supports(Oid, Codec) of

+ 7 - 0
src/epgsqla.erl

@@ -1,3 +1,10 @@
+%%% @doc
+%%% Asynchronous interface.
+%%%
+%%% All the functions return `reference()' immediately. Results are delivered
+%%% asynchronously in a form of `{connection(), reference(), Result}', where
+%%% `Result' is what synchronous version of this function normally returns.
+%%% @end
 %%% Copyright (C) 2011 - Anton Lebedevich.  All rights reserved.
 
 -module(epgsqla).

+ 7 - 0
src/epgsqli.erl

@@ -1,3 +1,10 @@
+%%% @doc Incremental interface
+%%%
+%%% All the functions return `reference()' immediately. Each data row as well
+%%% as metadata are delivered as separate messages in a form of
+%%% `{connection(), reference(), Payload}' where `Payload' depends on command
+%%% being executed.
+%%% @end
 %%% Copyright (C) 2011 - Anton Lebedevich.  All rights reserved.
 
 -module(epgsqli).

+ 7 - 2
src/ewkb.erl

@@ -1,5 +1,10 @@
-%% https://en.wikipedia.org/wiki/Well-known_text
-%% http://postgis.net/docs/manual-2.4/using_postgis_dbmanagement.html#EWKB_EWKT
+%% @doc
+%% Encoder/decoder for PostGIS binary data representation.
+%%
+%% <ul>
+%%  <li>[https://en.wikipedia.org/wiki/Well-known_text]</li>
+%%  <li>[http://postgis.net/docs/manual-2.4/using_postgis_dbmanagement.html#EWKB_EWKT]</li>
+%% </ul>
 -module(ewkb).
 -export([decode_geometry/1, encode_geometry/1]).
 -export_type([point_type/0, point/1, multi_point/1, line_string/1,