epgsql_cmd_describe_statement.erl 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. %% Almost the same as "parse"
  2. %% > Describe
  3. %% < ParameterDescription
  4. %% < RowDescription | NoData
  5. -module(epgsql_cmd_describe_statement).
  6. -behaviour(epgsql_command).
  7. -export([init/1, execute/2, handle_message/4]).
  8. -export_type([response/0]).
  9. -include("epgsql.hrl").
  10. -include("protocol.hrl").
  11. -type response() :: {ok, #statement{}} | {error, epgsql:query_error()}.
  12. -record(desc_stmt,
  13. {name :: iodata(),
  14. parameter_descr}).
  15. init(Name) ->
  16. #desc_stmt{name = Name}.
  17. execute(Sock, #desc_stmt{name = Name} = St) ->
  18. epgsql_sock:send_multi(
  19. Sock,
  20. [
  21. {?DESCRIBE, [?PREPARED_STATEMENT, Name, 0]},
  22. {?FLUSH, []}
  23. ]),
  24. {ok, Sock, St}.
  25. handle_message(?PARAMETER_DESCRIPTION, Bin, Sock, State) ->
  26. Codec = epgsql_sock:get_codec(Sock),
  27. Types = epgsql_wire:decode_parameters(Bin, Codec),
  28. Sock2 = epgsql_sock:notify(Sock, {types, Types}),
  29. {noaction, Sock2, State#desc_stmt{parameter_descr = Types}};
  30. handle_message(?ROW_DESCRIPTION, <<Count:?int16, Bin/binary>>, Sock,
  31. #desc_stmt{name = Name, parameter_descr = Params}) ->
  32. Codec = epgsql_sock:get_codec(Sock),
  33. Columns = epgsql_wire:decode_columns(Count, Bin, Codec),
  34. Columns2 = [Col#column{format = epgsql_wire:format(Col#column.type, Codec)}
  35. || Col <- Columns],
  36. Result = {ok, #statement{name = Name, types = Params, columns = Columns2}},
  37. {finish, Result, {columns, Columns2}, Sock};
  38. handle_message(?NO_DATA, <<>>, Sock, #desc_stmt{name = Name, parameter_descr = Params}) ->
  39. Result = {ok, #statement{name = Name, types = Params, columns = []}},
  40. {finish, Result, no_data, Sock};
  41. handle_message(?ERROR, Error, _Sock, _State) ->
  42. Result = {error, Error},
  43. {sync_required, Result};
  44. handle_message(_, _, _, _) ->
  45. unknown.