Add named parameters support

SQLite supports named parameters in either of these forms:
- $NAME
- :NAME
- @NAME

These parameters should be supplied to the query either in a form of a map
or as a list, the key is always iodata:
- #{":myparam" => "value"}
- [{"$myparam", 1}]
- [{text, "@myparam", "value"}]
This commit is contained in:
Dmitry Matveyev
2023-01-08 13:54:27 +06:00
parent c71ad3eb6b
commit 16580ce11d
5 changed files with 99 additions and 1 deletions

View File

@@ -295,8 +295,17 @@ prepare(#esqlite3{db=Connection}, Sql, PrepareFlags) ->
%% @doc Bind an array of values as parameters of a prepared statement
-spec bind(Statement, Args) -> Result when
Statement :: esqlite3_stmt(),
Args :: list(),
Args :: list() | map(),
Result :: ok | {error, _}.
%% Named parameters
bind(#esqlite3_stmt{}=Statement, Args) when is_map(Args) ->
bind(Statement, maps:to_list(Args));
bind(#esqlite3_stmt{}=Statement, [{_Type, _ParameterName, _Value} | _] = Args) ->
bind2(Statement, Args);
bind(#esqlite3_stmt{}=Statement, [{ParameterName, _Value} | _] = Args)
when is_binary(ParameterName); is_list(ParameterName) ->
bind2(Statement, Args);
%% Anonymous parameters
bind(#esqlite3_stmt{}=Statement, Args) when is_list(Args) ->
bind1(Statement, 1, Args).
@@ -310,6 +319,33 @@ bind1(Statement, Column, [Arg | Args]) ->
Error
end.
bind2(_Statement, []) ->
ok;
bind2(#esqlite3_stmt{stmt=Stmt}=Statement, [{Type, ParameterName, Value} | Args]) ->
case esqlite3_nif:bind_parameter_index(Stmt, ParameterName) of
{ok, Column} ->
case bind_arg(Statement, Column, {Type, Value}) of
ok ->
bind2(Statement, Args);
{error, _}=Error ->
Error
end;
error ->
{error, named_parameter_not_found}
end;
bind2(#esqlite3_stmt{stmt=Stmt}=Statement, [{ParameterName, Value} | Args]) ->
case esqlite3_nif:bind_parameter_index(Stmt, ParameterName) of
{ok, Column} ->
case bind_arg(Statement, Column, Value) of
ok ->
bind2(Statement, Args);
{error, _}=Error ->
Error
end;
error ->
{error, named_parameter_not_found}
end.
% Bind with automatic tyoe conversion
bind_arg(Statement, Column, undefined) ->
bind_null(Statement, Column);

View File

@@ -42,6 +42,7 @@
bind_text/3,
bind_blob/3,
bind_null/2,
bind_parameter_index/2,
step/1,
@@ -194,6 +195,13 @@ bind_blob(_Statement, _Index, _Value) ->
bind_null(_Statement, _Index) ->
erlang:nif_error(nif_library_not_loaded).
-spec bind_parameter_index(Statement, ParameterName) -> Result when
Statement :: esqlite3_stmt_ref(),
ParameterName :: iodata(),
Result :: {ok, integer()} | error.
bind_parameter_index(_Statement, _ParameterName) ->
erlang:nif_error(nif_library_not_loaded).
-spec step(Statement) -> StepResult when
Statement :: esqlite3_stmt_ref(),
StepResult :: row() | '$done' | error().