Split off low-level api in separate file

This commit is contained in:
Maas-Maarten Zeeman
2011-11-06 21:37:35 +01:00
parent 281d720e8a
commit a015580021
6 changed files with 123 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Esqlite -- an erlang sqlite nif. * sqlite3_nif -- an erlang sqlite nif.
*/ */
#include <erl_nif.h> #include <erl_nif.h>
@@ -708,13 +708,13 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{ {
ErlNifResourceType *rt; ErlNifResourceType *rt;
rt = enif_open_resource_type(env, "esqlite", "esqlite_connection_type", rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_connection_type",
destruct_esqlite_connection, ERL_NIF_RT_CREATE, NULL); destruct_esqlite_connection, ERL_NIF_RT_CREATE, NULL);
if(!rt) if(!rt)
return -1; return -1;
esqlite_connection_type = rt; esqlite_connection_type = rt;
rt = enif_open_resource_type(env, "esqlite", "esqlite_statement_type", rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_statement_type",
destruct_esqlite_statement, ERL_NIF_RT_CREATE, NULL); destruct_esqlite_statement, ERL_NIF_RT_CREATE, NULL);
if(!rt) if(!rt)
return -1; return -1;
@@ -727,14 +727,14 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
} }
static ErlNifFunc nif_funcs[] = { static ErlNifFunc nif_funcs[] = {
{"esqlite_start", 0, esqlite_start}, {"start", 0, esqlite_start},
{"esqlite_open", 4, esqlite_open}, {"open", 4, esqlite_open},
{"esqlite_exec", 4, esqlite_exec}, {"exec", 4, esqlite_exec},
{"esqlite_prepare", 4, esqlite_prepare}, {"prepare", 4, esqlite_prepare},
{"esqlite_step", 3, esqlite_step}, {"step", 3, esqlite_step},
// {"esqlite_bind", 3, esqlite_bind_named}, // {"esqlite_bind", 3, esqlite_bind_named},
{"esqlite_bind", 4, esqlite_bind}, {"bind", 4, esqlite_bind},
{"esqlite_close", 3, esqlite_close} {"close", 3, esqlite_close}
}; };
ERL_NIF_INIT(esqlite, nif_funcs, on_load, NULL, NULL, NULL); ERL_NIF_INIT(esqlite3_nif, nif_funcs, on_load, NULL, NULL, NULL);

View File

@@ -1,3 +1,3 @@
{require_otp_vsn, "R14"}. {require_otp_vsn, "R14"}.
{port_sources, ["c_src/*.c"]}. {port_sources, ["c_src/*.c"]}.
{so_name, "esqlite_nif.so"}. {so_name, "esqlite3_nif.so"}.

View File

