]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the "ota_delta()" feature for delta-compressed updates.
authordan <dan@noemail.net>
Thu, 20 Nov 2014 19:19:02 +0000 (19:19 +0000)
committerdan <dan@noemail.net>
Thu, 20 Nov 2014 19:19:02 +0000 (19:19 +0000)
FossilOrigin-Name: c64dcd1788f5cc7db197a0ec4ab0981f34a72c6b

ext/ota/ota8.test [new file with mode: 0644]
ext/ota/sqlite3ota.c
ext/ota/sqlite3ota.h
manifest
manifest.uuid

diff --git a/ext/ota/ota8.test b/ext/ota/ota8.test
new file mode 100644 (file)
index 0000000..24a6e72
--- /dev/null
@@ -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
+
index 3b02750866c0d711e3035c6f3aeedb20e92d7cec..40091d965b04171e1c4936457a3cfb2c052fa59f 100644 (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;
index 8850d54d5b4e6e9ccaa2e17d95984c32b94fbbd7..022f3e3f3df1dc79b5e124cacfa23ae2c53a79c1 100644 (file)
 **
 **   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. 
 **
index 78a7f550e634ab4ea20a4f503260e0e4cdb8a058..505e6916bc184179a3b4e4ad39a9f574ee9f9538 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index 8e90b7e445bfb2aeac1a7fa3b1e2fde836774751..d045752a5f08b78e0b650f05b42996628eea1f72 100644 (file)
@@ -1 +1 @@
-55066a1171cbd3077f5e6c8ceb2745e810d9476e
\ No newline at end of file
+c64dcd1788f5cc7db197a0ec4ab0981f34a72c6b
\ No newline at end of file