Add the "ota_delta()" feature for delta-compressed updates.

FossilOrigin-Name: c64dcd1788f5cc7db197a0ec4ab0981f34a72c6b
This commit is contained in:
dan 2014-11-20 19:19:02 +00:00
parent 268c0f8844
commit f8bd49ee22
5 changed files with 187 additions and 15 deletions

75
ext/ota/ota8.test Normal file
View File

@ -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

View File

@ -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; i<pIter->nTblCol; 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<nArg; i++){
sqlite3_value *pIn = apVal[i];
const char *z = (const char*)sqlite3_value_text(pIn);
Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(z, -1));
}
if( TCL_OK==Tcl_EvalObjEx(interp, pScript, TCL_GLOBAL_ONLY) ){
const char *z = Tcl_GetStringResult(interp);
sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
}else{
Tcl_BackgroundError(interp);
}
Tcl_DecrRefCount(pScript);
}
static int test_sqlite3ota_cmd(
ClientData clientData,
Tcl_Interp *interp,
@ -1458,7 +1510,7 @@ static int test_sqlite3ota_cmd(
){
int ret = TCL_OK;
sqlite3ota *pOta = (sqlite3ota*)clientData;
const char *azMethod[] = { "step", "close", 0 };
const char *azMethod[] = { "step", "close", "create_ota_delta", 0 };
int iMethod;
if( objc!=2 ){
@ -1495,6 +1547,16 @@ static int test_sqlite3ota_cmd(
break;
}
case 2: /* create_ota_delta */ {
sqlite3 *db = sqlite3ota_db(pOta);
int rc = sqlite3_create_function(
db, "ota_delta", -1, SQLITE_UTF8, (void*)interp, test_ota_delta, 0, 0
);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
break;
}
default: /* seems unlikely */
assert( !"cannot happen" );
break;

View File

@ -132,6 +132,21 @@
**
** INSERT INTO data_t1(a, b, c, ota_control) VALUES(4, NULL, 'usa', '..x');
**
** Instead of an 'x' character, characters of the ota_control value specified
** for UPDATEs may also be set to 'd'. In this case, instead of updating the
** target table with the value stored in the corresponding data_% column, the
** user-defined SQL function "ota_delta()" is invoked and the result stored in
** the target table column. ota_delta() is invoked with two arguments - the
** original value currently stored in the target table column and the
** value specified in the data_xxx table.
**
** For example, this row:
**
** INSERT INTO data_t1(a, b, c, ota_control) VALUES(4, NULL, 'usa', '..d');
**
** is similar to an UPDATE statement such as:
**
** UPDATE t1 SET c = ota_delta(c, 'usa') WHERE a = 4;
**
** USAGE
**
@ -181,6 +196,25 @@ typedef struct sqlite3ota sqlite3ota;
*/
sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta);
/*
** Obtain the underlying database handle used by the OTA extension.
**
** The only argument passed to this function must be a valid, open, OTA
** handle. This function returns the database handle used by OTA for all
** operations on the target and source databases. This may be useful in
** two scenarios:
**
** * If the data_xxx tables in the OTA source database are virtual
** tables, or if any of the tables being updated are virtual tables,
** the application may need to call sqlite3_create_module() on
** the db handle to register the required virtual table implementations.
**
** * If the application uses the "ota_delta()" feature described above,
** it must use sqlite3_create_function() or similar to register the
** ota_delta() implementation with OTA.
*/
sqlite3 *sqlite3ota_db(sqlite3ota*);
/*
** Do some work towards applying the OTA update to the target db.
**

View File

@ -1,5 +1,5 @@
C Update\sthe\sota\sextension\sso\sthat\sit\scan\sbe\sused\sto\supdate\stables\swith\sexternal\sPRIMARY\sKEY\sindexes.
D 2014-11-20T17:37:08.997
C Add\sthe\s"ota_delta()"\sfeature\sfor\sdelta-compressed\supdates.
D 2014-11-20T19:19:02.502
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -131,9 +131,10 @@ F ext/ota/ota4.test 60f897f329a6782ef2f24862640acf3c52e48077
F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
F ext/ota/ota6.test 82f1f757ec9b2ad07d6de4060b8e3ba8e44dfdd3
F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a
F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
F ext/ota/otafault.test be02466863015a583cc0ceb6aca871a5e6f7a71b
F ext/ota/sqlite3ota.c 2c31a56890e915e13eb5d6ced02325e1f4db7487
F ext/ota/sqlite3ota.h 7b20abe9247d292429d00f0a5c237ff6e0dc0196
F ext/ota/sqlite3ota.c edeea10871d1307ff9ee9ccc765ba4031b507509
F ext/ota/sqlite3ota.h 08b276fc9f56c04cdb454cf7aefa41c29361ed7a
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
@ -1217,7 +1218,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 556c3de53ad33d11d33ec794345c2100aa76f3e1
R c3a23811c2315fa65ee1bcdda07f2567
P 55066a1171cbd3077f5e6c8ceb2745e810d9476e
R 97efd71a02c88dd0da29f19b3d083930
U dan
Z eebecee2ceb200b37a4bd343197c1b04
Z 1557aa5ff604851a6b4517de0e4ff6aa

View File

@ -1 +1 @@
55066a1171cbd3077f5e6c8ceb2745e810d9476e
c64dcd1788f5cc7db197a0ec4ab0981f34a72c6b