]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add documentation and test cases for sqlite3ota_create_vfs(). Also code to detect...
authordan <dan@noemail.net>
Tue, 10 Feb 2015 17:08:17 +0000 (17:08 +0000)
committerdan <dan@noemail.net>
Tue, 10 Feb 2015 17:08:17 +0000 (17:08 +0000)
FossilOrigin-Name: e729668168f00325459bc2e9b515aa95e57f2754

ext/ota/ota1.test
ext/ota/sqlite3ota.c
ext/ota/sqlite3ota.h
manifest
manifest.uuid

index 6b8ed971da69c4845752215415354654bb2d1e94..dec5f14a99959724d9c20524206bd446c11d5005 100644 (file)
@@ -106,362 +106,376 @@ proc step_ota_uri {target ota} {
   set rc
 }
 
-foreach {tn2 cmd} {1 run_ota 2 step_ota 3 step_ota_uri} {
-  foreach {tn schema} {
-    1 {
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-    }
-    2 { 
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b);
-    }
-    3 { 
-      CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID;
-    }
-    4 { 
-      CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b);
-    }
-    5 { 
-      CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c)) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b);
-    }
-    6 { 
-      CREATE TABLE t1(a, b, c, PRIMARY KEY(c)) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b, a);
-    }
-    7 { 
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b, c);
-      CREATE INDEX i2 ON t1(c, b);
-      CREATE INDEX i3 ON t1(a, b, c, a, b, c);
-    }
-
-    8 { 
-      CREATE TABLE t1(a PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b, c);
-      CREATE INDEX i2 ON t1(c, b);
-      CREATE INDEX i3 ON t1(a, b, c, a, b, c);
-    }
-
-    9 { 
-      CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c));
-      CREATE INDEX i1 ON t1(b);
-    }
+foreach {tn3 create_vfs destroy_vfs} {
+  1 {} {}
+  2 {
+    sqlite3ota_create_vfs -default myota ""
+  } {
+    sqlite3ota_destroy_vfs myota
+  }
+} {
 
-    10 { 
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b DESC);
+  eval $create_vfs
+
+  foreach {tn2 cmd} {1 run_ota 2 step_ota 3 step_ota_uri} {
+    foreach {tn schema} {
+      1 {
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+      }
+      2 { 
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b);
+      }
+      3 { 
+        CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID;
+      }
+      4 { 
+        CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b);
+      }
+      5 { 
+        CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c)) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b);
+      }
+      6 { 
+        CREATE TABLE t1(a, b, c, PRIMARY KEY(c)) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b, a);
+      }
+      7 { 
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b, c);
+        CREATE INDEX i2 ON t1(c, b);
+        CREATE INDEX i3 ON t1(a, b, c, a, b, c);
+      }
+
+      8 { 
+        CREATE TABLE t1(a PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b, c);
+        CREATE INDEX i2 ON t1(c, b);
+        CREATE INDEX i3 ON t1(a, b, c, a, b, c);
+      }
+
+      9 { 
+        CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c));
+        CREATE INDEX i1 ON t1(b);
+      }
+
+      10 { 
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b DESC);
+      }
+
+      11 { 
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b DESC, a ASC, c DESC);
+      }
+
+      12 { 
+        CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c) WITHOUT ROWID; 
+      }
+
+      13 { 
+        CREATE TABLE t1(a INT, b, c, PRIMARY KEY(a DESC)) WITHOUT ROWID; 
+      }
+
+      14 { 
+        CREATE TABLE t1(a, b, c, PRIMARY KEY(a DESC, c)) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b);
+      }
+
+      15 { 
+        CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c DESC)) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b);
+      }
+
+      16 { 
+        CREATE TABLE t1(a, b, c, PRIMARY KEY(c DESC, a)) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b DESC, c, a);
+      }
+    } {
+      reset_db
+      execsql $schema
+
+      do_test $tn3.1.$tn2.$tn.1 {
+        create_ota1 ota.db
+        breakpoint
+        $cmd test.db ota.db
+      } {SQLITE_DONE}
+
+      do_execsql_test $tn3.1.$tn2.$tn.2 { SELECT * FROM t1 ORDER BY a ASC } {
+        1 2 3 
+        2 two three 
+        3 {} 8.2
+      }
+      do_execsql_test $tn3.1.$tn2.$tn.3 { SELECT * FROM t1 ORDER BY b ASC } {
+        3 {} 8.2
+        1 2 3 
+        2 two three 
+      }
+      do_execsql_test $tn3.1.$tn2.$tn.4 { SELECT * FROM t1 ORDER BY c ASC } {
+        1 2 3 
+        3 {} 8.2
+        2 two three 
+      }
+   
+      do_execsql_test $tn3.1.$tn2.$tn.5 { PRAGMA integrity_check } ok
     }
