%% > Bind %% < BindComplete %% > Execute %% < DataRow* %% < CommandComplete %% > Close %% < CloseComplete %% > Sync %% < ReadyForQuery -module(epgsql_cmd_equery). -behaviour(epgsql_command). -export([init/1, execute/2, handle_message/4]). -export_type([response/0]). -type response() :: {ok, Count :: non_neg_integer(), Cols :: [epgsql:column()], Rows :: [tuple()]} | {ok, Count :: non_neg_integer()} | {ok, Cols :: [epgsql:column()], Rows :: [tuple()]} | {error, epgsql:query_error()}. -include("epgsql.hrl"). -include("protocol.hrl"). -record(equery, {stmt :: #statement{}, params :: list(), decoder}). init({Stmt, TypedParams}) -> #equery{stmt = Stmt, params = TypedParams}. execute(Sock, #equery{stmt = Stmt, params = TypedParams} = St) -> #statement{name = StatementName, columns = Columns} = Stmt, Codec = epgsql_sock:get_codec(Sock), Bin1 = epgsql_wire:encode_parameters(TypedParams, Codec), Bin2 = epgsql_wire:encode_formats(Columns), epgsql_sock:send_multi( Sock, [ {?BIND, ["", 0, StatementName, 0, Bin1, Bin2]}, {?EXECUTE, ["", 0, <<0:?int32>>]}, {?CLOSE, [?PREPARED_STATEMENT, StatementName, 0]}, {?SYNC, []} ]), {ok, Sock, St}. handle_message(?BIND_COMPLETE, <<>>, Sock, #equery{stmt = Stmt} = State) -> #statement{columns = Columns} = Stmt, epgsql_sock:notify(Sock, {columns, Columns}), % Why do we need this? Codec = epgsql_sock:get_codec(Sock), Decoder = epgsql_wire:build_decoder(Columns, Codec), {noaction, Sock, State#equery{decoder = Decoder}}; handle_message(?DATA_ROW, <<_Count:?int16, Bin/binary>>, Sock, #equery{decoder = Decoder} = St) -> Row = epgsql_wire:decode_data(Bin, Decoder), {add_row, Row, Sock, St}; handle_message(?EMPTY_QUERY, <<>>, Sock, St) -> {add_result, {ok, [], []}, {complete, empty}, Sock, St}; handle_message(?COMMAND_COMPLETE, Bin, Sock, #equery{stmt = Stmt} = St) -> Complete = epgsql_wire:decode_complete(Bin), #statement{columns = Cols} = Stmt, Rows = epgsql_sock:get_rows(Sock), Result = case Complete of {_, Count} when Cols == [] -> {ok, Count}; {_, Count} -> {ok, Count, Cols, Rows}; _ -> {ok, Cols, Rows} end, {add_result, Result, {complete, Complete}, Sock, St}; handle_message(?CLOSE_COMPLETE, _, Sock, _State) -> {noaction, Sock}; handle_message(?READY_FOR_QUERY, _Status, Sock, _State) -> case epgsql_sock:get_results(Sock) of [Result] -> {finish, Result, done, Sock}; [] -> {finish, done, done, Sock} end; handle_message(?ERROR, Error, Sock, St) -> Result = {error, Error}, {add_result, Result, Result, Sock, St}; handle_message(_, _, _, _) -> unknown.