@@ -2,7 +2,7 @@
%% %%
%% %%
-module(esqlite). -module(esqlite3).
-author("Maas-Maarten Zeeman <mmzeeman@xs4all.nl>"). -author("Maas-Maarten Zeeman <mmzeeman@xs4all.nl>").
%% higher-level export %% higher-level export
@@ -13,23 +13,8 @@
bind/2, bind/3, bind/2, bind/3,
close/1, close/2]). close/1, close/2]).
%% low-level exports
-export([esqlite_start/0,
esqlite_open/4,
esqlite_exec/4,
esqlite_prepare/4,
esqlite_step/3,
esqlite_bind/4,
esqlite_close/3
]).
-on_load(init/0).
-define(DEFAULT_TIMEOUT, infinity). -define(DEFAULT_TIMEOUT, infinity).
init() ->
ok = erlang:load_nif(code:priv_dir(esqlite) ++ "/esqlite_nif", 0).
%% @doc Opens a sqlite3 database mentioned in Filename. %% @doc Opens a sqlite3 database mentioned in Filename.
%% %%
%% @spec open(string()) -> {ok, connection()} | {error, error_message()} %% @spec open(string()) -> {ok, connection()} | {error, error_message()}
@@ -40,10 +25,10 @@ open(Filename) ->
%% %%
%% @spec open(string(), integer()) -> {ok, connection()} | {error, error_message()} %% @spec open(string(), integer()) -> {ok, connection()} | {error, error_message()}
open(Filename, Timeout) -> open(Filename, Timeout) ->
{ok, Db} = esqlite_start(), {ok, Db} = esqlite3_nif:start(),
Ref = make_ref(), Ref = make_ref(),
ok = esqlite_open(Db, Ref, self(), Filename), ok = esqlite3_nif:open(Db, Ref, self(), Filename),
case receive_answer(Ref, Timeout) of case receive_answer(Ref, Timeout) of
ok -> ok ->
{ok, Db}; {ok, Db};
@@ -62,7 +47,7 @@ exec(Db, Sql) ->
%% @spec exec(connection(), iolist(), integer()) -> integer() | {error, error_message()} %% @spec exec(connection(), iolist(), integer()) -> integer() | {error, error_message()}
exec(Db, Sql, Timeout) -> exec(Db, Sql, Timeout) ->
Ref = make_ref(), Ref = make_ref(),
ok = esqlite_exec(Db, Ref, self(), add_eos(Sql)), ok = esqlite3_nif:exec(Db, Ref, self(), add_eos(Sql)),
receive_answer(Ref, Timeout). receive_answer(Ref, Timeout).
%% @doc Prepare a statement %% @doc Prepare a statement
@@ -76,7 +61,7 @@ prepare(Db, Sql) ->
%% @spec(connection(), iolist()) -> {ok, prepared_statement()} | {error, error_message()} %% @spec(connection(), iolist()) -> {ok, prepared_statement()} | {error, error_message()}
prepare(Db, Sql, Timeout) -> prepare(Db, Sql, Timeout) ->
Ref = make_ref(), Ref = make_ref(),
ok = esqlite_prepare(Db, Ref, self(), add_eos(Sql)), ok = esqlite3_nif:prepare(Db, Ref, self(), add_eos(Sql)),
receive_answer(Ref, Timeout). receive_answer(Ref, Timeout).
%% @doc Step %% @doc Step
@@ -90,7 +75,7 @@ step(Stmt) ->
%% @spec step(prepared_statement(), integer()) -> tuple() %% @spec step(prepared_statement(), integer()) -> tuple()
step(Stmt, Timeout) -> step(Stmt, Timeout) ->
Ref = make_ref(), Ref = make_ref(),
ok = esqlite_step(Stmt, Ref, self()), ok = esqlite3_nif:step(Stmt, Ref, self()),
receive_answer(Ref, Timeout). receive_answer(Ref, Timeout).
%% @doc Bind values to prepared statements %% @doc Bind values to prepared statements
@@ -104,7 +89,7 @@ bind(Stmt, Args) ->
%% @spec bind(prepared_statement()) -> ok | {error, error_message()} %% @spec bind(prepared_statement()) -> ok | {error, error_message()}
bind(Stmt, Args, Timeout) -> bind(Stmt, Args, Timeout) ->
Ref = make_ref(), Ref = make_ref(),
ok = esqlite_bind(Stmt, Ref, self(), Args), ok = esqlite3_nif:bind(Stmt, Ref, self(), Args),
receive_answer(Ref, Timeout). receive_answer(Ref, Timeout).
%% @doc Close the database %% @doc Close the database
@@ -118,38 +103,9 @@ close(Db) ->
%% @spec close(connection(), integer()) -> ok | {error, error_message()} %% @spec close(connection(), integer()) -> ok | {error, error_message()}
close(Db, Timeout) -> close(Db, Timeout) ->
Ref = make_ref(), Ref = make_ref(),
ok = esqlite_close(Db, Ref, self()), ok = esqlite3_nif:close(Db, Ref, self()),
receive_answer(Ref, Timeout). receive_answer(Ref, Timeout).
%% @doc
%%
esqlite_start() ->
exit(nif_library_not_loaded).
%% @doc
esqlite_open(_Db, _Ref, _Dest, _Filename) ->
exit(nif_library_not_loaded).
%% @doc
esqlite_exec(_Db, _Ref, _Dest, _Sql) ->
exit(nif_library_not_loaded).
%% @doc
esqlite_prepare(_Db, _Ref, _Dest, _Sql) ->
exit(nif_library_not_loaded).
%% @doc
esqlite_step(_Stmt, _Ref, _Dest) ->
exit(nif_library_not_loaded).
%% @doc
esqlite_bind(_Stmt, _Ref, _Dest, _Args) ->
exit(nif_library_not_loaded).
%% @doc
esqlite_close(_Db, _Ref, _Dest) ->
exit(nif_library_not_loaded).
%% Internal functions %% Internal functions
add_eos(String) when is_list(String) -> add_eos(String) when is_list(String) ->

57
src/esqlite3_nif.erl Normal file
View File

