mysql_text_protocol.erl 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. %% MySQL/OTP – a MySQL driver for Erlang/OTP
  2. %% Copyright (C) 2014 Viktor Söderqvist
  3. %%
  4. %% This program is free software: you can redistribute it and/or modify
  5. %% it under the terms of the GNU General Public License as published by
  6. %% the Free Software Foundation, either version 3 of the License, or
  7. %% (at your option) any later version.
  8. %%
  9. %% This program is distributed in the hope that it will be useful,
  10. %% but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. %% GNU General Public License for more details.
  13. %%
  14. %% You should have received a copy of the GNU General Public License
  15. %% along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. %% @doc This module handles conversion of values in the form they are
  17. %% represented in the text protocol to our prefered Erlang term representations.
  18. -module(mysql_text_protocol).
  19. -export([text_to_term/2]).
  20. -include("records.hrl").
  21. -include("protocol.hrl"). %% The TYPE_* macros.
  22. %% @doc When receiving data in the text protocol, we get everything as binaries
  23. %% (except NULL). This function is used to parse these strings values.
  24. text_to_term(Type, Text) when is_binary(Text) ->
  25. case Type of
  26. ?TYPE_DECIMAL -> parse_float(Text); %% <-- this will probably change
  27. ?TYPE_TINY -> binary_to_integer(Text);
  28. ?TYPE_SHORT -> binary_to_integer(Text);
  29. ?TYPE_LONG -> binary_to_integer(Text);
  30. ?TYPE_FLOAT -> parse_float(Text);
  31. ?TYPE_DOUBLE -> parse_float(Text);
  32. ?TYPE_TIMESTAMP -> parse_datetime(Text);
  33. ?TYPE_LONGLONG -> binary_to_integer(Text);
  34. ?TYPE_INT24 -> binary_to_integer(Text);
  35. ?TYPE_DATE -> parse_date(Text);
  36. ?TYPE_TIME -> parse_time(Text);
  37. ?TYPE_DATETIME -> parse_datetime(Text);
  38. ?TYPE_YEAR -> binary_to_integer(Text);
  39. ?TYPE_VARCHAR -> Text;
  40. ?TYPE_BIT -> binary_to_integer(Text);
  41. ?TYPE_NEWDECIMAL -> parse_float(Text); %% <-- this will probably change
  42. ?TYPE_ENUM -> Text;
  43. ?TYPE_SET when Text == <<>> -> sets:new();
  44. ?TYPE_SET -> sets:from_list(binary:split(Text, <<",">>, [global]));
  45. ?TYPE_TINY_BLOB -> Text; %% charset?
  46. ?TYPE_MEDIUM_BLOB -> Text;
  47. ?TYPE_LONG_BLOB -> Text;
  48. ?TYPE_BLOB -> Text;
  49. ?TYPE_VAR_STRING -> Text;
  50. ?TYPE_STRING -> Text;
  51. ?TYPE_GEOMETRY -> Text %% <-- what do we want here?
  52. end;
  53. text_to_term(_, null) ->
  54. %% NULL is the only value not represented as a binary.
  55. null.
  56. parse_datetime(<<Y:4/binary, "-", M:2/binary, "-", D:2/binary, " ",
  57. H:2/binary, ":", Mi:2/binary, ":", S:2/binary>>) ->
  58. {{binary_to_integer(Y), binary_to_integer(M), binary_to_integer(D)},
  59. {binary_to_integer(H), binary_to_integer(Mi), binary_to_integer(S)}}.
  60. parse_date(<<Y:4/binary, "-", M:2/binary, "-", D:2/binary>>) ->
  61. {binary_to_integer(Y), binary_to_integer(M), binary_to_integer(D)}.
  62. parse_time(<<H:2/binary, ":", Mi:2/binary, ":", S:2/binary>>) ->
  63. {binary_to_integer(H), binary_to_integer(Mi), binary_to_integer(S)}.
  64. parse_float(Text) ->
  65. try binary_to_float(Text)
  66. catch error:badarg ->
  67. try binary_to_integer(Text) of
  68. Int -> float(Int)
  69. catch error:badarg ->
  70. %% It is something like "4e75" that must be turned into "4.0e75"
  71. binary_to_float(binary:replace(Text, <<"e">>, <<".0e">>))
  72. end
  73. end.
  74. -ifdef(TEST).
  75. -include_lib("eunit/include/eunit.hrl").
  76. text_to_term_test() ->
  77. %% Int types
  78. lists:foreach(fun (T) -> ?assertEqual(1, text_to_term(T, <<"1">>)) end,
  79. [?TYPE_TINY, ?TYPE_SHORT, ?TYPE_LONG, ?TYPE_LONGLONG,
  80. ?TYPE_INT24, ?TYPE_YEAR, ?TYPE_BIT]),
  81. %% Floating point and decimal numbers
  82. lists:foreach(fun (T) -> ?assertEqual(3.0, text_to_term(T, <<"3.0">>)) end,
  83. [?TYPE_FLOAT, ?TYPE_DOUBLE, ?TYPE_DECIMAL, ?TYPE_NEWDECIMAL]),
  84. ?assertEqual(3.0, text_to_term(?TYPE_FLOAT, <<"3">>)),
  85. ?assertEqual(30.0, text_to_term(?TYPE_FLOAT, <<"3e1">>)),
  86. ?assertEqual(3, text_to_term(?TYPE_LONG, <<"3">>)),
  87. %% Date and time
  88. ?assertEqual({2014, 11, 01}, text_to_term(?TYPE_DATE, <<"2014-11-01">>)),
  89. ?assertEqual({23, 59, 01}, text_to_term(?TYPE_TIME, <<"23:59:01">>)),
  90. ?assertEqual({{2014, 11, 01}, {23, 59, 01}},
  91. text_to_term(?TYPE_DATETIME, <<"2014-11-01 23:59:01">>)),
  92. ?assertEqual({{2014, 11, 01}, {23, 59, 01}},
  93. text_to_term(?TYPE_TIMESTAMP, <<"2014-11-01 23:59:01">>)),
  94. %% Strings and blobs
  95. lists:foreach(fun (T) ->
  96. ?assertEqual(<<"x">>, text_to_term(T, <<"x">>))
  97. end,
  98. [?TYPE_VARCHAR, ?TYPE_ENUM, ?TYPE_TINY_BLOB,
  99. ?TYPE_MEDIUM_BLOB, ?TYPE_LONG_BLOB, ?TYPE_BLOB,
  100. ?TYPE_VAR_STRING, ?TYPE_STRING, ?TYPE_GEOMETRY]),
  101. %% Set
  102. ?assertEqual(sets:from_list([<<"b">>, <<"a">>]),
  103. text_to_term(?TYPE_SET, <<"a,b">>)),
  104. ?assertEqual(sets:from_list([]), text_to_term(?TYPE_SET, <<>>)),
  105. %% NULL
  106. ?assertEqual(null, text_to_term(?TYPE_FLOAT, null)),
  107. ok.
  108. -endif.