+  }
 
-    11 { 
+  #-------------------------------------------------------------------------
+  # Check that an OTA cannot be applied to a table that has no PK.
+  #
+  # UPDATE: At one point OTA required that all tables featured either
+  # explicit IPK columns or were declared WITHOUT ROWID. This has been
+  # relaxed so that external PRIMARY KEYs on tables with automatic rowids
+  # are now allowed.
+  #
+  # UPDATE 2: Tables without any PRIMARY KEY declaration are now allowed.
+  # However the input table must feature an "ota_rowid" column.
+  #
+  reset_db
+  create_ota1 ota.db
+  do_execsql_test $tn3.2.1 { CREATE TABLE t1(a, b, c) }
+  do_test $tn3.2.2 {
+    sqlite3ota ota test.db ota.db
+    ota step
+  } {SQLITE_ERROR}
+  do_test $tn3.2.3 {
+    list [catch { ota close } msg] $msg
+  } {1 {SQLITE_ERROR - table data_t1 requires ota_rowid column}}
+  reset_db
+  do_execsql_test $tn3.2.4 { CREATE TABLE t1(a PRIMARY KEY, b, c) }
+  do_test $tn3.2.5 {
+    sqlite3ota ota test.db ota.db
+    ota step
+  } {SQLITE_OK}
+  do_test $tn3.2.6 {
+    list [catch { ota close } msg] $msg
+  } {0 SQLITE_OK}
+
+  #-------------------------------------------------------------------------
+  # Check that if a UNIQUE constraint is violated the current and all 
+  # subsequent [ota step] calls return SQLITE_CONSTRAINT. And that the OTA 
+  # transaction is rolled back by the [ota close] that deletes the ota 
+  # handle.
+  #
+  foreach {tn errcode errmsg schema} {
+    1 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.a" {
       CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b DESC, a ASC, c DESC);
-    }
-
-    12 { 
-      CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c) WITHOUT ROWID; 
-    }
+      INSERT INTO t1 VALUES(3, 2, 1);
+    } 
 
-    13 { 
-      CREATE TABLE t1(a INT, b, c, PRIMARY KEY(a DESC)) WITHOUT ROWID; 
-    }
+    2 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.c" {
+      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c UNIQUE);
+      INSERT INTO t1 VALUES(4, 2, 'three');
+    } 
 
-    14 { 
-      CREATE TABLE t1(a, b, c, PRIMARY KEY(a DESC, c)) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b);
-    }
+    3 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.a" {
+      CREATE TABLE t1(a PRIMARY KEY, b, c);
+      INSERT INTO t1 VALUES(3, 2, 1);
+    } 
 
-    15 { 
-      CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c DESC)) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b);
-    }
+    4 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.c" {
+      CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE);
+      INSERT INTO t1 VALUES(4, 2, 'three');
+    } 
 