@@ -0,0 +1,57 @@
%%
%%
%%
-module(esqlite3_nif).
-author("Maas-Maarten Zeeman <mmzeeman@xs4all.nl>").
%% low-level exports
-export([start/0,
open/4,
exec/4,
prepare/4,
step/3,
bind/4,
close/3
]).
-on_load(init/0).
init() ->
ok = erlang:load_nif(code:priv_dir(esqlite) ++ "/esqlite3_nif", 0).
%% @doc Start a low level thread which will can handle sqlite3 calls.
%%
%% @spec
start() ->
exit(nif_library_not_loaded).
%% @doc Open a connection to
%%
open(_Db, _Ref, _Dest, _Filename) ->
exit(nif_library_not_loaded).
%% @doc
exec(_Db, _Ref, _Dest, _Sql) ->
exit(nif_library_not_loaded).
%% @doc
prepare(_Db, _Ref, _Dest, _Sql) ->
exit(nif_library_not_loaded).
%% @doc
step(_Stmt, _Ref, _Dest) ->
exit(nif_library_not_loaded).
%% @doc
bind(_Stmt, _Ref, _Dest, _Args) ->
exit(nif_library_not_loaded).
%% @doc
close(_Db, _Ref, _Dest) ->
exit(nif_library_not_loaded).

View File

@@ -11,13 +11,13 @@
%% @doc Open a database connection %% @doc Open a database connection
%% %%
handle_open(DatabaseName) -> handle_open(DatabaseName) ->
esqlite:open(DatabaseName). esqlite3:open(DatabaseName).
%% @doc Execute a query and return the results %% @doc Execute a query and return the results
%% %%
handle_execute(Operation, Args, Connection) -> handle_execute(Operation, Args, Connection) ->
{ok, Stmt} = esqlite:prepare(Connection, Operation), {ok, Stmt} = esqlite3:prepare(Connection, Operation),
ok = esqlite:bind(Stmt, Args), ok = esqlite3:bind(Stmt, Args),
Answer = execute(Stmt), Answer = execute(Stmt),
%% TODO Finalize the statement. %% TODO Finalize the statement.
Answer. Answer.
@@ -38,7 +38,7 @@ execute(Statement) ->
execute(_Statement, _Acc, Tries) when Tries > 5 -> execute(_Statement, _Acc, Tries) when Tries > 5 ->
throw(too_many_tries); throw(too_many_tries);
execute(Statement, Acc, Tries) -> execute(Statement, Acc, Tries) ->
case esqlite:step(Statement) of case esqlite3:step(Statement) of
'$done' -> '$done' ->
lists:reverse(Acc); lists:reverse(Acc);
'$busy' -> '$busy' ->

View File

