12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- %% @doc Asks server to parse SQL query and send information aboud bind-parameters and result columns.
- %%
- %% ```
- %% > Parse
- %% < ParseComplete
- %% > Describe
- %% < ParameterDescription
- %% < RowDescription | NoData
- %% '''
- -module(epgsql_cmd_parse).
- -behaviour(epgsql_command).
- -export([init/1, execute/2, handle_message/4]).
- -export_type([response/0]).
- -include("epgsql.hrl").
- -include("protocol.hrl").
- -type response() :: {ok, #statement{}} | {error, epgsql:query_error()}.
- -record(parse,
- {name :: iodata(),
- sql :: iodata(),
- types :: [atom()],
- parameter_typenames = [] :: [epgsql:type_name() | {array, epgsql:type_name()}],
- parameter_descr = [] :: [epgsql_oid_db:oid_info()]}).
- %% FIXME: make it use oids instead of type names!
- init({Name, Sql, Types}) ->
- #parse{name = Name, sql = Sql, types = Types}.
- execute(Sock, #parse{name = Name, sql = Sql, types = Types} = St) ->
- Codec = epgsql_sock:get_codec(Sock),
- Bin = epgsql_wire:encode_types(Types, Codec),
- epgsql_sock:send_multi(
- Sock,
- [
- {?PARSE, [Name, 0, Sql, 0, Bin]},
- {?DESCRIBE, [?PREPARED_STATEMENT, Name, 0]},
- {?FLUSH, []}
- ]),
- {ok, Sock, St}.
- handle_message(?PARSE_COMPLETE, <<>>, Sock, _State) ->
- {noaction, Sock};
- handle_message(?PARAMETER_DESCRIPTION, Bin, Sock, State) ->
- Codec = epgsql_sock:get_codec(Sock),
- TypeInfos = epgsql_wire:decode_parameters(Bin, Codec),
- OidInfos = [epgsql_binary:typeinfo_to_oid_info(Type, Codec) || Type <- TypeInfos],
- TypeNames = [epgsql_binary:typeinfo_to_name_array(Type, Codec) || Type <- TypeInfos],
- Sock2 = epgsql_sock:notify(Sock, {types, TypeNames}),
- {noaction, Sock2, State#parse{parameter_descr = OidInfos,
- parameter_typenames = TypeNames}};
- handle_message(?ROW_DESCRIPTION, <<Count:?int16, Bin/binary>>, Sock,
- #parse{name = Name, parameter_descr = Params,
- parameter_typenames = TypeNames}) ->
- Codec = epgsql_sock:get_codec(Sock),
- Columns = epgsql_wire:decode_columns(Count, Bin, Codec),
- Columns2 = [Col#column{format = epgsql_wire:format(Col, Codec)}
- || Col <- Columns],
- Result = {ok, #statement{name = Name,
- types = TypeNames,
- columns = Columns2,
- parameter_info = Params}},
- {finish, Result, {columns, Columns2}, Sock};
- handle_message(?NO_DATA, <<>>, Sock, #parse{name = Name, parameter_descr = Params,
- parameter_typenames = TypeNames}) ->
- Result = {ok, #statement{name = Name,
- types = TypeNames,
- parameter_info = Params,
- columns = []}},
- {finish, Result, no_data, Sock};
- handle_message(?ERROR, Error, _Sock, _State) ->
- Result = {error, Error},
- {sync_required, Result};
- handle_message(_, _, _, _) ->
- unknown.
|