Removed remaining io:format calls when constructing queries
This commit is contained in:
@@ -1,3 +1 @@
|
|||||||
{'src/sqlite3_lib.erl',[debug_info,{outdir,"ebin"}, {d, 'NULL_ATOM', '@NULL_ATOM@'}]}.
|
{'src/*', [debug_info, {outdir, "ebin"}, {i, "include"}]}.
|
||||||
{'src/sqlite3.erl',[debug_info,{outdir,"ebin"}]}.
|
|
||||||
{'src/sqlite3_test.erl',[debug_info,{outdir,"ebin"}]}.
|
|
||||||
|
|||||||
2
include/sqlite3.hrl
Normal file
2
include/sqlite3.hrl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-define(NULL_ATOM, null).
|
||||||
|
-type(sql_value() :: number() | ?NULL_ATOM | iodata()).
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(sqlite3).
|
-module(sqlite3).
|
||||||
|
-include("sqlite3.hrl").
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
|
|
||||||
-export([create_function/3]).
|
-export([create_function/3]).
|
||||||
|
|
||||||
|
-export([value_to_sql/1, value_to_sql_unsafe/1]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
terminate/2, code_change/3]).
|
terminate/2, code_change/3]).
|
||||||
@@ -372,6 +375,38 @@ drop_table(Db, Tbl) ->
|
|||||||
create_function(Db, FunctionName, Function) ->
|
create_function(Db, FunctionName, Function) ->
|
||||||
gen_server:call(Db, {create_function, FunctionName, Function}).
|
gen_server:call(Db, {create_function, FunctionName, Function}).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec value_to_sql_unsafe(Value :: sql_value()) -> iodata()
|
||||||
|
%% @doc
|
||||||
|
%% Converts an Erlang term to an SQL string.
|
||||||
|
%% Currently supports integers, floats, 'null' atom, and iodata
|
||||||
|
%% (binaries and iolists) which are treated as SQL strings.
|
||||||
|
%%
|
||||||
|
%% Note that it opens opportunity for injection if an iolist includes
|
||||||
|
%% single quotes! Replace all single quotes (') with '' manually, or
|
||||||
|
%% use value_to_sql/1 if you are not sure if your strings contain
|
||||||
|
%% single quotes (e.g. can be entered by users).
|
||||||
|
%%
|
||||||
|
%% Reexported from sqlite3_lib:value_to_sql/1 for user convenience.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec(value_to_sql_unsafe/1::(sql_value()) -> iodata()).
|
||||||
|
value_to_sql_unsafe(X) -> sqlite3_lib:value_to_sql_unsafe(X).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec value_to_sql(Value :: sql_value()) -> iodata()
|
||||||
|
%% @doc
|
||||||
|
%% Converts an Erlang term to an SQL string.
|
||||||
|
%% Currently supports integers, floats, 'null' atom, and iodata
|
||||||
|
%% (binaries and iolists) which are treated as SQL strings.
|
||||||
|
%%
|
||||||
|
%% All single quotes (') will be replaced with ''.
|
||||||
|
%%
|
||||||
|
%% Reexported from sqlite3_lib:value_to_sql/1 for user convenience.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec(value_to_sql/1::(sql_value()) -> iolist()).
|
||||||
|
value_to_sql(X) -> sqlite3_lib:value_to_sql(X).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
|
|||||||
@@ -7,13 +7,15 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(sqlite3_lib).
|
-module(sqlite3_lib).
|
||||||
|
-include("sqlite3.hrl").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([col_type/1]).
|
-export([col_type/1]).
|
||||||
|
-export([value_to_sql/1, value_to_sql_unsafe/1, escape/1]).
|
||||||
-export([write_value_sql/1, write_col_sql/1]).
|
-export([write_value_sql/1, write_col_sql/1]).
|
||||||
-export([create_table_sql/2, write_sql/2, read_sql/3, delete_sql/3, drop_table/1]).
|
-export([create_table_sql/2, write_sql/2, read_sql/3, delete_sql/3, drop_table/1]).
|
||||||
-export ([update_sql/4, update_set_sql/1, replace/1]).
|
-export([update_sql/4, update_set_sql/1, replace/1]).
|
||||||
-export ([read_sql/4, read_cols_sql/1]).
|
-export([read_sql/4, read_cols_sql/1]).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
@@ -41,21 +43,56 @@ col_type(date) ->
|
|||||||
col_type("DATE") ->
|
col_type("DATE") ->
|
||||||
date.
|
date.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec value_to_sql_unsafe(Value :: sql_value()) -> iodata()
|
||||||
|
%% @doc
|
||||||
|
%% Converts an Erlang term to an SQL string.
|
||||||
|
%% Currently supports integers, floats, 'null' atom, and iodata
|
||||||
|
%% (binaries and iolists) which are treated as SQL strings.
|
||||||
|
%%
|
||||||
|
%% Note that it opens opportunity for injection if an iolist includes
|
||||||
|
%% single quotes! Replace all single quotes (') with '' manually, or
|
||||||
|
%% use value_to_sql/1 if you are not sure if your strings contain
|
||||||
|
%% single quotes (e.g. can be entered by users).
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec(value_to_sql_unsafe/1::(sql_value()) -> iodata()).
|
||||||
|
value_to_sql_unsafe(X) ->
|
||||||
|
if
|
||||||
|
is_integer(X) -> integer_to_list(X);
|
||||||
|
is_float(X) -> float_to_list(X);
|
||||||
|
X == ?NULL_ATOM -> "NULL";
|
||||||
|
true -> [$', X, $'] %% assumes no $' inside strings!
|
||||||
|
end.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec value_to_sql(Value :: sql_value()) -> iodata()
|
||||||
|
%% @doc
|
||||||
|
%% Converts an Erlang term to an SQL string.
|
||||||
|
%% Currently supports integers, floats, 'null' atom, and iodata
|
||||||
|
%% (binaries and iolists) which are treated as SQL strings.
|
||||||
|
%%
|
||||||
|
%% All single quotes (') will be replaced with ''.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec(value_to_sql/1::(sql_value()) -> iolist()).
|
||||||
|
value_to_sql(X) ->
|
||||||
|
if
|
||||||
|
is_integer(X) -> integer_to_list(X);
|
||||||
|
is_float(X) -> float_to_list(X);
|
||||||
|
X == ?NULL_ATOM -> "NULL";
|
||||||
|
true -> [$', escape(X), $']
|
||||||
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec write_value_sql(Value :: [term()]) -> string()
|
%% @spec write_value_sql(Value :: [term()]) -> string()
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Creates the values portion of the sql stmt.
|
%% Creates the values portion of the sql stmt.
|
||||||
%% Currently only support integer, double/float and strings.
|
|
||||||
%% @end
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec(write_value_sql/1::(any()) -> string()).
|
-spec(write_value_sql/1::(any()) -> string()).
|
||||||
write_value_sql(Values) ->
|
write_value_sql(Values) ->
|
||||||
StrValues = lists:map(fun
|
StrValues = lists:map(fun value_to_sql/1, Values),
|
||||||
(X) when is_integer(X) -> integer_to_list(X);
|
|
||||||
(X) when is_float(X) -> float_to_list(X);
|
|
||||||
(?NULL_ATOM) -> "null";
|
|
||||||
(X) -> io_lib:format("'~s'", [X])
|
|
||||||
end, Values),
|
|
||||||
intersperse(StrValues, ",").
|
intersperse(StrValues, ",").
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
@@ -83,26 +120,32 @@ replace([$" | T]) ->
|
|||||||
replace([H | T]) ->
|
replace([H | T]) ->
|
||||||
[H | replace(T)].
|
[H | replace(T)].
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec escape(IoData :: iodata()) -> iodata()
|
||||||
|
%%
|
||||||
|
%% @doc Returns copy of IoData with all ' replaced by ''
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
-spec(escape/1::(iodata()) -> iodata()).
|
||||||
|
escape(IoData) -> re:replace(IoData, "'", "''", [global]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec update_set_sql ([{Col, Value}]) -> string ()
|
%% @spec update_set_sql ([{Col, Value}]) -> string ()
|
||||||
%% Col = atom ()
|
%% Col = atom ()
|
||||||
%% Value = integer () | float () | string ()
|
%% Value = number () | atom () | string ()
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Creates update set stmt.
|
%% Creates update set stmt.
|
||||||
%% Currently only supports integer, double/float and strings.
|
%% Currently supports integer, double/float and strings.
|
||||||
%% For strings \" replaced with '.
|
%% For strings \" replaced with '.
|
||||||
%% @end
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec (update_set_sql/1::(any ()) -> string ()).
|
-spec (update_set_sql/1::(any ()) -> string ()).
|
||||||
update_set_sql (Data) ->
|
update_set_sql (Data) ->
|
||||||
Set = lists:map (fun
|
Set = lists:map (fun
|
||||||
({Col, Value}) when is_integer (Value) ->
|
({Col, Value}) when is_list(Value) ->
|
||||||
[atom_to_list (Col), " = ", integer_to_list (Value)];
|
[atom_to_list (Col), " = ", $", replace(Value), $"];
|
||||||
({Col, Value}) when is_float (Value) ->
|
|
||||||
[atom_to_list (Col), " = ", float_to_list (Value)];
|
|
||||||
({Col, Value}) ->
|
({Col, Value}) ->
|
||||||
[atom_to_list (Col), " = ",
|
[atom_to_list (Col), " = ", value_to_sql(Value)]
|
||||||
io_lib:format ("\"~s\"", [replace (Value)])]
|
|
||||||
end,
|
end,
|
||||||
Data),
|
Data),
|
||||||
intersperse(Set, ", ").
|
intersperse(Set, ", ").
|
||||||
@@ -128,11 +171,11 @@ read_cols_sql (Columns) ->
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec(create_table_sql/2::(atom(), [{atom(), string()}]) -> string()).
|
-spec(create_table_sql/2::(atom(), [{atom(), string()}]) -> string()).
|
||||||
create_table_sql(Tbl, [{ColName, Type} | Tl]) ->
|
create_table_sql(Tbl, [{ColName, Type} | Tl]) ->
|
||||||
CT = io_lib:format("CREATE TABLE ~p ", [Tbl]),
|
CT = ["CREATE TABLE ", atom_to_list(Tbl), " "],
|
||||||
Start = io_lib:format("(~p ~s PRIMARY KEY, ", [ColName, sqlite3_lib:col_type(Type)]),
|
Start = ["(", atom_to_list(ColName), " ", sqlite3_lib:col_type(Type), " PRIMARY KEY, "],
|
||||||
End = [intersperse(
|
End = [intersperse(
|
||||||
lists:map(fun({Name0, Type0}) ->
|
lists:map(fun({Name0, Type0}) ->
|
||||||
io_lib:format("~p ~s", [Name0, sqlite3_lib:col_type(Type0)])
|
[atom_to_list(Name0), " ", sqlite3_lib:col_type(Type0)]
|
||||||
end, Tl), ", "), ");"],
|
end, Tl), ", "), ");"],
|
||||||
[CT, Start, End].
|
[CT, Start, End].
|
||||||
|
|
||||||
@@ -148,15 +191,10 @@ create_table_sql(Tbl, [{ColName, Type} | Tl]) ->
|
|||||||
%% record with matching Value.
|
%% record with matching Value.
|
||||||
%% @end
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-type(sql_value() :: string() | integer() | float()).
|
|
||||||
-spec (update_sql/4::(atom (), atom (), atom (), [{atom (), sql_value ()}]) -> string ()).
|
-spec (update_sql/4::(atom (), atom (), atom (), [{atom (), sql_value ()}]) -> string ()).
|
||||||
update_sql (Tbl, Key, Value, Data) ->
|
update_sql (Tbl, Key, Value, Data) ->
|
||||||
io_lib:format("UPDATE ~p SET ~s WHERE ~p = ~p;",
|
["UPDATE ", atom_to_list(Tbl), " SET ", sqlite3_lib:update_set_sql(Data),
|
||||||
[Tbl,
|
" WHERE ", atom_to_list(Key), " = ", value_to_sql(Value), ";"].
|
||||||
sqlite3_lib:update_set_sql (Data),
|
|
||||||
Key,
|
|
||||||
Value
|
|
||||||
]).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec write_sql(Tbl, Data) -> string()
|
%% @spec write_sql(Tbl, Data) -> string()
|
||||||
@@ -169,11 +207,8 @@ update_sql (Tbl, Key, Value, Data) ->
|
|||||||
-spec(write_sql/2::(atom(), [{atom(), sql_value()}]) -> string()).
|
-spec(write_sql/2::(atom(), [{atom(), sql_value()}]) -> string()).
|
||||||
write_sql(Tbl, Data) ->
|
write_sql(Tbl, Data) ->
|
||||||
{Cols, Values} = lists:unzip(Data),
|
{Cols, Values} = lists:unzip(Data),
|
||||||
io_lib:format("INSERT INTO ~p (~s) values (~s);",
|
["INSERT INTO ", atom_to_list(Tbl), " (", sqlite3_lib:write_col_sql(Cols),
|
||||||
[Tbl,
|
") values (", sqlite3_lib:write_value_sql(Values), ");"].
|
||||||
sqlite3_lib:write_col_sql(Cols),
|
|
||||||
sqlite3_lib:write_value_sql(Values)
|
|
||||||
]).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec read_sql(Tbl, Key, Value) -> string()
|
%% @spec read_sql(Tbl, Key, Value) -> string()
|
||||||
@@ -186,7 +221,8 @@ write_sql(Tbl, Data) ->
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec(read_sql/3::(atom(), atom(), sql_value()) -> string()).
|
-spec(read_sql/3::(atom(), atom(), sql_value()) -> string()).
|
||||||
read_sql(Tbl, Key, Value) ->
|
read_sql(Tbl, Key, Value) ->
|
||||||
io_lib:format("SELECT * FROM ~p WHERE ~p = ~p;", [Tbl, Key, Value]).
|
["SELECT * FROM ", atom_to_list(Tbl), " WHERE ", atom_to_list(Key),
|
||||||
|
" = ", value_to_sql(Value), ";"].
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec read_sql (Tbl, Key, Value, Columns) -> string ()
|
%% @spec read_sql (Tbl, Key, Value, Columns) -> string ()
|
||||||
@@ -201,12 +237,9 @@ read_sql(Tbl, Key, Value) ->
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec (read_sql/4::(atom (), atom (), sql_value (), [atom ()]) -> string ()).
|
-spec (read_sql/4::(atom (), atom (), sql_value (), [atom ()]) -> string ()).
|
||||||
read_sql (Tbl, Key, Value, Columns) ->
|
read_sql (Tbl, Key, Value, Columns) ->
|
||||||
io_lib:format("SELECT ~s FROM ~p WHERE ~p = ~p;",
|
["SELECT ", sqlite3_lib:read_cols_sql(Columns), " FROM ",
|
||||||
[sqlite3_lib:read_cols_sql (Columns),
|
atom_to_list(Tbl), " WHERE ", atom_to_list(Key), " = ",
|
||||||
Tbl,
|
value_to_sql(Value), ";"].
|
||||||
Key,
|
|
||||||
Value
|
|
||||||
]).
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec delete_sql(Tbl, Key, Value) -> string()
|
%% @spec delete_sql(Tbl, Key, Value) -> string()
|
||||||
@@ -219,7 +252,8 @@ read_sql (Tbl, Key, Value, Columns) ->
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec(delete_sql/3::(atom(), atom(), sql_value()) -> string()).
|
-spec(delete_sql/3::(atom(), atom(), sql_value()) -> string()).
|
||||||
delete_sql(Tbl, Key, Value) ->
|
delete_sql(Tbl, Key, Value) ->
|
||||||
io_lib:format("DELETE FROM ~p WHERE ~p = ~p;", [Tbl, Key, Value]).
|
["DELETE FROM ", atom_to_list(Tbl), " WHERE ", atom_to_list(Key),
|
||||||
|
" = ", value_to_sql(Value), ";"].
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec drop_table(Tbl) -> string()
|
%% @spec drop_table(Tbl) -> string()
|
||||||
@@ -229,7 +263,7 @@ delete_sql(Tbl, Key, Value) ->
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec(drop_table/1::(atom()) -> string()).
|
-spec(drop_table/1::(atom()) -> string()).
|
||||||
drop_table(Tbl) ->
|
drop_table(Tbl) ->
|
||||||
io_lib:format("DROP TABLE ~p;", [Tbl]).
|
["DROP TABLE ", atom_to_list(Tbl), ";"].
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
|
|||||||
Reference in New Issue
Block a user