@@ -7,65 +7,65 @@
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
open_single_database_test() -> open_single_database_test() ->
{ok, _C1} = esqlite:open("test.db"), {ok, _C1} = esqlite3:open("test.db"),
ok. ok.
open_multiple_same_databases_test() -> open_multiple_same_databases_test() ->
{ok, _C1} = esqlite:open("test.db"), {ok, _C1} = esqlite3:open("test.db"),
{ok, _C2} = esqlite:open("test.db"), {ok, _C2} = esqlite3:open("test.db"),
ok. ok.
open_multiple_different_databases_test() -> open_multiple_different_databases_test() ->
{ok, _C1} = esqlite:open("test1.db"), {ok, _C1} = esqlite3:open("test1.db"),
{ok, _C2} = esqlite:open("test2.db"), {ok, _C2} = esqlite3:open("test2.db"),
ok. ok.
simple_query_test() -> simple_query_test() ->
{ok, Db} = esqlite:open(":memory:"), {ok, Db} = esqlite3:open(":memory:"),
ok = esqlite:exec(Db, "begin;"), ok = esqlite3:exec(Db, "begin;"),
ok = esqlite:exec(Db, "create table test_table(one varchar(10), two int);"), ok = esqlite3:exec(Db, "create table test_table(one varchar(10), two int);"),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello1\"", ",", "10" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello1\"", ",", "10" ");"]),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello2\"", ",", "11" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello2\"", ",", "11" ");"]),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello3\"", ",", "12" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello3\"", ",", "12" ");"]),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello4\"", ",", "13" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello4\"", ",", "13" ");"]),
ok = esqlite:exec(Db, "commit;"), ok = esqlite3:exec(Db, "commit;"),
ok = esqlite:exec(Db, "select * from test_table;"), ok = esqlite3:exec(Db, "select * from test_table;"),
ok. ok.
prepare_test() -> prepare_test() ->
{ok, Db} = esqlite:open(":memory:"), {ok, Db} = esqlite3:open(":memory:"),
esqlite:exec(Db, "begin;"), esqlite3:exec(Db, "begin;"),
esqlite:exec(Db, "create table test_table(one varchar(10), two int);"), esqlite3:exec(Db, "create table test_table(one varchar(10), two int);"),
{ok, Statement} = esqlite:prepare(Db, "insert into test_table values(\"one\", 2)"), {ok, Statement} = esqlite3:prepare(Db, "insert into test_table values(\"one\", 2)"),
'$done' = esqlite:step(Statement), '$done' = esqlite3:step(Statement),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello4\"", ",", "13" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello4\"", ",", "13" ");"]),
{ok, St2} = esqlite:prepare(Db, "select * from test_table order by two"), {ok, St2} = esqlite3:prepare(Db, "select * from test_table order by two"),
[{"one", 2}, {"hello4", 13}] = exec(St2), [{"one", 2}, {"hello4", 13}] = exec(St2),
esqlite:exec(Db, "commit;"), esqlite3:exec(Db, "commit;"),
esqlite:close(Db), esqlite3:close(Db),
ok. ok.
bind_test() -> bind_test() ->
{ok, Db} = esqlite:open(":memory:"), {ok, Db} = esqlite3:open(":memory:"),
ok = esqlite:exec(Db, "begin;"), ok = esqlite3:exec(Db, "begin;"),
ok = esqlite:exec(Db, "create table test_table(one varchar(10), two int);"), ok = esqlite3:exec(Db, "create table test_table(one varchar(10), two int);"),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello1\"", ",", "10" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello1\"", ",", "10" ");"]),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello2\"", ",", "11" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello2\"", ",", "11" ");"]),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello3\"", ",", "12" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello3\"", ",", "12" ");"]),
ok = esqlite:exec(Db, ["insert into test_table values(", "\"hello4\"", ",", "13" ");"]), ok = esqlite3:exec(Db, ["insert into test_table values(", "\"hello4\"", ",", "13" ");"]),
ok = esqlite:exec(Db, "commit;"), ok = esqlite3:exec(Db, "commit;"),
%% Create a prepared statement %% Create a prepared statement
{ok, Statement} = esqlite:prepare(Db, "insert into test_table values(?1, ?2)"), {ok, Statement} = esqlite3:prepare(Db, "insert into test_table values(?1, ?2)"),
esqlite:bind(Statement, [one, 2]), esqlite3:bind(Statement, [one, 2]),
esqlite:step(Statement), esqlite3:step(Statement),
esqlite:bind(Statement, ["three", 4]), esqlite3:bind(Statement, ["three", 4]),
esqlite:step(Statement), esqlite3:step(Statement),
esqlite:bind(Statement, [<<"five">>, 6]), esqlite3:bind(Statement, [<<"five">>, 6]),
esqlite:step(Statement), esqlite3:step(Statement),
[{"one", 2}] = q(Db, "select * from test_table where two = '2'"), [{"one", 2}] = q(Db, "select * from test_table where two = '2'"),
[{"three", 4}] = q(Db, "select * from test_table where two = 4"), [{"three", 4}] = q(Db, "select * from test_table where two = 4"),
@@ -84,14 +84,14 @@ gen_db_test() ->
%% Handy functions... %% Handy functions...
%% %%
q(Connection, Sql) -> q(Connection, Sql) ->
{ok, Statement} = esqlite:prepare(Connection, Sql), {ok, Statement} = esqlite3:prepare(Connection, Sql),
exec(Statement). exec(Statement).
q(Connection, Sql, []) -> q(Connection, Sql, []) ->
q(Connection, Sql); q(Connection, Sql);
q(Connection, Sql, Args) -> q(Connection, Sql, Args) ->
{ok, Statement} = esqlite:prepare(Connection, Sql), {ok, Statement} = esqlite3:prepare(Connection, Sql),
esqlite:bind(Statement, Args), esqlite3:bind(Statement, Args),
exec(Statement). exec(Statement).
@@ -101,7 +101,7 @@ exec(Statement) ->
exec(_Statement, _Acc, Tries) when Tries > 5 -> exec(_Statement, _Acc, Tries) when Tries > 5 ->
throw(too_many_tries); throw(too_many_tries);
exec(Statement, Acc, Tries) -> exec(Statement, Acc, Tries) ->
case esqlite:step(Statement) of case esqlite3:step(Statement) of
'$done' -> '$done' ->
lists:reverse(Acc); lists:reverse(Acc);
'$busy' -> '$busy' ->