Use binary:replace instead of re:replace to handle Latin-1 binaries

Fixes #43
This commit is contained in:
Alexey Romanov
2015-12-21 15:21:02 +03:00
parent 8350dc6038
commit cbc3505f7a
2 changed files with 23 additions and 15 deletions

View File

@@ -13,7 +13,7 @@
%% API %% API
-export([col_type_to_atom/1]). -export([col_type_to_atom/1]).
-export([value_to_sql/1, value_to_sql_unsafe/1, sql_to_value/1, escape/1, bin_to_hex/1]). -export([value_to_sql/1, value_to_sql_unsafe/1, sql_to_value/1, bin_to_hex/1]).
-export([write_value_sql/1, write_col_sql/1]). -export([write_value_sql/1, write_col_sql/1]).
-export([create_table_sql/2, create_table_sql/3, drop_table_sql/1]). -export([create_table_sql/2, create_table_sql/3, drop_table_sql/1]).
-export([add_columns_sql/2]). -export([add_columns_sql/2]).
@@ -74,15 +74,11 @@ col_type_to_atom(String) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec value_to_sql_unsafe(sql_value()) -> iolist(). -spec value_to_sql_unsafe(sql_value()) -> iolist().
value_to_sql_unsafe(X) -> value_to_sql_unsafe(X) ->
case X of if
_ when is_integer(X) -> integer_to_list(X); is_binary(X) orelse is_list(X) ->
_ when is_float(X) -> float_to_list(X); [$', binary_or_unicode_to_binary(X), $'];
true -> "1"; true ->
false -> "0"; value_to_sql(X)
undefined -> "NULL";
?NULL_ATOM -> "NULL";
{blob, Blob} -> ["x'", bin_to_hex(Blob), $'];
_ -> [$', unicode:characters_to_binary(X), $'] %% assumes no $' inside strings!
end. end.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@@ -104,7 +100,9 @@ value_to_sql(X) ->
undefined -> "NULL"; undefined -> "NULL";
?NULL_ATOM -> "NULL"; ?NULL_ATOM -> "NULL";
{blob, Blob} -> ["x'", bin_to_hex(Blob), $']; {blob, Blob} -> ["x'", bin_to_hex(Blob), $'];
_ -> [$', unicode:characters_to_binary(escape(X)), $'] _ when is_binary(X) orelse is_list(X) ->
Bin = binary_or_unicode_to_binary(X),
[$', binary:replace(Bin, <<"'">>, <<"''">>, [global]), $']
end. end.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@@ -151,15 +149,16 @@ write_col_sql(Cols) ->
%% @doc Returns copy of IoData with all ' replaced by '' %% @doc Returns copy of IoData with all ' replaced by ''
%% @end %% @end
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec escape(iodata()) -> iodata(). -spec binary_or_unicode_to_binary(binary() | unicode:charlist()) -> binary().
escape(IoData) -> re:replace(IoData, "'", "''", [global, unicode]). binary_or_unicode_to_binary(Bin) when is_binary(Bin) -> Bin;
binary_or_unicode_to_binary(CharList) when is_list(CharList) -> unicode:characters_to_binary(CharList).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @doc Converts a plain binary to its hexadecimal encoding, to be %% @doc Converts a plain binary to its hexadecimal encoding, to be
%% passed as a blob literal. %% passed as a blob literal.
%% @end %% @end
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec bin_to_hex(iodata()) -> binary(). -spec bin_to_hex(binary()) -> binary().
bin_to_hex(Binary) -> << <<(half_byte_to_hex(X)):8>> || <<X:4>> <= Binary>>. bin_to_hex(Binary) -> << <<(half_byte_to_hex(X)):8>> || <<X:4>> <= Binary>>.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------

View File

@@ -49,6 +49,7 @@ all_test_() ->
?FuncTest(nonexistent_table_info), ?FuncTest(nonexistent_table_info),
?FuncTest(large_number), ?FuncTest(large_number),
?FuncTest(unicode), ?FuncTest(unicode),
?FuncTest(latin1_binary),
?FuncTest(acc_string_encoding), ?FuncTest(acc_string_encoding),
?FuncTest(large_offset), ?FuncTest(large_offset),
?FuncTest(issue23), ?FuncTest(issue23),
@@ -171,7 +172,7 @@ parametrized() ->
negative() -> negative() ->
drop_table_if_exists(ct, negative), drop_table_if_exists(ct, negative),
sqlite3:create_table(ct, negative, [{id, int}]), sqlite3:create_table(ct, negative, [{id, int}]),
?assertEqual({error, badarg}, ?assertMatch({error, _},
sqlite3:write(ct, negative, [{id, bad_sql_value}])). sqlite3:write(ct, negative, [{id, bad_sql_value}])).
blob() -> blob() ->
@@ -254,6 +255,14 @@ unicode() ->
sqlite3:write(ct, unicode, [{str, UnicodeString}]), sqlite3:write(ct, unicode, [{str, UnicodeString}]),
?assertEqual([{unicode:characters_to_binary(UnicodeString)}], rows(sqlite3:read_all(ct, unicode))). ?assertEqual([{unicode:characters_to_binary(UnicodeString)}], rows(sqlite3:read_all(ct, unicode))).
latin1_binary() ->
Latin1String = <<"^PUjC^PUjC",176,230,176>>, %% "^PUjC^PUjC°æ°" in Latin-1
sqlite3:open(issue43, [in_memory]),
ok = sqlite3:create_table(issue43, issue43, [{str, text}]),
sqlite3:write(issue43, issue43, [{str, Latin1String}]),
?assertEqual([{Latin1String}], rows(sqlite3:read_all(issue43, issue43))),
sqlite3:close(issue43).
acc_string_encoding() -> acc_string_encoding() ->
?assertEqual([{62}], rows(sqlite3:sql_exec(ct, "SELECT ? + ?", [30,32]))). ?assertEqual([{62}], rows(sqlite3:sql_exec(ct, "SELECT ? + ?", [30,32]))).