From cbc3505f7a131254265d3ef56191b2581b8cc172 Mon Sep 17 00:00:00 2001 From: Alexey Romanov Date: Mon, 21 Dec 2015 15:21:02 +0300 Subject: [PATCH] Use binary:replace instead of re:replace to handle Latin-1 binaries Fixes #43 --- src/sqlite3_lib.erl | 27 +++++++++++++-------------- test/sqlite3_test.erl | 11 ++++++++++- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/sqlite3_lib.erl b/src/sqlite3_lib.erl index 7f543d1..3244247 100644 --- a/src/sqlite3_lib.erl +++ b/src/sqlite3_lib.erl @@ -13,7 +13,7 @@ %% API -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([create_table_sql/2, create_table_sql/3, drop_table_sql/1]). -export([add_columns_sql/2]). @@ -74,15 +74,11 @@ col_type_to_atom(String) -> %%-------------------------------------------------------------------- -spec value_to_sql_unsafe(sql_value()) -> iolist(). value_to_sql_unsafe(X) -> - case X of - _ when is_integer(X) -> integer_to_list(X); - _ when is_float(X) -> float_to_list(X); - true -> "1"; - false -> "0"; - undefined -> "NULL"; - ?NULL_ATOM -> "NULL"; - {blob, Blob} -> ["x'", bin_to_hex(Blob), $']; - _ -> [$', unicode:characters_to_binary(X), $'] %% assumes no $' inside strings! + if + is_binary(X) orelse is_list(X) -> + [$', binary_or_unicode_to_binary(X), $']; + true -> + value_to_sql(X) end. %%-------------------------------------------------------------------- @@ -104,7 +100,9 @@ value_to_sql(X) -> undefined -> "NULL"; ?NULL_ATOM -> "NULL"; {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. %%-------------------------------------------------------------------- @@ -151,15 +149,16 @@ write_col_sql(Cols) -> %% @doc Returns copy of IoData with all ' replaced by '' %% @end %%-------------------------------------------------------------------- --spec escape(iodata()) -> iodata(). -escape(IoData) -> re:replace(IoData, "'", "''", [global, unicode]). +-spec binary_or_unicode_to_binary(binary() | unicode:charlist()) -> binary(). +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 %% passed as a blob literal. %% @end %%-------------------------------------------------------------------- --spec bin_to_hex(iodata()) -> binary(). +-spec bin_to_hex(binary()) -> binary(). bin_to_hex(Binary) -> << <<(half_byte_to_hex(X)):8>> || <> <= Binary>>. %%-------------------------------------------------------------------- diff --git a/test/sqlite3_test.erl b/test/sqlite3_test.erl index 8930241..a791dff 100644 --- a/test/sqlite3_test.erl +++ b/test/sqlite3_test.erl @@ -49,6 +49,7 @@ all_test_() -> ?FuncTest(nonexistent_table_info), ?FuncTest(large_number), ?FuncTest(unicode), + ?FuncTest(latin1_binary), ?FuncTest(acc_string_encoding), ?FuncTest(large_offset), ?FuncTest(issue23), @@ -171,7 +172,7 @@ parametrized() -> negative() -> drop_table_if_exists(ct, negative), sqlite3:create_table(ct, negative, [{id, int}]), - ?assertEqual({error, badarg}, + ?assertMatch({error, _}, sqlite3:write(ct, negative, [{id, bad_sql_value}])). blob() -> @@ -254,6 +255,14 @@ unicode() -> sqlite3:write(ct, unicode, [{str, UnicodeString}]), ?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() -> ?assertEqual([{62}], rows(sqlite3:sql_exec(ct, "SELECT ? + ?", [30,32]))).