Fix reference count to connection when a prepared statement is made
This commit is contained in:
@@ -242,7 +242,7 @@ destruct_esqlite_statement(ErlNifEnv *env, void *arg)
|
|||||||
stmt->statement = NULL;
|
stmt->statement = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
enif_release_resource(stmt->connection);
|
stmt->connection = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ERL_NIF_TERM
|
static ERL_NIF_TERM
|
||||||
@@ -869,11 +869,6 @@ esqlite_prepare(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
|||||||
if(!cmd)
|
if(!cmd)
|
||||||
return make_error_tuple(env, "command_create_failed");
|
return make_error_tuple(env, "command_create_failed");
|
||||||
|
|
||||||
/* Keep a reference to the connection to prevent it from being taken down
|
|
||||||
* while the prepare statement is waiting on the queue.
|
|
||||||
*/
|
|
||||||
enif_keep_resource(conn);
|
|
||||||
|
|
||||||
cmd->type = cmd_prepare;
|
cmd->type = cmd_prepare;
|
||||||
cmd->ref = enif_make_copy(cmd->env, argv[1]);
|
cmd->ref = enif_make_copy(cmd->env, argv[1]);
|
||||||
cmd->pid = pid;
|
cmd->pid = pid;
|
||||||
|
|||||||
@@ -40,8 +40,8 @@
|
|||||||
-define(DEFAULT_TIMEOUT, 5000).
|
-define(DEFAULT_TIMEOUT, 5000).
|
||||||
|
|
||||||
%%
|
%%
|
||||||
-type connection() :: tuple().
|
-type connection() :: {connection, reference(), term()}.
|
||||||
-type statement() :: term().
|
-type statement() :: {statement, term(), connection()}.
|
||||||
-type sql() :: iolist().
|
-type sql() :: iolist().
|
||||||
|
|
||||||
%% @doc Opens a sqlite3 database mentioned in Filename.
|
%% @doc Opens a sqlite3 database mentioned in Filename.
|
||||||
@@ -260,10 +260,13 @@ prepare(Sql, Connection) ->
|
|||||||
%% @doc
|
%% @doc
|
||||||
%%
|
%%
|
||||||
%% @spec(iolist(), connection(), timeout()) -> {ok, prepared_statement()} | {error, error_message()}
|
%% @spec(iolist(), connection(), timeout()) -> {ok, prepared_statement()} | {error, error_message()}
|
||||||
prepare(Sql, {connection, _Ref, Connection}, Timeout) ->
|
prepare(Sql, {connection, _Ref, Connection}=C, Timeout) ->
|
||||||
Ref = make_ref(),
|
Ref = make_ref(),
|
||||||
ok = esqlite3_nif:prepare(Connection, Ref, self(), Sql),
|
ok = esqlite3_nif:prepare(Connection, Ref, self(), Sql),
|
||||||
receive_answer(Ref, Timeout).
|
case receive_answer(Ref, Timeout) of
|
||||||
|
{ok, Stmt} -> {ok, {statement, Stmt, C}};
|
||||||
|
Else -> Else
|
||||||
|
end.
|
||||||
|
|
||||||
%% @doc Step
|
%% @doc Step
|
||||||
%%
|
%%
|
||||||
@@ -275,7 +278,7 @@ step(Stmt) ->
|
|||||||
%%
|
%%
|
||||||
%% @spec step(prepared_statement(), timeout()) -> tuple()
|
%% @spec step(prepared_statement(), timeout()) -> tuple()
|
||||||
-spec step(term(), timeout()) -> tuple() | '$busy' | '$done'.
|
-spec step(term(), timeout()) -> tuple() | '$busy' | '$done'.
|
||||||
step(Stmt, Timeout) ->
|
step({statement, Stmt, _}, Timeout) ->
|
||||||
Ref = make_ref(),
|
Ref = make_ref(),
|
||||||
ok = esqlite3_nif:step(Stmt, Ref, self()),
|
ok = esqlite3_nif:step(Stmt, Ref, self()),
|
||||||
receive_answer(Ref, Timeout).
|
receive_answer(Ref, Timeout).
|
||||||
@@ -283,7 +286,7 @@ step(Stmt, Timeout) ->
|
|||||||
%% @doc Reset the prepared statement back to its initial state.
|
%% @doc Reset the prepared statement back to its initial state.
|
||||||
%%
|
%%
|
||||||
%% @spec reset(prepared_statement()) -> ok | {error, error_message()}
|
%% @spec reset(prepared_statement()) -> ok | {error, error_message()}
|
||||||
reset(Stmt) ->
|
reset({statement, Stmt, _}) ->
|
||||||
Ref = make_ref(),
|
Ref = make_ref(),
|
||||||
ok = esqlite3_nif:reset(Stmt, Ref, self()),
|
ok = esqlite3_nif:reset(Stmt, Ref, self()),
|
||||||
receive_answer(Ref, ?DEFAULT_TIMEOUT).
|
receive_answer(Ref, ?DEFAULT_TIMEOUT).
|
||||||
@@ -297,7 +300,7 @@ bind(Stmt, Args) ->
|
|||||||
%% @doc Bind values to prepared statements
|
%% @doc Bind values to prepared statements
|
||||||
%%
|
%%
|
||||||
%% @spec bind(prepared_statement(), [], timeout()) -> ok | {error, error_message()}
|
%% @spec bind(prepared_statement(), [], timeout()) -> ok | {error, error_message()}
|
||||||
bind(Stmt, Args, Timeout) ->
|
bind({statement, Stmt, _}, Args, Timeout) ->
|
||||||
Ref = make_ref(),
|
Ref = make_ref(),
|
||||||
ok = esqlite3_nif:bind(Stmt, Ref, self(), Args),
|
ok = esqlite3_nif:bind(Stmt, Ref, self(), Args),
|
||||||
receive_answer(Ref, Timeout).
|
receive_answer(Ref, Timeout).
|
||||||
@@ -309,7 +312,7 @@ column_names(Stmt) ->
|
|||||||
column_names(Stmt, ?DEFAULT_TIMEOUT).
|
column_names(Stmt, ?DEFAULT_TIMEOUT).
|
||||||
|
|
||||||
-spec column_names(statement(), timeout()) -> {atom()}.
|
-spec column_names(statement(), timeout()) -> {atom()}.
|
||||||
column_names(Stmt, Timeout) ->
|
column_names({statement, Stmt, _}, Timeout) ->
|
||||||
Ref = make_ref(),
|
Ref = make_ref(),
|
||||||
ok = esqlite3_nif:column_names(Stmt, Ref, self()),
|
ok = esqlite3_nif:column_names(Stmt, Ref, self()),
|
||||||
receive_answer(Ref, Timeout).
|
receive_answer(Ref, Timeout).
|
||||||
@@ -321,7 +324,7 @@ column_types(Stmt) ->
|
|||||||
column_types(Stmt, ?DEFAULT_TIMEOUT).
|
column_types(Stmt, ?DEFAULT_TIMEOUT).
|
||||||
|
|
||||||
-spec column_types(statement(), timeout()) -> {atom()}.
|
-spec column_types(statement(), timeout()) -> {atom()}.
|
||||||
column_types(Stmt, Timeout) ->
|
column_types({statement, Stmt, _}, Timeout) ->
|
||||||
Ref = make_ref(),
|
Ref = make_ref(),
|
||||||
ok = esqlite3_nif:column_types(Stmt, Ref, self()),
|
ok = esqlite3_nif:column_types(Stmt, Ref, self()),
|
||||||
receive_answer(Ref, Timeout).
|
receive_answer(Ref, Timeout).
|
||||||
|
|||||||
@@ -116,7 +116,6 @@ bind_test() ->
|
|||||||
?assertEqual([{<<228,184,138,230,181,183>>, 100}],
|
?assertEqual([{<<228,184,138,230,181,183>>, 100}],
|
||||||
esqlite3:q("select one, two from test_table where two = 100", Db)),
|
esqlite3:q("select one, two from test_table where two = 100", Db)),
|
||||||
|
|
||||||
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
bind_for_queries_test() ->
|
bind_for_queries_test() ->
|
||||||
@@ -326,3 +325,24 @@ sqlite_source_id_test() ->
|
|||||||
?assertEqual({row, {<<"2015-07-23 16:39:33 793e206f9032d9205bdb3f447b136bed9a25fa22">>}}, esqlite3:step(Stmt)),
|
?assertEqual({row, {<<"2015-07-23 16:39:33 793e206f9032d9205bdb3f447b136bed9a25fa22">>}}, esqlite3:step(Stmt)),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
garbage_collect_test() ->
|
||||||
|
F = fun() ->
|
||||||
|
{ok, Db} = esqlite3:open(":memory:"),
|
||||||
|
[] = esqlite3:q("create table test(one, two, three)", Db),
|
||||||
|
{ok, Stmt} = esqlite3:prepare("select * from test", Db),
|
||||||
|
'$done' = esqlite3:step(Stmt)
|
||||||
|
end,
|
||||||
|
|
||||||
|
[spawn(F) || _X <- lists:seq(0,30)],
|
||||||
|
receive after 500 -> ok end,
|
||||||
|
erlang:garbage_collect(),
|
||||||
|
|
||||||
|
[spawn(F) || _X <- lists:seq(0,30)],
|
||||||
|
receive after 500 -> ok end,
|
||||||
|
erlang:garbage_collect(),
|
||||||
|
|
||||||
|
ok.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user