Browse Source

Try to not convert iolists to binary for text/varchar/bytea types

Сергей Прохоров 7 years ago
parent
commit
b9ea711fb8
2 changed files with 15 additions and 3 deletions
  1. 10 2
      src/datatypes/epgsql_codec_text.erl
  2. 5 1
      test/epgsql_SUITE.erl

+ 10 - 2
src/datatypes/epgsql_codec_text.erl

@@ -15,7 +15,7 @@
 -export_type([data/0]).
 
 -type data() :: in_data() | out_data().
--type in_data() :: binary() | string().
+-type in_data() :: binary() | iolist() | string().
 -type out_data() :: binary().
 
 init(_, _) -> [].
@@ -24,7 +24,15 @@ names() ->
     [text, varchar, bytea].
 
 encode(String, Name, State) when is_list(String) ->
-    encode(list_to_binary(String), Name, State);
+    %% Try to not convert iolists to binary; this way they will be written directly to socket
+    %% But we are doing implicit check that iolist is well formed by calling
+    %% relatively cheap iolist_size/1 on it
+    try iolist_size(String) of
+        _ -> String
+    catch error:badarg when Name == varchar orelse Name == text ->
+            %% Maybe it's a unicode string; try to convert it to bytes
+            encode(unicode:characters_to_binary(String), Name, State)
+    end;
 encode(Bin, _, _) when is_binary(Bin) -> Bin;
 encode(Other, _Name, _State) ->
     %% This is for backward compatibitlty! Maybe add warning?

+ 5 - 1
test/epgsql_SUITE.erl

@@ -670,11 +670,15 @@ character_type(Config) ->
     check_type(Config, bpchar, "'A'", $A, [1, $1, 16#7F, Alpha, Ka, One], "c_char"),
     check_type(Config, text, "'hi'", <<"hi">>, [<<"">>, <<"hi">>]),
     check_type(Config, varchar, "'hi'", <<"hi">>, [<<"">>, <<"hi">>]),
-    %% Deprecated casts
     epgsql_ct:with_connection(
       Config,
       fun(C) ->
               Module = ?config(module, Config),
+              %% IOlists
+              ?assertMatch({ok, _, [{<<1087/utf8, 1088/utf8, 1080/utf8,
+                                        1074/utf8, 1077/utf8, 1090/utf8>>}]},
+                           Module:equery(C, "SELECT $1::text", [[1087,1088,1080,1074,1077,1090]])),
+              %% Deprecated casts
               ?assertMatch({ok, _, [{<<"my_atom">>}]},
                            Module:equery(C, "SELECT $1::varchar", [my_atom])),
               ?assertMatch({ok, _, [{<<"12345">>}]},