diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index 8dce7a6..932c5e0 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -1745,7 +1745,7 @@ static ErlNifFunc nif_funcs[] = { {"backup_init", 6, esqlite_backup_init}, {"backup_step", 5, esqlite_backup_step}, {"backup_remaining", 4, esqlite_backup_remaining}, - {"backup_pagecount", 4, esqlite_backup_remaining}, + {"backup_pagecount", 4, esqlite_backup_pagecount}, {"backup_finish", 4, esqlite_backup_finish}, {"interrupt", 1, esqlite_interrupt, ERL_NIF_DIRTY_JOB_IO_BOUND}, diff --git a/src/esqlite3.erl b/src/esqlite3.erl index 1ceeb31..e4250bf 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -36,6 +36,7 @@ column_names/1, column_names/2, column_types/1, column_types/2, backup_init/4, backup_init/5, + backup_finish/1, backup_finish/2, backup_remaining/1, backup_remaining/2, backup_pagecount/1, backup_pagecount/2, backup_step/2, backup_step/3, @@ -507,6 +508,17 @@ backup_init(#connection{raw_connection=Dest}, DestName, #connection{raw_connecti end. +%% @doc Release the resources held by the backup. +-spec backup_finish(backup()) -> ok | {error, _}. +backup_finish(Backup) -> + backup_finish(Backup, ?DEFAULT_TIMEOUT). +%% @doc Like backup_finish/1, but with an extra timeout. +-spec backup_finish(backup(), timeout()) -> ok | {error, _}. +backup_finish(#backup{raw_connection=Conn, raw_backup=Back}, Timeout) -> + Ref = make_ref(), + ok = esqlite3_nif:backup_finish(Conn, Back, Ref, self()), + receive_answer(Conn, Ref, Timeout). + %% @doc Do a backup step. -spec backup_step(backup(), integer()) -> ok | {error, _}. backup_step(Backup, NPage) -> diff --git a/test/esqlite_test.erl b/test/esqlite_test.erl index 87eaa7d..2bac6c2 100644 --- a/test/esqlite_test.erl +++ b/test/esqlite_test.erl @@ -10,7 +10,8 @@ -define(DB2, "./test/dbs/temp_db2.db"). open_single_database_test() -> - {ok, _C1} = esqlite3:open("test.db"), + cleanup(), + {ok, _C1} = esqlite3:open(?DB1), ok. close_test() -> @@ -29,13 +30,19 @@ close_test() -> ok. open_multiple_same_databases_test() -> + cleanup(), + {ok, _C1} = esqlite3:open(?DB1), {ok, _C2} = esqlite3:open(?DB1), + + cleanup(), ok. open_multiple_different_databases_test() -> + cleanup(), {ok, _C1} = esqlite3:open(?DB1), {ok, _C2} = esqlite3:open(?DB2), + cleanup(), ok. get_autocommit_test() -> @@ -444,6 +451,8 @@ prepare_and_close_connection_test() -> ok. backup_test() -> + cleanup(), + {ok, Dest} = esqlite3:open(?DB1), {ok, Source} = esqlite3:open(?DB2), @@ -452,8 +461,53 @@ backup_test() -> {ok, 0} = esqlite3:backup_pagecount(Backup), done = esqlite3:backup_step(Backup, 1), + cleanup(), + ok. +backup1_test() -> + cleanup(), + + {ok, Dest} = esqlite3:open(?DB1), + {ok, Source} = esqlite3:open(?DB2), + + [] = esqlite3:q("create table test(one, two)", Source), + [] = esqlite3:q("begin;", Source), + [] = esqlite3:q("insert into test values(randomblob(10000), randomblob(10000));", Source), + [] = esqlite3:q("insert into test values(randomblob(10000), randomblob(10000));", Source), + [] = esqlite3:q("insert into test values(randomblob(10000), randomblob(10000));", Source), + [] = esqlite3:q("insert into test values(randomblob(10000), randomblob(10000));", Source), + [] = esqlite3:q("insert into test values(randomblob(10000), randomblob(10000));", Source), + [] = esqlite3:q("commit;", Source), + + [{5}] = esqlite3:q("select count(*) from test", Source), + {error, {sqlite_error, "no such table: test"}} = esqlite3:q("select count(*) from test", Dest), + + {ok, Backup} = esqlite3:backup_init(Dest, "main", Source, "main"), + + {ok, 0} = esqlite3:backup_remaining(Backup), + {ok, 0} = esqlite3:backup_pagecount(Backup), + + %% Backup 1 page. + ok = esqlite3:backup_step(Backup, 1), + + {ok, 26} = esqlite3:backup_remaining(Backup), + {ok, 27} = esqlite3:backup_pagecount(Backup), + + %% Do all the remaining pages. + done = esqlite3:backup_step(Backup, -1), + + {ok, 0} = esqlite3:backup_remaining(Backup), + {ok, 27} = esqlite3:backup_pagecount(Backup), + + ok = esqlite3:backup_finish(Backup), + + [{5}] = esqlite3:q("select count(*) from test", Dest), + + cleanup(), + + ok. + sqlite_version_test() -> {ok, Db} = esqlite3:open(":memory:"), @@ -510,5 +564,20 @@ garbage_collect_test() -> receive after 500 -> ok end, erlang:garbage_collect(), + ok. +%% +%% Helpers +%% + +cleanup() -> + rm_rf(?DB1), + rm_rf(?DB2). + +rm_rf(Filename) -> + case file:delete(Filename) of + ok -> ok; + {error, _} -> ok + end. +