pgsql_wire.erl 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. -module(pgsql_wire).
  2. -export([decode_message/1,
  3. decode_error/1,
  4. decode_strings/1,
  5. encode/1,
  6. encode/2]).
  7. -include("pgsql.hrl").
  8. -include("pgsql_binary.hrl").
  9. decode_message(<<Type:8, Len:?int32, Rest/binary>> = Bin) ->
  10. Len2 = Len - 4,
  11. case Rest of
  12. <<Data:Len2/binary, Tail/binary>> ->
  13. case Type of
  14. $E ->
  15. {{error, decode_error(Data)}, Tail};
  16. _ ->
  17. {{Type, Data}, Tail}
  18. end;
  19. _Other ->
  20. Bin
  21. end;
  22. decode_message(Bin) ->
  23. Bin.
  24. %% decode a single null-terminated string
  25. %% TODO signature changed, returns [Str, Rest], old code expects {Str, Rest}
  26. decode_string(Bin) ->
  27. binary:split(Bin, <<0>>).
  28. %% decode multiple null-terminated string
  29. decode_strings(Bin) ->
  30. binary:split(Bin, <<0>>, [global, trim]).
  31. %% decode field
  32. decode_fields(Bin) ->
  33. decode_fields(Bin, []).
  34. decode_fields(<<0>>, Acc) ->
  35. Acc;
  36. decode_fields(<<Type:8, Rest/binary>>, Acc) ->
  37. [Str, Rest2] = decode_string(Rest),
  38. decode_fields(Rest2, [{Type, Str} | Acc]).
  39. %% decode ErrorResponse
  40. %% TODO add fields from http://www.postgresql.org/docs/9.0/interactive/protocol-error-fields.html
  41. decode_error(Bin) ->
  42. Fields = decode_fields(Bin),
  43. Error = #error{
  44. severity = lower_atom(proplists:get_value($S, Fields)),
  45. code = proplists:get_value($C, Fields),
  46. message = proplists:get_value($M, Fields),
  47. extra = decode_error_extra(Fields)},
  48. Error.
  49. decode_error_extra(Fields) ->
  50. Types = [{$D, detail}, {$H, hint}, {$P, position}],
  51. decode_error_extra(Types, Fields, []).
  52. decode_error_extra([], _Fields, Extra) ->
  53. Extra;
  54. decode_error_extra([{Type, Name} | T], Fields, Extra) ->
  55. case proplists:get_value(Type, Fields) of
  56. undefined -> decode_error_extra(T, Fields, Extra);
  57. Value -> decode_error_extra(T, Fields, [{Name, Value} | Extra])
  58. end.
  59. lower_atom(Str) when is_binary(Str) ->
  60. lower_atom(binary_to_list(Str));
  61. lower_atom(Str) when is_list(Str) ->
  62. list_to_atom(string:to_lower(Str)).
  63. encode(Data) ->
  64. Bin = iolist_to_binary(Data),
  65. <<(byte_size(Bin) + 4):?int32, Bin/binary>>.
  66. encode(Type, Data) ->
  67. Bin = iolist_to_binary(Data),
  68. <<Type:8, (byte_size(Bin) + 4):?int32, Bin/binary>>.