merge
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
.rebar
|
||||||
|
|
||||||
rebar
|
rebar
|
||||||
|
|
||||||
ebin
|
ebin
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ typedef enum {
|
|||||||
cmd_unknown,
|
cmd_unknown,
|
||||||
cmd_open,
|
cmd_open,
|
||||||
cmd_exec,
|
cmd_exec,
|
||||||
|
cmd_changes,
|
||||||
cmd_prepare,
|
cmd_prepare,
|
||||||
cmd_bind,
|
cmd_bind,
|
||||||
cmd_step,
|
cmd_step,
|
||||||
@@ -281,6 +282,18 @@ do_exec(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
|||||||
return make_atom(env, "ok");
|
return make_atom(env, "ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nr of changes
|
||||||
|
*/
|
||||||
|
static ERL_NIF_TERM
|
||||||
|
do_changes(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg)
|
||||||
|
{
|
||||||
|
int changes = sqlite3_changes(conn->db);
|
||||||
|
|
||||||
|
ERL_NIF_TERM changes_term = enif_make_int64(env, changes);
|
||||||
|
return make_ok_tuple(env, changes_term);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* insert action
|
* insert action
|
||||||
*/
|
*/
|
||||||
@@ -492,7 +505,14 @@ do_step(ErlNifEnv *env, sqlite3 *db, sqlite3_stmt *stmt)
|
|||||||
if(rc == SQLITE_BUSY)
|
if(rc == SQLITE_BUSY)
|
||||||
return make_atom(env, "$busy");
|
return make_atom(env, "$busy");
|
||||||
|
|
||||||
return make_sqlite3_error_tuple(env, rc, db);
|
if(rc == SQLITE_ERROR)
|
||||||
|
return make_sqlite3_error_tuple(env, rc, db);
|
||||||
|
if(rc == SQLITE_MISUSE)
|
||||||
|
return make_error_tuple(env, "misuse");
|
||||||
|
if(rc == SQLITE_CONSTRAINT)
|
||||||
|
return make_sqlite3_error_tuple(env, rc, db);
|
||||||
|
|
||||||
|
return make_error_tuple(env, "unexpected_return_value");
|
||||||
}
|
}
|
||||||
|
|
||||||
static ERL_NIF_TERM
|
static ERL_NIF_TERM
|
||||||
@@ -540,6 +560,8 @@ evaluate_command(esqlite_command *cmd, esqlite_connection *conn)
|
|||||||
return do_open(cmd->env, conn, cmd->arg);
|
return do_open(cmd->env, conn, cmd->arg);
|
||||||
case cmd_exec:
|
case cmd_exec:
|
||||||
return do_exec(cmd->env, conn, cmd->arg);
|
return do_exec(cmd->env, conn, cmd->arg);
|
||||||
|
case cmd_changes:
|
||||||
|
return do_changes(cmd->env, conn, cmd->arg);
|
||||||
case cmd_prepare:
|
case cmd_prepare:
|
||||||
return do_prepare(cmd->env, conn, cmd->arg);
|
return do_prepare(cmd->env, conn, cmd->arg);
|
||||||
case cmd_step:
|
case cmd_step:
|
||||||
@@ -695,6 +717,37 @@ esqlite_exec(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
|||||||
return push_command(env, db, cmd);
|
return push_command(env, db, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count the nr of changes of last statement
|
||||||
|
*/
|
||||||
|
static ERL_NIF_TERM
|
||||||
|
esqlite_changes(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
||||||
|
{
|
||||||
|
esqlite_connection *db;
|
||||||
|
esqlite_command *cmd = NULL;
|
||||||
|
ErlNifPid pid;
|
||||||
|
|
||||||
|
if(argc != 3)
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &db))
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
if(!enif_is_ref(env, argv[1]))
|
||||||
|
return make_error_tuple(env, "invalid_ref");
|
||||||
|
if(!enif_get_local_pid(env, argv[2], &pid))
|
||||||
|
return make_error_tuple(env, "invalid_pid");
|
||||||
|
|
||||||
|
cmd = command_create();
|
||||||
|
if(!cmd)
|
||||||
|
return make_error_tuple(env, "command_create_failed");
|
||||||
|
|
||||||
|
/* command */
|
||||||
|
cmd->type = cmd_changes;
|
||||||
|
cmd->ref = enif_make_copy(cmd->env, argv[1]);
|
||||||
|
cmd->pid = pid;
|
||||||
|
|
||||||
|
return push_command(env, db, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static ERL_NIF_TERM
|
static ERL_NIF_TERM
|
||||||
esqlite_insert(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
esqlite_insert(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
|
||||||
{
|
{
|
||||||
@@ -936,6 +989,7 @@ static ErlNifFunc nif_funcs[] = {
|
|||||||
{"start", 0, esqlite_start},
|
{"start", 0, esqlite_start},
|
||||||
{"open", 4, esqlite_open},
|
{"open", 4, esqlite_open},
|
||||||
{"exec", 4, esqlite_exec},
|
{"exec", 4, esqlite_exec},
|
||||||
|
{"changes", 3, esqlite_changes},
|
||||||
{"prepare", 4, esqlite_prepare},
|
{"prepare", 4, esqlite_prepare},
|
||||||
{"insert", 4, esqlite_insert},
|
{"insert", 4, esqlite_insert},
|
||||||
{"step", 3, esqlite_step},
|
{"step", 3, esqlite_step},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{require_otp_vsn, "R14|R15|R16"}.
|
{require_min_otp_vsn, "R14"}.
|
||||||
{port_env, [
|
{port_env, [
|
||||||
{"CFLAGS", "$CFLAGS -DSQLITE_THREADSAFE=1 -DSQLITE_USE_URI -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS"}]}.
|
{"CFLAGS", "$CFLAGS -DSQLITE_THREADSAFE=1 -DSQLITE_USE_URI -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS"}]}.
|
||||||
{port_specs, [
|
{port_specs, [
|
||||||
|
|||||||
@@ -23,8 +23,9 @@
|
|||||||
%% higher-level export
|
%% higher-level export
|
||||||
-export([open/1, open/2,
|
-export([open/1, open/2,
|
||||||
exec/2, exec/3,
|
exec/2, exec/3,
|
||||||
|
changes/1, changes/2,
|
||||||
insert/2,
|
insert/2,
|
||||||
prepare/2, prepare/3,
|
prepare/2, prepare/3,
|
||||||
step/1, step/2,
|
step/1, step/2,
|
||||||
bind/2, bind/3,
|
bind/2, bind/3,
|
||||||
fetchone/1,
|
fetchone/1,
|
||||||
@@ -122,6 +123,7 @@ foreach(F, Sql, Connection) ->
|
|||||||
foreach_s(F, Statement) when is_function(F, 1) ->
|
foreach_s(F, Statement) when is_function(F, 1) ->
|
||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' -> ok;
|
'$done' -> ok;
|
||||||
|
{error, _} = E -> F(E);
|
||||||
{row, Row} ->
|
{row, Row} ->
|
||||||
F(Row),
|
F(Row),
|
||||||
foreach_s(F, Statement)
|
foreach_s(F, Statement)
|
||||||
@@ -130,6 +132,7 @@ foreach_s(F, Statement) when is_function(F, 2) ->
|
|||||||
ColumnNames = column_names(Statement),
|
ColumnNames = column_names(Statement),
|
||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' -> ok;
|
'$done' -> ok;
|
||||||
|
{error, _} = E -> F([], E);
|
||||||
{row, Row} ->
|
{row, Row} ->
|
||||||
F(ColumnNames, Row),
|
F(ColumnNames, Row),
|
||||||
foreach_s(F, Statement)
|
foreach_s(F, Statement)
|
||||||
@@ -144,6 +147,7 @@ foreach_s(F, Statement) when is_function(F, 2) ->
|
|||||||
map_s(F, Statement) when is_function(F, 1) ->
|
map_s(F, Statement) when is_function(F, 1) ->
|
||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' -> [];
|
'$done' -> [];
|
||||||
|
{error, _} = E -> F(E);
|
||||||
{row, Row} ->
|
{row, Row} ->
|
||||||
[F(Row) | map_s(F, Statement)]
|
[F(Row) | map_s(F, Statement)]
|
||||||
end;
|
end;
|
||||||
@@ -151,6 +155,7 @@ map_s(F, Statement) when is_function(F, 2) ->
|
|||||||
ColumnNames = column_names(Statement),
|
ColumnNames = column_names(Statement),
|
||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' -> [];
|
'$done' -> [];
|
||||||
|
{error, _} = E -> F([], E);
|
||||||
{row, Row} ->
|
{row, Row} ->
|
||||||
[F(ColumnNames, Row) | map_s(F, Statement)]
|
[F(ColumnNames, Row) | map_s(F, Statement)]
|
||||||
end.
|
end.
|
||||||
@@ -160,6 +165,7 @@ map_s(F, Statement) when is_function(F, 2) ->
|
|||||||
fetchone(Statement) ->
|
fetchone(Statement) ->
|
||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' -> ok;
|
'$done' -> ok;
|
||||||
|
{error, _} = E -> E;
|
||||||
{row, Row} -> Row
|
{row, Row} -> Row
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@@ -169,6 +175,7 @@ fetchall(Statement) ->
|
|||||||
case try_step(Statement, 0) of
|
case try_step(Statement, 0) of
|
||||||
'$done' ->
|
'$done' ->
|
||||||
[];
|
[];
|
||||||
|
{error, _} = E -> E;
|
||||||
{row, Row} ->
|
{row, Row} ->
|
||||||
[Row | fetchall(Statement)]
|
[Row | fetchall(Statement)]
|
||||||
end.
|
end.
|
||||||
@@ -211,6 +218,16 @@ exec(Sql, Params, {connection, _, _}=Connection, Timeout) when is_list(Params) -
|
|||||||
step(Statement, Timeout).
|
step(Statement, Timeout).
|
||||||
|
|
||||||
|
|
||||||
|
%% @doc Return the number of affected rows of last statement.
|
||||||
|
changes(Connection) ->
|
||||||
|
changes(Connection, ?DEFAULT_TIMEOUT).
|
||||||
|
|
||||||
|
%% @doc Return the number of affected rows of last statement.
|
||||||
|
changes({connection, _Ref, Connection}, Timeout) ->
|
||||||
|
Ref = make_ref(),
|
||||||
|
ok = esqlite3_nif:changes(Connection, Ref, self()),
|
||||||
|
receive_answer(Ref, Timeout).
|
||||||
|
|
||||||
%% @doc Insert records, returns the last rowid.
|
%% @doc Insert records, returns the last rowid.
|
||||||
%%
|
%%
|
||||||
%% @spec insert(iolist(), connection()) -> {ok, integer()} | {error, error_message()}
|
%% @spec insert(iolist(), connection()) -> {ok, integer()} | {error, error_message()}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
-export([start/0,
|
-export([start/0,
|
||||||
open/4,
|
open/4,
|
||||||
exec/4,
|
exec/4,
|
||||||
|
changes/3,
|
||||||
insert/4,
|
insert/4,
|
||||||
prepare/4,
|
prepare/4,
|
||||||
step/3,
|
step/3,
|
||||||
@@ -70,6 +71,14 @@ open(_Db, _Ref, _Dest, _Filename) ->
|
|||||||
exec(_Db, _Ref, _Dest, _Sql) ->
|
exec(_Db, _Ref, _Dest, _Sql) ->
|
||||||
exit(nif_library_not_loaded).
|
exit(nif_library_not_loaded).
|
||||||
|
|
||||||
|
%% @doc Get the number of affected rows of last statement
|
||||||
|
%%
|
||||||
|
%% When the statement is executed Dest will receive message {Ref, answer()}
|
||||||
|
%% with answer() integer | {error, reason()}
|
||||||
|
%%
|
||||||
|
changes(_Db, _Ref, _Dest) ->
|
||||||
|
exit(nif_library_not_loaded).
|
||||||
|
|
||||||
%% @doc
|
%% @doc
|
||||||
%%
|
%%
|
||||||
%% @spec prepare(connection(), reference(), pid(), string()) -> ok | {error, message()}
|
%% @spec prepare(connection(), reference(), pid(), string()) -> ok | {error, message()}
|
||||||
|
|||||||
@@ -25,11 +25,20 @@ simple_query_test() ->
|
|||||||
ok = esqlite3:exec("begin;", Db),
|
ok = esqlite3:exec("begin;", Db),
|
||||||
ok = esqlite3:exec("create table test_table(one varchar(10), two int);", Db),
|
ok = esqlite3:exec("create table test_table(one varchar(10), two int);", Db),
|
||||||
ok = esqlite3:exec(["insert into test_table values(", "\"hello1\"", ",", "10" ");"], Db),
|
ok = esqlite3:exec(["insert into test_table values(", "\"hello1\"", ",", "10" ");"], Db),
|
||||||
|
{ok, 1} = esqlite3:changes(Db),
|
||||||
|
|
||||||
ok = esqlite3:exec(["insert into test_table values(", "\"hello2\"", ",", "11" ");"], Db),
|
ok = esqlite3:exec(["insert into test_table values(", "\"hello2\"", ",", "11" ");"], Db),
|
||||||
|
{ok, 1} = esqlite3:changes(Db),
|
||||||
ok = esqlite3:exec(["insert into test_table values(", "\"hello3\"", ",", "12" ");"], Db),
|
ok = esqlite3:exec(["insert into test_table values(", "\"hello3\"", ",", "12" ");"], Db),
|
||||||
|
{ok, 1} = esqlite3:changes(Db),
|
||||||
ok = esqlite3:exec(["insert into test_table values(", "\"hello4\"", ",", "13" ");"], Db),
|
ok = esqlite3:exec(["insert into test_table values(", "\"hello4\"", ",", "13" ");"], Db),
|
||||||
|
{ok, 1} = esqlite3:changes(Db),
|
||||||
ok = esqlite3:exec("commit;", Db),
|
ok = esqlite3:exec("commit;", Db),
|
||||||
ok = esqlite3:exec("select * from test_table;", Db),
|
ok = esqlite3:exec("select * from test_table;", Db),
|
||||||
|
|
||||||
|
ok = esqlite3:exec("delete from test_table;", Db),
|
||||||
|
{ok, 4} = esqlite3:changes(Db),
|
||||||
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
prepare_test() ->
|
prepare_test() ->
|
||||||
@@ -39,6 +48,7 @@ prepare_test() ->
|
|||||||
{ok, Statement} = esqlite3:prepare("insert into test_table values(\"one\", 2)", Db),
|
{ok, Statement} = esqlite3:prepare("insert into test_table values(\"one\", 2)", Db),
|
||||||
|
|
||||||
'$done' = esqlite3:step(Statement),
|
'$done' = esqlite3:step(Statement),
|
||||||
|
{ok, 1} = esqlite3:changes(Db),
|
||||||
|
|
||||||
ok = esqlite3:exec(["insert into test_table values(", "\"hello4\"", ",", "13" ");"], Db),
|
ok = esqlite3:exec(["insert into test_table values(", "\"hello4\"", ",", "13" ");"], Db),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user