From f8bd49ee22fcd900013e9cdbfd374ab51b211e88 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 20 Nov 2014 19:19:02 +0000 Subject: [PATCH] Add the "ota_delta()" feature for delta-compressed updates. FossilOrigin-Name: c64dcd1788f5cc7db197a0ec4ab0981f34a72c6b --- ext/ota/ota8.test | 75 +++++++++++++++++++++++++++++++++++++++++++ ext/ota/sqlite3ota.c | 76 ++++++++++++++++++++++++++++++++++++++++---- ext/ota/sqlite3ota.h | 34 ++++++++++++++++++++ manifest | 15 +++++---- manifest.uuid | 2 +- 5 files changed, 187 insertions(+), 15 deletions(-) create mode 100644 ext/ota/ota8.test diff --git a/ext/ota/ota8.test b/ext/ota/ota8.test new file mode 100644 index 0000000000..24a6e72248 --- /dev/null +++ b/ext/ota/ota8.test @@ -0,0 +1,75 @@ +# 2014 November 20 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test the ota_delta() feature. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source $testdir/tester.tcl +set ::testprefix ota8 + +do_execsql_test 1.0 { + CREATE TABLE t1(x, y PRIMARY KEY, z); + INSERT INTO t1 VALUES(NULL, 1, 'one'); + INSERT INTO t1 VALUES(NULL, 2, 'two'); + INSERT INTO t1 VALUES(NULL, 3, 'three'); + CREATE INDEX i1z ON t1(z, x); +} + +do_test 1.1 { + forcedelete ota.db + sqlite3 db2 ota.db + db2 eval { + CREATE TABLE data_t1(x, y, z, ota_control); + INSERT INTO data_t1 VALUES('a', 1, '_i' , 'x.d'); + INSERT INTO data_t1 VALUES('b', 2, 2 , '..x'); + INSERT INTO data_t1 VALUES('_iii', 3, '-III' , 'd.d'); + } + db2 close +} {} + +do_test 1.2.1 { + sqlite3ota ota test.db ota.db + ota step +} {SQLITE_ERROR} +do_test 1.2.2 { + list [catch {ota close} msg] $msg +} {1 {SQLITE_ERROR - no such function: ota_delta}} + +proc ota_delta {orig new} { + return "${orig}${new}" +} + +do_test 1.3.1 { + while 1 { + sqlite3ota ota test.db ota.db + ota create_ota_delta + set rc [ota step] + if {$rc != "SQLITE_OK"} break + ota close + } + ota close +} {SQLITE_DONE} + +do_execsql_test 1.3.2 { + SELECT * FROM t1 +} { + a 1 one_i + {} 2 2 + _iii 3 three-III +} +integrity_check 1.3.3 + + +finish_test + diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c index 3b02750866..40091d965b 100644 --- a/ext/ota/sqlite3ota.c +++ b/ext/ota/sqlite3ota.c @@ -447,6 +447,22 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ return p->rc; } +/* +** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs, +** an error code is stored in the OTA handle passed as the first argument. +*/ +static char *otaMPrintfAndCollectError(sqlite3ota *p, const char *zFmt, ...){ + char *zSql = 0; + va_list ap; + va_start(ap, zFmt); + if( p->rc==SQLITE_OK ){ + zSql = sqlite3_vmprintf(zFmt, ap); + if( zSql==0 ) p->rc = SQLITE_NOMEM; + } + va_end(ap); + return zSql; +} + /* ** This function constructs and returns a pointer to a nul-terminated ** string containing some SQL clause or list based on one or more of the @@ -570,6 +586,7 @@ static void otaBadControlError(sqlite3ota *p){ p->zErrmsg = sqlite3_mprintf("Invalid ota_control value"); } + static char *otaObjIterGetSetlist( sqlite3ota *p, OtaObjIter *pIter, @@ -584,14 +601,17 @@ static char *otaObjIterGetSetlist( }else{ const char *zSep = ""; for(i=0; inTblCol; i++){ - if( zMask[i]=='x' ){ - zList = sqlite3_mprintf("%z%s%s=?%d", + char c = zMask[i]; + if( c=='x' ){ + zList = otaMPrintfAndCollectError(p, "%z%s%s=?%d", zList, zSep, pIter->azTblCol[i], i+1 ); - if( zList==0 ){ - p->rc = SQLITE_NOMEM; - break; - } + zSep = ", "; + } + if( c=='d' ){ + zList = otaMPrintfAndCollectError(p, "%z%s%s=ota_delta(%s, ?%d)", + zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 + ); zSep = ", "; } } @@ -1389,6 +1409,13 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){ return p; } +/* +** Return the database handle used by pOta. +*/ +sqlite3 *sqlite3ota_db(sqlite3ota *pOta){ + return (pOta ? pOta->db : 0); +} + /* ** Close the OTA handle. */ @@ -1450,6 +1477,31 @@ sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta){ /* From main.c (apparently...) */ extern const char *sqlite3ErrName(int); +void test_ota_delta(sqlite3_context *pCtx, int nArg, sqlite3_value **apVal){ + Tcl_Interp *interp = (Tcl_Interp*)sqlite3_user_data(pCtx); + Tcl_Obj *pScript; + int i; + + pScript = Tcl_NewObj(); + Tcl_IncrRefCount(pScript); + Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj("ota_delta", -1)); + for(i=0; i