diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index 18a1145..b9d8784 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -52,6 +52,7 @@ typedef enum { cmd_unknown, cmd_open, cmd_exec, + cmd_changes, cmd_prepare, cmd_bind, cmd_step, @@ -280,6 +281,18 @@ do_exec(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) 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 */ @@ -544,6 +557,8 @@ evaluate_command(esqlite_command *cmd, esqlite_connection *conn) return do_open(cmd->env, conn, cmd->arg); case cmd_exec: return do_exec(cmd->env, conn, cmd->arg); + case cmd_changes: + return do_changes(cmd->env, conn, cmd->arg); case cmd_prepare: return do_prepare(cmd->env, conn, cmd->arg); case cmd_step: @@ -699,6 +714,37 @@ esqlite_exec(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) 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 esqlite_insert(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { @@ -940,6 +986,7 @@ static ErlNifFunc nif_funcs[] = { {"start", 0, esqlite_start}, {"open", 4, esqlite_open}, {"exec", 4, esqlite_exec}, + {"changes", 3, esqlite_changes}, {"prepare", 4, esqlite_prepare}, {"insert", 4, esqlite_insert}, {"step", 3, esqlite_step}, diff --git a/src/esqlite3.erl b/src/esqlite3.erl index 597accc..4d05ad3 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -23,8 +23,9 @@ %% higher-level export -export([open/1, open/2, exec/2, exec/3, + changes/1, changes/2, insert/2, - prepare/2, prepare/3, + prepare/2, prepare/3, step/1, step/2, bind/2, bind/3, fetchone/1, @@ -200,6 +201,16 @@ exec(Sql, {connection, _Ref, Connection}, Timeout) -> ok = esqlite3_nif:exec(Connection, Ref, self(), Sql), receive_answer(Ref, 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. %% %% @spec insert(iolist(), connection()) -> {ok, integer()} | {error, error_message()} diff --git a/src/esqlite3_nif.erl b/src/esqlite3_nif.erl index 147ec0b..efab77e 100644 --- a/src/esqlite3_nif.erl +++ b/src/esqlite3_nif.erl @@ -24,6 +24,7 @@ -export([start/0, open/4, exec/4, + changes/3, insert/4, prepare/4, step/3, @@ -70,6 +71,14 @@ open(_Db, _Ref, _Dest, _Filename) -> exec(_Db, _Ref, _Dest, _Sql) -> 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 %% %% @spec prepare(connection(), reference(), pid(), string()) -> ok | {error, message()} diff --git a/test/esqlite_test.erl b/test/esqlite_test.erl index c51b32d..8685679 100644 --- a/test/esqlite_test.erl +++ b/test/esqlite_test.erl @@ -25,11 +25,20 @@ simple_query_test() -> ok = esqlite3:exec("begin;", 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, 1} = esqlite3:changes(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, 1} = esqlite3:changes(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("select * from test_table;", Db), + + ok = esqlite3:exec("delete from test_table;", Db), + {ok, 4} = esqlite3:changes(Db), + ok. prepare_test() -> @@ -39,6 +48,7 @@ prepare_test() -> {ok, Statement} = esqlite3:prepare("insert into test_table values(\"one\", 2)", Db), '$done' = esqlite3:step(Statement), + {ok, 1} = esqlite3:changes(Db), ok = esqlite3:exec(["insert into test_table values(", "\"hello4\"", ",", "13" ");"], Db),