-    16 { 
-      CREATE TABLE t1(a, b, c, PRIMARY KEY(c DESC, a)) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b DESC, c, a);
-    }
   } {
     reset_db
     execsql $schema
+    set cksum [dbcksum db main]
 
-    do_test 1.$tn2.$tn.1 {
+    do_test $tn3.3.$tn.1 {
       create_ota1 ota.db
-      breakpoint
-      $cmd test.db ota.db
-    } {SQLITE_DONE}
-
-    do_execsql_test 1.$tn2.$tn.2 { SELECT * FROM t1 ORDER BY a ASC } {
-      1 2 3 
-      2 two three 
-      3 {} 8.2
-    }
-    do_execsql_test 1.$tn2.$tn.3 { SELECT * FROM t1 ORDER BY b ASC } {
-      3 {} 8.2
-      1 2 3 
-      2 two three 
-    }
-    do_execsql_test 1.$tn2.$tn.4 { SELECT * FROM t1 ORDER BY c ASC } {
-      1 2 3 
-      3 {} 8.2
-      2 two three 
-    }
-    do_execsql_test 1.$tn2.$tn.5 { PRAGMA integrity_check } ok
-  }
-}
-
-#-------------------------------------------------------------------------
-# Check that an OTA cannot be applied to a table that has no PK.
-#
-# UPDATE: At one point OTA required that all tables featured either
-# explicit IPK columns or were declared WITHOUT ROWID. This has been
-# relaxed so that external PRIMARY KEYs on tables with automatic rowids
-# are now allowed.
-#
-# UPDATE 2: Tables without any PRIMARY KEY declaration are now allowed.
-# However the input table must feature an "ota_rowid" column.
-#
-reset_db
-create_ota1 ota.db
-do_execsql_test 2.1 { CREATE TABLE t1(a, b, c) }
-do_test 2.2 {
-  sqlite3ota ota test.db ota.db
-  ota step
-} {SQLITE_ERROR}
-do_test 2.3 {
-  list [catch { ota close } msg] $msg
-} {1 {SQLITE_ERROR - table data_t1 requires ota_rowid column}}
-reset_db
-do_execsql_test 2.4 { CREATE TABLE t1(a PRIMARY KEY, b, c) }
-do_test 2.5 {
-  sqlite3ota ota test.db ota.db
-  ota step
-} {SQLITE_OK}
-do_test 2.6 {
-  list [catch { ota close } msg] $msg
-} {0 SQLITE_OK}
-
-#-------------------------------------------------------------------------
-# Check that if a UNIQUE constraint is violated the current and all 
-# subsequent [ota step] calls return SQLITE_CONSTRAINT. And that the OTA 
-# transaction is rolled back by the [ota close] that deletes the ota 
-# handle.
-#
-foreach {tn errcode errmsg schema} {
-  1 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.a" {
-    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-    INSERT INTO t1 VALUES(3, 2, 1);
-  } 
-
-  2 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.c" {
-    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c UNIQUE);
-    INSERT INTO t1 VALUES(4, 2, 'three');
-  } 
-
-  3 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.a" {
-    CREATE TABLE t1(a PRIMARY KEY, b, c);
-    INSERT INTO t1 VALUES(3, 2, 1);
-  } 
-
-  4 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.c" {
-    CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE);
-    INSERT INTO t1 VALUES(4, 2, 'three');
-  } 
-
-} {
-  reset_db
-  execsql $schema
-  set cksum [dbcksum db main]
+      sqlite3ota ota test.db ota.db
+      while {[set res [ota step]]=="SQLITE_OK"} {}
+      set res
+    } $errcode
 
-  do_test 3.$tn.1 {
-    create_ota1 ota.db
-    sqlite3ota ota test.db ota.db
-    while {[set res [ota step]]=="SQLITE_OK"} {}
-    set res
-  } $errcode
-
-  do_test 3.$tn.2 { ota step } $errcode
+    do_test $tn3.3.$tn.2 { ota step } $errcode
 
-  do_test 3.$tn.3 { 
-    list [catch { ota close } msg] $msg
-  } [list 1 "$errcode - $errmsg"]
+    do_test $tn3.3.$tn.3 { 
+      list [catch { ota close } msg] $msg
+    } [list 1 "$errcode - $errmsg"]
 
-  do_test 3.$tn.4 { dbcksum db main } $cksum
-}
+    do_test $tn3.3.$tn.4 { dbcksum db main } $cksum
+  }
 
