1%%% Behaviour module for epgsql_sock commands. 2%%% 3%%% Copyright (C) 2017 - Sergey Prokhorov. All rights reserved. 4 5-module(epgsql_command). 6-export([init/2, execute/3, handle_message/5]). 7 8-export_type([command/0, state/0]). 9 10-type command() :: module(). 11-type state() :: any(). 12 13%% Initialize command's state. Called when command is received by epgsql_sock process. 14-callback init(any()) -> state(). 15 16-type execute_return() :: 17 {ok, epgsql_sock:pg_sock(), state()} 18 | {stop, Reason :: any(), Response :: any(), epgsql_sock:pg_sock()}. 19%% Execute command. It should send commands to socket. 20%% May be called many times if 'handle_message' will return 'requeue'. 21-callback execute(epgsql_sock:pg_sock(), state()) -> execute_return(). 22 23-type handle_message_return() :: 24 {noaction, epgsql_sock:pg_sock()} 25 %% Do nothing; remember changed state 26 | {noaction, epgsql_sock:pg_sock(), state()} 27 %% Add result to resultset (eg, `{ok, Count}' `{ok, Cols, Rows}', `{error, #error{}}' 28 %% It may be returned many times for eg, `squery' with multiple 29 %% queries separated by ';' 30 %% See epgsql_sock:get_results/1 31 | {add_result, Data :: any(), Notification :: any(), epgsql_sock:pg_sock(), state()} 32 %% Add new row to current resultset; 33 %% See epgsql_sock:get_rows/1 34 | {add_row, tuple(), epgsql_sock:pg_sock(), state()} 35 %% Finish command execution, reply to the client and go to next command 36 | {finish, Result :: any(), Notification :: any(), epgsql_sock:pg_sock()} 37 %% Stop `epgsql_sock' process 38 | {stop, Reason :: any(), Response :: any(), epgsql_sock:pg_sock()} 39 %% Call 'execute' and reschedule command. 40 %% It's forbidden to call epgsql_sock:send from `handle_message'. 41 %% If you need to do so, you should set some flag in state and 42 %% reschedule command. 43 %% See `epgsql_cmd_connect' for reference. 44 | {requeue, epgsql_sock:pg_sock(), state()} 45 %% Protocol synchronization error (eg, unexpected packet) 46 %% Drop command queue and don't accept any command except 'sync' 47 | {sync_required, Why :: any()} 48 %% Unknown packet. Terminate `epgsql_sock' process 49 | unknown. 50%% Handle incoming packet 51-callback handle_message(Type :: byte(), Payload :: binary() | epgsql:query_error(), 52 epgsql_sock:pg_sock(), state()) -> handle_message_return(). 53 54-spec init(command(), any()) -> state(). 55init(Command, Args) -> 56 Command:init(Args). 57 58-spec execute(command(), epgsql_sock:pg_sock(), state()) -> execute_return(). 59execute(Command, PgSock, CmdState) -> 60 Command:execute(PgSock, CmdState). 61 62-spec handle_message(command(), Type :: byte(), Payload :: binary() | epgsql:query_error(), 63 epgsql_sock:pg_sock(), state()) -> handle_message_return(). 64handle_message(Command, Type, Payload, PgSock, State) -> 65 Command:handle_message(Type, Payload, PgSock, State). 66