diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index fd335b1..202df82 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -64,6 +64,7 @@ typedef enum { cmd_close, cmd_stop, cmd_insert, + cmd_last_insert_rowid, cmd_get_autocommit, } command_type; @@ -373,6 +374,14 @@ do_insert(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) return make_ok_tuple(env, last_rowid_term); } +static ERL_NIF_TERM +do_last_insert_rowid(ErlNifEnv *env, esqlite_connection *conn) +{ + sqlite3_int64 last_rowid = sqlite3_last_insert_rowid(conn->db); + ERL_NIF_TERM last_rowid_term = enif_make_int64(env, last_rowid); + return make_ok_tuple(env, last_rowid_term); +} + /* */ static ERL_NIF_TERM @@ -731,6 +740,8 @@ evaluate_command(esqlite_command *cmd, esqlite_connection *conn) return do_close(cmd->env, conn, cmd->arg); case cmd_insert: return do_insert(cmd->env, conn, cmd->arg); + case cmd_last_insert_rowid: + return do_last_insert_rowid(cmd->env, conn); case cmd_get_autocommit: return do_get_autocommit(cmd->env, conn); default: @@ -968,6 +979,34 @@ esqlite_insert(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) return push_command(env, db, cmd); } +static ERL_NIF_TERM +esqlite_last_insert_rowid(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_last_insert_rowid; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + + return push_command(env, db, cmd); +} + static ERL_NIF_TERM esqlite_get_autocommit(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { @@ -1308,6 +1347,7 @@ static ErlNifFunc nif_funcs[] = { {"changes", 3, esqlite_changes}, {"prepare", 4, esqlite_prepare}, {"insert", 4, esqlite_insert}, + {"last_insert_rowid", 3, esqlite_last_insert_rowid}, {"get_autocommit", 3, esqlite_get_autocommit}, {"multi_step", 5, esqlite_multi_step}, {"reset", 4, esqlite_reset}, diff --git a/src/esqlite3.erl b/src/esqlite3.erl index 81b247e..ab8a023 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -26,6 +26,7 @@ exec/2, exec/3, exec/4, changes/1, changes/2, insert/2, + last_insert_rowid/1, get_autocommit/1, get_autocommit/2, prepare/2, prepare/3, @@ -380,6 +381,21 @@ insert(Sql, {connection, _Ref, Connection}, Timeout) -> ok = esqlite3_nif:insert(Connection, Ref, self(), Sql), receive_answer(Connection, Ref, Timeout). +%% @doc Get the last insert rowid, using the default timeout. +%% +-spec last_insert_rowid(connection()) -> {ok, rowid()} | {error, _}. +last_insert_rowid(Connection) -> + last_insert_rowid(Connection, ?DEFAULT_TIMEOUT). + +%% @doc Get the last insert rowid. +%% +-spec last_insert_rowid(connection(), timeout()) -> {ok, integer()} | {error, _}. +last_insert_rowid({connection, _Ref, Connection}, Timeout) -> + Ref = make_ref(), + ok = esqlite3_nif:last_insert_rowid(Connection, Ref, self()), + receive_answer(Connection, Ref, Timeout). + +%% @doc Get autocommit %% @doc Check if the connection is in auto-commit mode. %% See: [https://sqlite.org/c3ref/get_autocommit.html] for more details. %% diff --git a/src/esqlite3_nif.erl b/src/esqlite3_nif.erl index 3f2503a..5ad9ab1 100644 --- a/src/esqlite3_nif.erl +++ b/src/esqlite3_nif.erl @@ -27,6 +27,7 @@ exec/4, changes/3, insert/4, + last_insert_rowid/3, get_autocommit/3, prepare/4, multi_step/5, @@ -145,6 +146,12 @@ close(_Db, _Ref, _Dest) -> insert(_Db, _Ref, _Dest, _Sql) -> erlang:nif_error(nif_library_not_loaded). +%% @doc Get the last insert rowid. +%% +%% @spec insert(connection(), Ref::reference(), Dest::pid()) -> {ok, integer()} | {error, message()} +last_insert_rowid(_Db, _Ref, _Dest) -> + erlang:nif_error(nif_library_not_loaded). + %% @doc Get automcommit %% -spec get_autocommit(esqlite:connection(), reference(), pid()) -> ok | {error, any()}. diff --git a/test/esqlite_test.erl b/test/esqlite_test.erl index d4f37bd..e35750d 100644 --- a/test/esqlite_test.erl +++ b/test/esqlite_test.erl @@ -31,6 +31,15 @@ get_autocommit_test() -> true = esqlite3:get_autocommit(Db), ok. +last_insert_rowid_test() -> + {ok, Db} = esqlite3:open(":memory:"), + ok = esqlite3:exec("CREATE TABLE test (id INTEGER PRIMARY KEY, val STRING);", Db), + ok = esqlite3:exec("INSERT INTO test (val) VALUES ('this is a test');", Db), + {ok, 1} = esqlite3:last_insert_rowid(Db), + ok = esqlite3:exec("INSERT INTO test (val) VALUES ('this is another test');", Db), + {ok, 2} = esqlite3:last_insert_rowid(Db), + ok. + update_hook_test() -> {ok, Db} = esqlite3:open(":memory:"), ok = esqlite3:set_update_hook(self(), Db),