-#-------------------------------------------------------------------------
-#
-foreach {tn2 cmd} {1 run_ota 2 step_ota} {
-  foreach {tn schema} {
-    1 {
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-    }
-    2 {
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b);
-    }
-    3 {
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b);
-      CREATE INDEX i2 ON t1(c, b);
-      CREATE INDEX i3 ON t1(c, b, c);
-    }
-    4 {
-      CREATE TABLE t1(a INT PRIMARY KEY, b, c) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b);
-      CREATE INDEX i2 ON t1(c, b);
-      CREATE INDEX i3 ON t1(c, b, c);
-    }
-    5 {
-      CREATE TABLE t1(a INT PRIMARY KEY, b, c);
-      CREATE INDEX i1 ON t1(b);
-      CREATE INDEX i2 ON t1(c, b);
-      CREATE INDEX i3 ON t1(c, b, c);
+  #-------------------------------------------------------------------------
+  #
+  foreach {tn2 cmd} {1 run_ota 2 step_ota} {
+    foreach {tn schema} {
+      1 {
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+      }
+      2 {
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b);
+      }
+      3 {
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b);
+        CREATE INDEX i2 ON t1(c, b);
+        CREATE INDEX i3 ON t1(c, b, c);
+      }
+      4 {
+        CREATE TABLE t1(a INT PRIMARY KEY, b, c) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b);
+        CREATE INDEX i2 ON t1(c, b);
+        CREATE INDEX i3 ON t1(c, b, c);
+      }
+      5 {
+        CREATE TABLE t1(a INT PRIMARY KEY, b, c);
+        CREATE INDEX i1 ON t1(b);
+        CREATE INDEX i2 ON t1(c, b);
+        CREATE INDEX i3 ON t1(c, b, c);
+      }
+
+      6 {
+        CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c);
+        CREATE INDEX i1 ON t1(b DESC);
+        CREATE INDEX i2 ON t1(c, b);
+        CREATE INDEX i3 ON t1(c DESC, b, c);
+      }
+      7 {
+        CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(b);
+        CREATE INDEX i2 ON t1(c, b);
+        CREATE INDEX i3 ON t1(c, b, c);
+      }
+    } {
+      reset_db
+      execsql $schema
+      execsql {
+        INSERT INTO t1 VALUES(2, 'hello', 'world');
+        INSERT INTO t1 VALUES(4, 'hello', 'planet');
+        INSERT INTO t1 VALUES(6, 'hello', 'xyz');
+      }
+    
+      do_test $tn3.4.$tn2.$tn.1 {
+        create_ota4 ota.db
+        $cmd test.db ota.db
+      } {SQLITE_DONE}
+      
+      do_execsql_test $tn3.4.$tn2.$tn.2 {
+        SELECT * FROM t1 ORDER BY a ASC;
+      } {
+        1 2 3 
+        3 8 9
+        6 hello xyz
+      }
+    
+      do_execsql_test $tn3.4.$tn2.$tn.3 { PRAGMA integrity_check } ok
     }
+  }
 
