Index: ext/rbu/rbuvacuum.test ================================================================== --- ext/rbu/rbuvacuum.test +++ ext/rbu/rbuvacuum.test @@ -296,10 +296,18 @@ } {SQLITE_ERROR} do_test 2.1.2 { list [catch { rbu close } msg] $msg } {1 {SQLITE_ERROR - cannot vacuum wal mode database}} +do_test 2.1.3 { + sqlite3rbu_vacuum rbu test.db state.db + rbu step +} {SQLITE_ERROR} +do_test 2.1.4 { + list [catch { rbu close_no_error } msg] $msg +} {1 SQLITE_ERROR} + reset_db do_execsql_test 2.2.0 { CREATE TABLE tx(a PRIMARY KEY, b BLOB); INSERT INTO tx VALUES(1, randomblob(900)); INSERT INTO tx SELECT a+1, randomblob(900) FROM tx; Index: ext/rbu/sqlite3rbu.c ================================================================== --- ext/rbu/sqlite3rbu.c +++ ext/rbu/sqlite3rbu.c @@ -3785,11 +3785,15 @@ sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; - *pzErrmsg = p->zErrmsg; + if( pzErrmsg ){ + *pzErrmsg = p->zErrmsg; + }else{ + sqlite3_free(p->zErrmsg); + } sqlite3_free(p->zState); sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; Index: ext/rbu/sqlite3rbu.h ================================================================== --- ext/rbu/sqlite3rbu.h +++ ext/rbu/sqlite3rbu.h @@ -418,14 +418,14 @@ ** as fully applied. Otherwise, assuming no error has occurred, save the ** current state of the RBU update appliation to the RBU database. ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an -** SQLite error code is returned. Additionally, *pzErrmsg may be set to -** point to a buffer containing a utf-8 formatted English language error -** message. It is the responsibility of the caller to eventually free any -** such buffer using sqlite3_free(). +** SQLite error code is returned. Additionally, if pzErrmsg is not NULL, +** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted +** English language error message. It is the responsibility of the caller to +** eventually free any such buffer using sqlite3_free(). ** ** Otherwise, if no error occurs, this function returns SQLITE_OK if the ** update has been partially applied, or SQLITE_DONE if it has been ** completely applied. */ Index: ext/rbu/test_rbu.c ================================================================== --- ext/rbu/test_rbu.c +++ ext/rbu/test_rbu.c @@ -76,10 +76,11 @@ {"dbMain_eval", 3, "SQL"}, /* 4 */ {"bp_progress", 2, ""}, /* 5 */ {"db", 3, "RBU"}, /* 6 */ {"state", 2, ""}, /* 7 */ {"progress", 2, ""}, /* 8 */ + {"close_no_error", 2, ""}, /* 9 */ {0,0,0} }; int iCmd; if( objc<2 ){ @@ -100,15 +101,20 @@ int rc = sqlite3rbu_step(pRbu); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); break; } + case 9: /* close_no_error */ case 1: /* close */ { char *zErrmsg = 0; int rc; Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); - rc = sqlite3rbu_close(pRbu, &zErrmsg); + if( iCmd==1 ){ + rc = sqlite3rbu_close(pRbu, &zErrmsg); + }else{ + rc = sqlite3rbu_close(pRbu, 0); + } if( rc==SQLITE_OK || rc==SQLITE_DONE ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); assert( zErrmsg==0 ); }else{ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));