diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index c812c8e..8dce7a6 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -262,6 +262,10 @@ static void destruct_esqlite_backup(ErlNifEnv *env, void *arg) { esqlite_backup *backup = (esqlite_backup *) arg; + + if(backup->backup) { + sqlite3_backup_finish(backup->backup); + } backup->backup = NULL; } @@ -751,7 +755,6 @@ do_backup_init(ErlNifEnv *env, sqlite3 *db, const ERL_NIF_TERM arg) if(!enif_get_tuple(env, arg, &tuple_arity, &elements)) { return make_error_tuple(env, "no_tuple"); } - if(tuple_arity != 3) { return make_error_tuple(env, "invalid_tuple"); } @@ -791,9 +794,46 @@ do_backup_init(ErlNifEnv *env, sqlite3 *db, const ERL_NIF_TERM arg) } static ERL_NIF_TERM -do_backup_step(ErlNifEnv *env, const ERL_NIF_TERM arg) +do_backup_step(ErlNifEnv *env, sqlite3 *db, const ERL_NIF_TERM arg) { - return make_atom(env, "todo"); + int tuple_arity; + const ERL_NIF_TERM *elements; + esqlite_backup *esqlite_backup; + int n_page = 0; + int rc; + + if(db == NULL) { + return make_error_tuple(env, "closed"); + } + + if(!enif_get_tuple(env, arg, &tuple_arity, &elements)) { + return make_error_tuple(env, "no_tuple"); + } + if(tuple_arity != 2) { + return make_error_tuple(env, "invalid_tuple"); + } + + if(!enif_get_resource(env, elements[0], esqlite_backup_type, (void **) &esqlite_backup)) { + return make_error_tuple(env, "invalid"); + } + if(!esqlite_backup->backup) { + return make_error_tuple(env, "backup"); + } + + if(!enif_get_int(env, elements[1], &n_page)) { + return make_error_tuple(env, "n_page"); + } + + rc = sqlite3_backup_step(esqlite_backup->backup, n_page); + if(rc == SQLITE_DONE) { + return make_atom(env, "done"); + } + + if(rc != SQLITE_OK) { + return make_sqlite3_error_tuple(env, rc, db); + } + + return make_atom(env, "ok"); } static ERL_NIF_TERM @@ -833,7 +873,18 @@ do_backup_pagecount(ErlNifEnv *env, const ERL_NIF_TERM arg) static ERL_NIF_TERM do_backup_finish(ErlNifEnv *env, const ERL_NIF_TERM arg) { - return make_atom(env, "todo"); + esqlite_backup *esqlite_backup; + + if(!enif_get_resource(env, arg, esqlite_backup_type, (void **) &esqlite_backup)) { + return make_error_tuple(env, "invalid"); + } + + if(esqlite_backup->backup) { + (void) sqlite3_backup_finish(esqlite_backup->backup); + esqlite_backup->backup = NULL; + } + + return make_atom(env, "ok"); } static ERL_NIF_TERM @@ -884,7 +935,7 @@ evaluate_command(esqlite_command *cmd, esqlite_connection *conn) case cmd_backup_init: return do_backup_init(cmd->env, conn->db, cmd->arg); case cmd_backup_step: - return do_backup_step(cmd->env, cmd->arg); + return do_backup_step(cmd->env, conn->db, cmd->arg); case cmd_backup_remaining: return do_backup_remaining(cmd->env, cmd->arg); case cmd_backup_pagecount: diff --git a/src/esqlite3.erl b/src/esqlite3.erl index 5d20f94..eb9b8a0 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -39,6 +39,7 @@ backup_init/4, backup_init/5, backup_remaining/1, backup_remaining/2, backup_pagecount/1, backup_pagecount/2, + backup_step/2, backup_step/3, close/1, close/2, flush/0 ]). @@ -554,6 +555,20 @@ backup_init(#connection{raw_connection=Dest}, DestName, #connection{raw_connecti Error end. + +%% @doc Do a backup step. +-spec backup_step(backup(), integer()) -> ok | {error, _}. +backup_step(Backup, NPage) -> + backup_step(Backup, NPage, ?DEFAULT_TIMEOUT). + +%% @doc Do a backup step. +-spec backup_step(backup(), integer(), timeout()) -> ok | {error, _}. +backup_step(#backup{raw_connection=Conn, raw_backup=Back}, NPage, Timeout) -> + Ref = make_ref(), + ok = esqlite3_nif:backup_step(Conn, Back, NPage, Ref, self()), + receive_answer(Conn, Ref, Timeout). + + %% @doc Get the remaining number of pages which need to be backed up. -spec backup_remaining(backup()) -> {ok, pos_integer()} | {error, _}. backup_remaining(Backup) -> diff --git a/src/esqlite3_nif.erl b/src/esqlite3_nif.erl index 5d8563c..a93c4a0 100644 --- a/src/esqlite3_nif.erl +++ b/src/esqlite3_nif.erl @@ -143,7 +143,7 @@ column_types(_Db, _Stmt, _Ref, _Dest) -> erlang:nif_error(nif_library_not_loaded). %% @doc Initialize a backup procedure of a database. --spec backup_init(raw_connection(), iodata(), raw_connection(), iodata(), reference(), pid()) -> ok | {error, _}. +-spec backup_init(raw_connection(), string(), raw_connection(), string(), reference(), pid()) -> ok | {error, _}. backup_init(_DestDb, _DestName, _SourceDb, _SourceName, _Ref, _Dest) -> erlang:nif_error(nif_library_not_loaded). diff --git a/test/esqlite_test.erl b/test/esqlite_test.erl index 7e20d07..93f079e 100644 --- a/test/esqlite_test.erl +++ b/test/esqlite_test.erl @@ -447,6 +447,7 @@ backup_test() -> {ok, Backup} = esqlite3:backup_init(Dest, "main", Source, "main"), {ok, 0} = esqlite3:backup_remaining(Backup), {ok, 0} = esqlite3:backup_pagecount(Backup), + done = esqlite3:backup_step(Backup, 1), ok.