-    6 {
-      CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c);
-      CREATE INDEX i1 ON t1(b DESC);
-      CREATE INDEX i2 ON t1(c, b);
-      CREATE INDEX i3 ON t1(c DESC, b, c);
-    }
-    7 {
-      CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(b);
-      CREATE INDEX i2 ON t1(c, b);
-      CREATE INDEX i3 ON t1(c, b, c);
-    }
-  } {
-    reset_db
-    execsql $schema
-    execsql {
-      INSERT INTO t1 VALUES(2, 'hello', 'world');
-      INSERT INTO t1 VALUES(4, 'hello', 'planet');
-      INSERT INTO t1 VALUES(6, 'hello', 'xyz');
-    }
-  
-    do_test 4.$tn2.$tn.1 {
-      create_ota4 ota.db
-      $cmd test.db ota.db
-    } {SQLITE_DONE}
-    
-    do_execsql_test 4.$tn2.$tn.2 {
-      SELECT * FROM t1 ORDER BY a ASC;
+  #-------------------------------------------------------------------------
+  #
+  foreach {tn2 cmd} {1 run_ota 2 step_ota} {
+    foreach {tn schema} {
+      1 {
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
+      }
+      2 {
+        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
+        CREATE INDEX i1 ON t1(d);
+        CREATE INDEX i2 ON t1(d, c);
+        CREATE INDEX i3 ON t1(d, c, b);
+        CREATE INDEX i4 ON t1(b);
+        CREATE INDEX i5 ON t1(c);
+        CREATE INDEX i6 ON t1(c, b);
+      }
+      3 {
+        CREATE TABLE t1(a PRIMARY KEY, b, c, d) WITHOUT ROWID;
+        CREATE INDEX i1 ON t1(d);
+        CREATE INDEX i2 ON t1(d, c);
+        CREATE INDEX i3 ON t1(d, c, b);
+        CREATE INDEX i4 ON t1(b);
+        CREATE INDEX i5 ON t1(c);
+        CREATE INDEX i6 ON t1(c, b);
+      }
+      4 {
+        CREATE TABLE t1(a PRIMARY KEY, b, c, d);
+        CREATE INDEX i1 ON t1(d);
+        CREATE INDEX i2 ON t1(d, c);
+        CREATE INDEX i3 ON t1(d, c, b);
+        CREATE INDEX i4 ON t1(b);
+        CREATE INDEX i5 ON t1(c);
+        CREATE INDEX i6 ON t1(c, b);
+      }
     } {
-      1 2 3 
-      3 8 9
-      6 hello xyz
+      reset_db
+      execsql $schema
+      execsql {
+        INSERT INTO t1 VALUES(1, 2, 3, 4);
+        INSERT INTO t1 VALUES(2, 5, 6, 7);
+        INSERT INTO t1 VALUES(3, 8, 9, 10);
+      }
+    
+      do_test $tn3.5.$tn2.$tn.1 {
+        create_ota5 ota.db
+        $cmd test.db ota.db
+      } {SQLITE_DONE}
+      
+      do_execsql_test $tn3.5.$tn2.$tn.2 {
+        SELECT * FROM t1 ORDER BY a ASC;
+      } {
+        1 2 3 5
+        2 5 10 5
+        3 11 9 10
+      }
+    
+      do_execsql_test $tn3.5.$tn2.$tn.3 { PRAGMA integrity_check } ok
     }
-  
-    do_execsql_test 4.$tn2.$tn.3 { PRAGMA integrity_check } ok
   }
-}
 
-#-------------------------------------------------------------------------
-#
-foreach {tn2 cmd} {1 run_ota 2 step_ota} {
-  foreach {tn schema} {
-    1 {
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
-    }
-    2 {
-      CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
-      CREATE INDEX i1 ON t1(d);
-      CREATE INDEX i2 ON t1(d, c);
-      CREATE INDEX i3 ON t1(d, c, b);
-      CREATE INDEX i4 ON t1(b);
-      CREATE INDEX i5 ON t1(c);
-      CREATE INDEX i6 ON t1(c, b);
-    }
-    3 {
-      CREATE TABLE t1(a PRIMARY KEY, b, c, d) WITHOUT ROWID;
-      CREATE INDEX i1 ON t1(d);
-      CREATE INDEX i2 ON t1(d, c);
-      CREATE INDEX i3 ON t1(d, c, b);
-      CREATE INDEX i4 ON t1(b);
-      CREATE INDEX i5 ON t1(c);
-      CREATE INDEX i6 ON t1(c, b);
-    }
-    4 {
-      CREATE TABLE t1(a PRIMARY KEY, b, c, d);
-      CREATE INDEX i1 ON t1(d);
-      CREATE INDEX i2 ON t1(d, c);
-      CREATE INDEX i3 ON t1(d, c, b);
-      CREATE INDEX i4 ON t1(b);
-      CREATE INDEX i5 ON t1(c);
-      CREATE INDEX i6 ON t1(c, b);
-    }
-  } {
-    reset_db
-    execsql $schema
-    execsql {
-      INSERT INTO t1 VALUES(1, 2, 3, 4);
-      INSERT INTO t1 VALUES(2, 5, 6, 7);
-      INSERT INTO t1 VALUES(3, 8, 9, 10);
-    }
-  
-    do_test 5.$tn2.$tn.1 {
-      create_ota5 ota.db
-      $cmd test.db ota.db
-    } {SQLITE_DONE}
+  #-------------------------------------------------------------------------
+  # Test some error cases:
+  # 
+  #   * A virtual table with no ota_rowid column.
+  #   * A no-PK table with no ota_rowid column.
+  #   * A PK table with an ota_rowid column.
+  #
+  ifcapable fts3 {
+    foreach {tn schema error} {
+       1 {
+         CREATE TABLE t1(a, b);
+         CREATE TABLE ota.data_t1(a, b, ota_control);
+       } {SQLITE_ERROR - table data_t1 requires ota_rowid column}
+    
+       2 {
+         CREATE VIRTUAL TABLE t1 USING fts4(a, b);
+         CREATE TABLE ota.data_t1(a, b, ota_control);
+       } {SQLITE_ERROR - table data_t1 requires ota_rowid column}
+    
+       3 {
+         CREATE TABLE t1(a PRIMARY KEY, b);
+         CREATE TABLE ota.data_t1(a, b, ota_rowid, ota_control);
+       } {SQLITE_ERROR - table data_t1 may not have ota_rowid column}
+    
+       4 {
+         CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+         CREATE TABLE ota.data_t1(a, b, ota_rowid, ota_control);
+       } {SQLITE_ERROR - table data_t1 may not have ota_rowid column}
+    
+       5 {
+         CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
+         CREATE TABLE ota.data_t1(a, b, ota_rowid, ota_control);
+       } {SQLITE_ERROR - table data_t1 may not have ota_rowid column}
     
-    do_execsql_test 5.$tn2.$tn.2 {
-      SELECT * FROM t1 ORDER BY a ASC;
     } {
-      1 2 3 5
-      2 5 10 5
-      3 11 9 10
+      reset_db
+      forcedelete ota.db
+      execsql { ATTACH 'ota.db' AS ota }
+      execsql $schema
+
+      do_test $tn3.6.$tn {
+        list [catch { run_ota test.db ota.db } msg] $msg
+      } [list 1 $error]
     }
-  
-    do_execsql_test 5.$tn2.$tn.3 { PRAGMA integrity_check } ok
   }
-}
 
-#-------------------------------------------------------------------------
-# Test some error cases:
-# 
-#   * A virtual table with no ota_rowid column.
-#   * A no-PK table with no ota_rowid column.
-#   * A PK table with an ota_rowid column.
-#
-ifcapable fts3 {
-  foreach {tn schema error} {
-     1 {
-       CREATE TABLE t1(a, b);
-       CREATE TABLE ota.data_t1(a, b, ota_control);
-     } {SQLITE_ERROR - table data_t1 requires ota_rowid column}
-  
-     2 {
-       CREATE VIRTUAL TABLE t1 USING fts4(a, b);
-       CREATE TABLE ota.data_t1(a, b, ota_control);
-     } {SQLITE_ERROR - table data_t1 requires ota_rowid column}
-  
-     3 {
-       CREATE TABLE t1(a PRIMARY KEY, b);
-       CREATE TABLE ota.data_t1(a, b, ota_rowid, ota_control);
-     } {SQLITE_ERROR - table data_t1 may not have ota_rowid column}
-  
-     4 {
-       CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
-       CREATE TABLE ota.data_t1(a, b, ota_rowid, ota_control);
-     } {SQLITE_ERROR - table data_t1 may not have ota_rowid column}
-  
-     5 {
-       CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
-       CREATE TABLE ota.data_t1(a, b, ota_rowid, ota_control);
-     } {SQLITE_ERROR - table data_t1 may not have ota_rowid column}
-  
-  } {
-    reset_db
-    forcedelete ota.db
-    execsql { ATTACH 'ota.db' AS ota }
-    execsql $schema
-
-    do_test 6.$tn {
-      list [catch { run_ota test.db ota.db } msg] $msg
-    } [list 1 $error]
-  }
+  eval $destroy_vfs
 }
 
 
index 41207501cffbe1bd3ebeff457f42b56da7f34857..72c4333ed4833e6e5e86194a087169777d459f12 100644 (file)
@@ -2350,13 +2350,34 @@ static int otaVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
 */
 static int otaVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
   ota_file *p = (ota_file *)pFile;
+  int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;
+
   if( op==SQLITE_FCNTL_OTA ){
+    int rc;
     sqlite3ota *pOta = (sqlite3ota*)pArg;
-    pOta->pTargetFd = p;
-    p->pOta = pOta;
-    return SQLITE_OK;
+
+    /* First try to find another OTA vfs lower down in the vfs stack. If
+    ** one is found, this vfs will operate in pass-through mode. The lower
+    ** level vfs will do the special OTA handling.  */
+    rc = xControl(p->pReal, op, pArg);
+
+    if( rc==SQLITE_NOTFOUND ){
+      /* Now search for a zipvfs instance lower down in the VFS stack. If
+      ** one is found, this is an error.  */
+      void *dummy = 0;
+      rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS_PAGER, &dummy);
+      if( rc==SQLITE_OK ){
+        rc = SQLITE_ERROR;
+        pOta->zErrmsg = sqlite3_mprintf("ota/zipvfs setup error");
+      }else if( rc==SQLITE_NOTFOUND ){
+        pOta->pTargetFd = p;
+        p->pOta = pOta;
+        rc = SQLITE_OK;
+      }
+    }
+    return rc;
   }
-  return p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
+  return xControl(p->pReal, op, pArg);
 }
 
 /*
@@ -2896,9 +2917,76 @@ static int test_sqlite3ota(
   return TCL_OK;
 }
 
+/*
+** Tclcmd: sqlite3ota_create_vfs ?-default? NAME PARENT
+*/
+static int test_sqlite3ota_create_vfs(
+  ClientData clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  const char *zName;
+  const char *zParent;
+  int rc;
+
+  if( objc!=3 && objc!=4 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "?-default? NAME PARENT");
+    return TCL_ERROR;
+  }
+
+  zName = Tcl_GetString(objv[objc-2]);
+  zParent = Tcl_GetString(objv[objc-1]);
+  if( zParent[0]=='\0' ) zParent = 0;
+
+  rc = sqlite3ota_create_vfs(zName, zParent);
+  if( rc!=SQLITE_OK ){
+    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+    return TCL_ERROR;
+  }else if( objc==4 ){
+    sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
+    sqlite3_vfs_register(pVfs, 1);
+  }
+
+  Tcl_ResetResult(interp);
+  return TCL_OK;
+}
+
+/*
+** Tclcmd: sqlite3ota_destroy_vfs NAME
+*/
+static int test_sqlite3ota_destroy_vfs(
+  ClientData clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  const char *zName;
+
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "NAME");
+    return TCL_ERROR;
+  }
+
+  zName = Tcl_GetString(objv[1]);
+  sqlite3ota_destroy_vfs(zName);
+  return TCL_OK;
+}
+
 
 int SqliteOta_Init(Tcl_Interp *interp){ 
-  Tcl_CreateObjCommand(interp, "sqlite3ota", test_sqlite3ota, 0, 0);
+  static struct {
+     char *zName;
+     Tcl_ObjCmdProc *xProc;
+  } aObjCmd[] = {
+    { "sqlite3ota", test_sqlite3ota },
+    { "sqlite3ota_create_vfs", test_sqlite3ota_create_vfs },
+    { "sqlite3ota_destroy_vfs", test_sqlite3ota_destroy_vfs },
+  };
+  int i;
+  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
+    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
+  }
   return TCL_OK;
 }
 #endif                  /* ifdef SQLITE_TEST */
