diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index 4f76eb9..418bcf5 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -57,7 +57,8 @@ typedef enum { cmd_step, cmd_column_names, cmd_close, - cmd_stop + cmd_stop, + cmd_insert } command_type; typedef struct { @@ -277,6 +278,27 @@ do_exec(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) return make_atom(env, "ok"); } +/* +* insert action +*/ +static ERL_NIF_TERM +do_insert(ErlNifEnv *env, esqlite_connection *conn, const ERL_NIF_TERM arg) +{ + ErlNifBinary bin; + int rc; + ERL_NIF_TERM eos = enif_make_int(env, 0); + + enif_inspect_iolist_as_binary(env, + enif_make_list2(env, arg, eos), &bin); + + rc = sqlite3_exec(conn->db, (char *) bin.data, NULL, NULL, NULL); + if(rc != SQLITE_OK) + return make_sqlite3_error_tuple(env, rc, conn->db); + sqlite3_int64 last_rowid = sqlite3_last_insert_rowid(conn->db); + ERL_NIF_TERM last_rowid_term = enif_make_int(env, last_rowid); + return make_ok_tuple(env, last_rowid_term); +} + /* */ static ERL_NIF_TERM @@ -530,6 +552,8 @@ evaluate_command(esqlite_command *cmd, esqlite_connection *conn) return do_column_names(cmd->env, cmd->stmt); case cmd_close: return do_close(cmd->env, conn, cmd->arg); + case cmd_insert: + return do_insert(cmd->env, conn, cmd->arg); default: return make_error_tuple(cmd->env, "invalid_command"); } @@ -673,6 +697,35 @@ esqlite_exec(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) return push_command(env, db, cmd); } +static ERL_NIF_TERM +esqlite_insert(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + esqlite_connection *db; + esqlite_command *cmd = NULL; + ErlNifPid pid; + + if(argc != 4) + 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_insert; + cmd->ref = enif_make_copy(cmd->env, argv[1]); + cmd->pid = pid; + cmd->arg = enif_make_copy(cmd->env, argv[3]); + + return push_command(env, db, cmd); +} + /* * Prepare the sql statement @@ -884,6 +937,7 @@ static ErlNifFunc nif_funcs[] = { {"open", 4, esqlite_open}, {"exec", 4, esqlite_exec}, {"prepare", 4, esqlite_prepare}, + {"insert", 4, esqlite_insert}, {"step", 3, esqlite_step}, // TODO: {"esqlite_bind", 3, esqlite_bind_named}, {"bind", 4, esqlite_bind}, diff --git a/src/esqlite3.erl b/src/esqlite3.erl index 1b40920..102c663 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -23,6 +23,7 @@ %% higher-level export -export([open/1, open/2, exec/2, exec/3, + insert/2, prepare/2, prepare/3, step/1, step/2, bind/2, bind/3, @@ -199,6 +200,20 @@ exec(Sql, {connection, _Ref, Connection}, Timeout) -> ok = esqlite3_nif:exec(Connection, Ref, self(), Sql), receive_answer(Ref, Timeout). +%% @doc Insert records, returns the last rowid. +%% +%% @spec insert(iolist(), connection()) -> {ok, integer()} | {error, error_message()} +insert(Sql, Connection) -> + insert(Sql, Connection, ?DEFAULT_TIMEOUT). + +%% @doc Insert +%% +%% @spec insert(iolist(), connection(), timeout()) -> {ok, integer()} | {error, error_message()} +insert(Sql, {connection, _Ref, Connection}, Timeout) -> + Ref = make_ref(), + ok = esqlite3_nif:insert(Connection, Ref, self(), Sql), + receive_answer(Ref, Timeout). + %% @doc Prepare a statement %% %% @spec prepare(iolist(), connection()) -> {ok, prepared_statement()} | {error, error_message()} diff --git a/src/esqlite3_nif.erl b/src/esqlite3_nif.erl index e1de979..147ec0b 100644 --- a/src/esqlite3_nif.erl +++ b/src/esqlite3_nif.erl @@ -21,15 +21,16 @@ -author("Maas-Maarten Zeeman "). %% low-level exports --export([start/0, - open/4, - exec/4, - prepare/4, - step/3, - finalize/3, - bind/4, - column_names/3, - close/3 +-export([start/0, + open/4, + exec/4, + insert/4, + prepare/4, + step/3, + finalize/3, + bind/4, + column_names/3, + close/3 ]). -on_load(init/0). @@ -37,9 +38,9 @@ init() -> NifName = "esqlite3_nif", NifFileName = case code:priv_dir(esqlite) of - {error, bad_name} -> filename:join("priv", NifName); - Dir -> filename:join(Dir, NifName) - end, + {error, bad_name} -> filename:join("priv", NifName); + Dir -> filename:join(Dir, NifName) + end, ok = erlang:load_nif(NifFileName, 0). %% @doc Start a low level thread which will can handle sqlite3 calls. @@ -105,7 +106,12 @@ column_names(_Stmt, _Ref, _Dest) -> close(_Db, _Ref, _Dest) -> exit(nif_library_not_loaded). - + +%% @doc Insert record +%% +%% @spec insert(connection(), Ref::reference(), Dest::pid(), string()) -> {ok, integer()} | {error, message()} +insert(_Db, _Ref, _Dest, _Sql) -> + exit(nif_library_not_loaded).