epgsql_cmd_describe_statement.erl 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. %% @doc Asks server to provide input parameter and result rows information.
  2. %%
  3. %% Almost the same as {@link epgsql_cmd_parse}.
  4. %%
  5. %% ```
  6. %% > Describe(STATEMENT)
  7. %% < ParameterDescription
  8. %% < RowDescription | NoData
  9. %% '''
  10. -module(epgsql_cmd_describe_statement).
  11. -behaviour(epgsql_command).
  12. -export([init/1, execute/2, handle_message/4]).
  13. -export_type([response/0]).
  14. -include("epgsql.hrl").
  15. -include("protocol.hrl").
  16. -type response() :: {ok, #statement{}} | {error, epgsql:query_error()}.
  17. -record(desc_stmt,
  18. {name :: iodata(),
  19. parameter_typenames = [],
  20. parameter_descr = []}).
  21. init(Name) ->
  22. #desc_stmt{name = Name}.
  23. execute(Sock, #desc_stmt{name = Name} = St) ->
  24. epgsql_sock:send_multi(
  25. Sock,
  26. [
  27. {?DESCRIBE, [?PREPARED_STATEMENT, Name, 0]},
  28. {?FLUSH, []}
  29. ]),
  30. {ok, Sock, St}.
  31. handle_message(?PARAMETER_DESCRIPTION, Bin, Sock, State) ->
  32. Codec = epgsql_sock:get_codec(Sock),
  33. TypeInfos = epgsql_wire:decode_parameters(Bin, Codec),
  34. OidInfos = [epgsql_binary:typeinfo_to_oid_info(Type, Codec) || Type <- TypeInfos],
  35. TypeNames = [epgsql_binary:typeinfo_to_name_array(Type, Codec) || Type <- TypeInfos],
  36. Sock2 = epgsql_sock:notify(Sock, {types, TypeNames}),
  37. {noaction, Sock2, State#desc_stmt{parameter_descr = OidInfos,
  38. parameter_typenames = TypeNames}};
  39. handle_message(?ROW_DESCRIPTION, <<Count:?int16, Bin/binary>>, Sock,
  40. #desc_stmt{name = Name, parameter_descr = Params,
  41. parameter_typenames = TypeNames}) ->
  42. Codec = epgsql_sock:get_codec(Sock),
  43. Columns = epgsql_wire:decode_columns(Count, Bin, Codec),
  44. Columns2 = [Col#column{format = epgsql_wire:format(Col, Codec)}
  45. || Col <- Columns],
  46. Result = {ok, #statement{name = Name,
  47. types = TypeNames,
  48. parameter_info = Params,
  49. columns = Columns2}},
  50. {finish, Result, {columns, Columns2}, Sock};
  51. handle_message(?NO_DATA, <<>>, Sock, #desc_stmt{name = Name, parameter_descr = Params,
  52. parameter_typenames = TypeNames}) ->
  53. Result = {ok, #statement{name = Name,
  54. types = TypeNames,
  55. parameter_info = Params,
  56. columns = []}},
  57. {finish, Result, no_data, Sock};
  58. handle_message(?ERROR, Error, _Sock, _State) ->
  59. Result = {error, Error},
  60. {sync_required, Result};
  61. handle_message(_, _, _, _) ->
  62. unknown.