index f6890f450893a1c98b846f4d154b5c16ba8e6bd3..f3c53a17904629438b067501be4d05ef56987d26 100644 (file)
@@ -237,6 +237,15 @@ typedef struct sqlite3ota sqlite3ota;
 ** Argument zTarget is the path to the target database. Argument zOta is
 ** the path to the OTA database. Each call to this function must be matched
 ** by a call to sqlite3ota_close().
+**
+** By default, OTA uses the default VFS to access the files on disk. To
+** use a VFS other than the default, an SQLite "file:" URI containing a
+** "vfs=..." option may be passed as the zTarget option.
+**
+** IMPORTANT NOTE FOR ZIPVFS USERS: The OTA extension works with all of
+** SQLite's built-in VFSs, including the multiplexor VFS. However it does
+** not work out of the box with zipvfs. Refer to the comment describing
+** the zipvfs_create_vfs() API below for details on using OTA with zipvfs.
 */
 sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta);
 
@@ -276,8 +285,8 @@ int sqlite3ota_step(sqlite3ota *pOta);
 /*
 ** Close an OTA handle. 
 **
-** If the OTA update has been completely applied, commit it to the target 
-** database. Otherwise, assuming no error has occurred, save the current 
+** If the OTA update has been completely applied, commit it to the target
+** database. Otherwise, assuming no error has occurred, save the current
 ** state of the OTA update appliation to the OTA database.
 **
 ** If an error has already occurred as part of an sqlite3ota_step()
@@ -301,17 +310,46 @@ int sqlite3ota_close(sqlite3ota *pOta, char **pzErrmsg);
 sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta);
 
 /*
-** Create an OTA VFS named zName. Use existing VFS zParent to interact
-** with the file-system.
+** Part of the OTA implementation uses a custom VFS object. Usually, this
+** object is created and deleted automatically by OTA. 
+**
+** The exception is for applications that also use zipvfs. In this case,
+** the custom VFS must be explicitly created by the user before the OTA
+** handle is opened. The OTA VFS should be installed so that the zipvfs
+** VFS uses the OTA VFS, which in turn uses any other VFS layers in use 
+** (for example multiplexor) to access the file-system. For example,
+** to assemble an OTA enabled VFS stack that uses both zipvfs and 
+** multiplexor (error checking omitted):
+**
+**     // Create a VFS named "multiplexor" (not the default).
+**     sqlite3_multiplex_initialize(zVfsName, 0);
+**
+**     // Create an ota VFS named "ota" that uses multiplexor.
+**     sqlite3ota_create_vfs("ota", "multiplexor");
+**
+**     // Create a zipvfs VFS named "zipvfs" that uses ota. 
+**     zipvfs_create_vfs_v3("zipvfs", "ota", 0, xCompressorAlgorithmDetector);
+**
+**     // Make zipvfs the default VFS.
+**     sqlite3_vfs_register(sqlite3_vfs_find("zipvfs"), 1);
+**
+** Because the default VFS created above includes a OTA functionality, it
+** may be used by OTA clients. Attempting to use OTA with a zipvfs VFS stack
+** that does not include the OTA layer results in an error.
+**
+** The overhead of adding the "ota" VFS to the system is negligible for 
+** non-OTA users. There is no harm in an application accessing the 
+** file-system via "ota" all the time, even if it only uses OTA functionality 
+** occasionally.
 */
 int sqlite3ota_create_vfs(const char *zName, const char *zParent);
 
 /*
-** Deregister and destroy an OTA vfs previously created by 
+** Deregister and destroy an OTA vfs created by an earlier call to
 ** sqlite3ota_create_vfs().
 **
 ** VFS objects are not reference counted. If a VFS object is destroyed
-** before all database handles that use it have been closed, the results 
+** before all database handles that use it have been closed, the results
 ** are undefined.
 */
 void sqlite3ota_destroy_vfs(const char *zName);
