|
@@ -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).
|
|
@@ -448,18 +460,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).
|