Support for BLOBs

This commit is contained in:
Alexey Romanov
2010-10-28 10:14:04 +04:00
parent 64101b04e1
commit 2059bfd7fd
3 changed files with 42 additions and 14 deletions

View File

@@ -20,4 +20,4 @@
-endif. -endif.
-define(NULL_ATOM, null). -define(NULL_ATOM, null).
-type(sql_value() :: number() | ?NULL_ATOM | iodata()). -type(sql_value() :: number() | ?NULL_ATOM | iodata() | {blob, binary()}).

View File

@@ -11,7 +11,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]). -export([value_to_sql/1, value_to_sql_unsafe/1, sql_to_value/1, escape/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([write_sql/2, update_sql/4, update_set_sql/1, delete_sql/3]). -export([write_sql/2, update_sql/4, update_set_sql/1, delete_sql/3]).
@@ -34,6 +34,8 @@ col_type_to_string(double) ->
"REAL"; "REAL";
col_type_to_string(real) -> col_type_to_string(real) ->
"REAL"; "REAL";
col_type_to_string(blob) ->
"BLOB";
col_type_to_string(String) when is_list(String) -> col_type_to_string(String) when is_list(String) ->
String. String.
@@ -48,7 +50,9 @@ col_type_to_atom("INTEGER") ->
col_type_to_atom("TEXT") -> col_type_to_atom("TEXT") ->
text; text;
col_type_to_atom("REAL") -> col_type_to_atom("REAL") ->
double. double;
col_type_to_atom("BLOB") ->
blob.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec value_to_sql_unsafe(Value :: sql_value()) -> iolist() %% @spec value_to_sql_unsafe(Value :: sql_value()) -> iolist()
@@ -65,11 +69,12 @@ col_type_to_atom("REAL") ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-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) ->
if case X of
is_integer(X) -> integer_to_list(X); _ when is_integer(X) -> integer_to_list(X);
is_float(X) -> float_to_list(X); _ when is_float(X) -> float_to_list(X);
X == ?NULL_ATOM -> "NULL"; ?NULL_ATOM -> "NULL";
true -> [$', X, $'] %% assumes no $' inside strings! {blob, Blob} -> ["x'", bin_to_hex(Blob), $'];
_ -> [$', X, $'] %% assumes no $' inside strings!
end. end.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@@ -84,14 +89,14 @@ value_to_sql_unsafe(X) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec value_to_sql(sql_value()) -> iolist(). -spec value_to_sql(sql_value()) -> iolist().
value_to_sql(X) -> value_to_sql(X) ->
if case X of
is_integer(X) -> integer_to_list(X); _ when is_integer(X) -> integer_to_list(X);
is_float(X) -> float_to_list(X); _ when is_float(X) -> float_to_list(X);
X == ?NULL_ATOM -> "NULL"; ?NULL_ATOM -> "NULL";
true -> [$', escape(X), $'] {blob, Blob} -> ["x'", bin_to_hex(Blob), $'];
_ -> [$', escape(X), $']
end. end.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec sql_to_value(String :: string()) -> sql_value() %% @spec sql_to_value(String :: string()) -> sql_value()
%% @doc %% @doc
@@ -144,6 +149,16 @@ write_col_sql(Cols) ->
-spec escape(iodata()) -> iodata(). -spec escape(iodata()) -> iodata().
escape(IoData) -> re:replace(IoData, "'", "''", [global]). escape(IoData) -> re:replace(IoData, "'", "''", [global]).
%%--------------------------------------------------------------------
%% @spec bin_to_hex(Binary :: binary()) -> binary()
%%
%% @doc Converts a plain binary to its hexadecimal encoding, to be
%% passed as a blob literal.
%% @end
%%--------------------------------------------------------------------
-spec bin_to_hex(iodata()) -> binary().
bin_to_hex(Binary) -> << <<(half_byte_to_hex(X)):8>> || <<X:4>> <= Binary>>.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec update_set_sql([{Column :: atom(), Value :: sql_value()}]) -> iolist() %% @spec update_set_sql([{Column :: atom(), Value :: sql_value()}]) -> iolist()
%% @doc %% @doc
@@ -322,6 +337,9 @@ map_intersperse(_Fun, [], _Sep) -> [];
map_intersperse(Fun, [Elem], _Sep) -> [Fun(Elem)]; map_intersperse(Fun, [Elem], _Sep) -> [Fun(Elem)];
map_intersperse(Fun, [Head | Tail], Sep) -> [Fun(Head), Sep | map_intersperse(Fun, Tail, Sep)]. map_intersperse(Fun, [Head | Tail], Sep) -> [Fun(Head), Sep | map_intersperse(Fun, Tail, Sep)].
half_byte_to_hex(X) when X < 10 -> $0 + X;
half_byte_to_hex(X) -> $a + X - 10.
-spec sql_number(string()) -> number() | {error, not_a_number}. -spec sql_number(string()) -> number() | {error, not_a_number}.
sql_number(NumberStr) -> sql_number(NumberStr) ->
case string:to_integer(NumberStr) of case string:to_integer(NumberStr) of

View File

@@ -79,6 +79,16 @@ basic_functionality_test() ->
sqlite3:drop_table(ct, user)), sqlite3:drop_table(ct, user)),
sqlite3:close(ct). sqlite3:close(ct).
blob_test() ->
sqlite3:open(ct),
drop_table_if_exists(ct, blobs),
sqlite3:create_table(ct, blobs, [{blob_col, blob}]),
sqlite3:write(ct, blobs, [{blob_col, {blob, <<0,255,1,2>>}}]),
?assertEqual(
[{columns, ["blob_col"]}, {rows, [{<<0,255,1,2>>}]}],
sqlite3:read_all(ct, blobs)),
sqlite3:close(ct).
select_many_records_test() -> select_many_records_test() ->
sqlite3:open(ct), sqlite3:open(ct),
drop_table_if_exists(ct, many_records), drop_table_if_exists(ct, many_records),