index fe890ddfd34c2724d4d15fd5a05b1779609cb942..7a19969c20c852b5e6cec7e4cb41d07af0cda08b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\ssqlite3ota_create_vfs()\sand\ssqlite3ota_destroy_vfs()\sfunctions.
-D 2015-02-09T20:07:35.066
+C Add\sdocumentation\sand\stest\scases\sfor\ssqlite3ota_create_vfs().\sAlso\scode\sto\sdetect\serrors\sin\szipvfs/ota\ssetup.
+D 2015-02-10T17:08:17.934
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 6b9e7677829aa94b9f30949656e27312aefb9a46
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -125,7 +125,7 @@ F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
 F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
 F ext/ota/README.txt 2ce4ffbb0aaa6731b041c27a7359f9a5f1c69152
 F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91
-F ext/ota/ota1.test a4779d5fe9710d607ebae360eebee3d82a1c14e6
+F ext/ota/ota1.test d50ba4ded2edeba99740bc7dd0b7284c1894127c
 F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
 F ext/ota/ota3.test a77efbce7723332eb688d2b28bf18204fc9614d7
 F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
@@ -134,8 +134,8 @@ F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a
 F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
 F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b
 F ext/ota/otafault.test 508ba87c83d632670ac0f94371a465d4bb4d49dd
-F ext/ota/sqlite3ota.c 3d3179fb9bcb0edf88b3391f480e84b451f1275e
-F ext/ota/sqlite3ota.h 58af0ab6361c76e0eda7aede72e7de42abf83605
+F ext/ota/sqlite3ota.c c73855939e124005f5c91fb50987297d50a81405
+F ext/ota/sqlite3ota.h 1cc7201086fe65a36957740381485a24738c4077
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
 F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f
 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
@@ -1253,7 +1253,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 7bb633639d1e41067903a49653f09a823054e213
-R 290f53a2e90389d88a1ff448f97370f1
+P 96443ecb6909141aa621a16e628455857d036482
+R 5e91280662dadb1373699ffdcf091961
 U dan
-Z 09bf3544f840f7fca63db224a647bd64
+Z 228647d512212dceaeb5d71668e39aca
index ae4cdfe82decccaa3004b5c8c95bcfe46a516ff8..64d574f4ffa2b02156f3a36ffe6bb7cebed00d8e 100644 (file)
@@ -1 +1 @@
-96443ecb6909141aa621a16e628455857d036482
\ No newline at end of file
+e729668168f00325459bc2e9b515aa95e57f2754
\ No newline at end of file