pgsql_wire.erl 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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. [<<>> | T] = lists:reverse(binary:split(Bin, <<0>>, [global])),
  31. lists:reverse(T).
  32. %% decode field
  33. decode_fields(Bin) ->
  34. decode_fields(Bin, []).
  35. decode_fields(<<0>>, Acc) ->
  36. Acc;
  37. decode_fields(<<Type:8, Rest/binary>>, Acc) ->
  38. [Str, Rest2] = decode_string(Rest),
  39. decode_fields(Rest2, [{Type, Str} | Acc]).
  40. %% decode ErrorResponse
  41. %% TODO add fields from http://www.postgresql.org/docs/9.0/interactive/protocol-error-fields.html
  42. decode_error(Bin) ->
  43. Fields = decode_fields(Bin),
  44. Error = #error{
  45. severity = lower_atom(proplists:get_value($S, Fields)),
  46. code = proplists:get_value($C, Fields),
  47. message = proplists:get_value($M, Fields),
  48. extra = decode_error_extra(Fields)},
  49. Error.
  50. decode_error_extra(Fields) ->
  51. Types = [{$D, detail}, {$H, hint}, {$P, position}],
  52. decode_error_extra(Types, Fields, []).
  53. decode_error_extra([], _Fields, Extra) ->
  54. Extra;
  55. decode_error_extra([{Type, Name} | T], Fields, Extra) ->
  56. case proplists:get_value(Type, Fields) of
  57. undefined -> decode_error_extra(T, Fields, Extra);
  58. Value -> decode_error_extra(T, Fields, [{Name, Value} | Extra])
  59. end.
  60. lower_atom(Str) when is_binary(Str) ->
  61. lower_atom(binary_to_list(Str));
  62. lower_atom(Str) when is_list(Str) ->
  63. list_to_atom(string:to_lower(Str)).
  64. encode(Data) ->
  65. Bin = iolist_to_binary(Data),
  66. <<(byte_size(Bin) + 4):?int32, Bin/binary>>.
  67. encode(Type, Data) ->
  68. Bin = iolist_to_binary(Data),
  69. <<Type:8, (byte_size(Bin) + 4):?int32, Bin/binary>>.