epgsql_cmd_parse.erl 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. %% > Parse
  2. %% < ParseComplete
  3. %% > Describe
  4. %% < ParameterDescription
  5. %% < RowDescription | NoData
  6. -module(epgsql_cmd_parse).
  7. -behaviour(epgsql_command).
  8. -export([init/1, execute/2, handle_message/4]).
  9. -export_type([response/0]).
  10. -include("epgsql.hrl").
  11. -include("protocol.hrl").
  12. -type response() :: {ok, #statement{}} | {error, epgsql:query_error()}.
  13. -record(parse,
  14. {name :: iodata(),
  15. sql :: iodata(),
  16. types :: [atom()],
  17. parameter_typenames = [] :: [epgsql:type_name() | {array, epgsql:type_name()}],
  18. parameter_descr = [] :: [epgsql_oid_db:oid_info()]}).
  19. %% FIXME: make it use oids instead of type names!
  20. init({Name, Sql, Types}) ->
  21. #parse{name = Name, sql = Sql, types = Types}.
  22. execute(Sock, #parse{name = Name, sql = Sql, types = Types} = St) ->
  23. Codec = epgsql_sock:get_codec(Sock),
  24. Bin = epgsql_wire:encode_types(Types, Codec),
  25. epgsql_sock:send_multi(
  26. Sock,
  27. [
  28. {?PARSE, [Name, 0, Sql, 0, Bin]},
  29. {?DESCRIBE, [?PREPARED_STATEMENT, Name, 0]},
  30. {?FLUSH, []}
  31. ]),
  32. {ok, Sock, St}.
  33. handle_message(?PARSE_COMPLETE, <<>>, Sock, _State) ->
  34. {noaction, Sock};
  35. handle_message(?PARAMETER_DESCRIPTION, Bin, Sock, State) ->
  36. Codec = epgsql_sock:get_codec(Sock),
  37. TypeInfos = epgsql_wire:decode_parameters(Bin, Codec),
  38. OidInfos = [epgsql_binary:typeinfo_to_oid_info(Type, Codec) || Type <- TypeInfos],
  39. TypeNames = [epgsql_binary:typeinfo_to_name_array(Type, Codec) || Type <- TypeInfos],
  40. Sock2 = epgsql_sock:notify(Sock, {types, TypeNames}),
  41. {noaction, Sock2, State#parse{parameter_descr = OidInfos,
  42. parameter_typenames = TypeNames}};
  43. handle_message(?ROW_DESCRIPTION, <<Count:?int16, Bin/binary>>, Sock,
  44. #parse{name = Name, parameter_descr = Params,
  45. parameter_typenames = TypeNames}) ->
  46. Codec = epgsql_sock:get_codec(Sock),
  47. Columns = epgsql_wire:decode_columns(Count, Bin, Codec),
  48. Columns2 = [Col#column{format = epgsql_wire:format(Col, Codec)}
  49. || Col <- Columns],
  50. Result = {ok, #statement{name = Name,
  51. types = TypeNames,
  52. columns = Columns2,
  53. parameter_info = Params}},
  54. {finish, Result, {columns, Columns2}, Sock};
  55. handle_message(?NO_DATA, <<>>, Sock, #parse{name = Name, parameter_descr = Params,
  56. parameter_typenames = TypeNames}) ->
  57. Result = {ok, #statement{name = Name,
  58. types = TypeNames,
  59. parameter_info = Params,
  60. columns = []}},
  61. {finish, Result, no_data, Sock};
  62. handle_message(?ERROR, Error, _Sock, _State) ->
  63. Result = {error, Error},
  64. {sync_required, Result};
  65. handle_message(_, _, _, _) ->
  66. unknown.