/ Check-in [16b9bf92]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhance existing snapshot tests to serialize/deserialize snapshots. No new tests.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | serializable-snapshot
Files: files | file ages | folders
SHA1: 16b9bf92741e4c62874cffd7c6a61763c5054c7a
User & Date: dan 2016-11-18 14:38:41
Context
2016-11-18
18:22
Add tests for snapshot interfaces. check-in: 1f7ee7af user: dan tags: serializable-snapshot
14:38
Enhance existing snapshot tests to serialize/deserialize snapshots. No new tests. check-in: 16b9bf92 user: dan tags: serializable-snapshot
2016-11-15
17:37
Experimental changes toward making snapshots serializable. check-in: b6a81fa1 user: drh tags: serializable-snapshot
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/test1.c.

  2384   2384     p2 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[2]));
  2385   2385     res = sqlite3_snapshot_cmp(p1, p2);
  2386   2386     Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
  2387   2387     return TCL_OK;
  2388   2388   }
  2389   2389   #endif /* SQLITE_ENABLE_SNAPSHOT */
  2390   2390   
         2391  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2392  +/*
         2393  +** Usage: sqlite3_snapshot_get_blob DB DBNAME
         2394  +*/
         2395  +static int SQLITE_TCLAPI test_snapshot_get_blob(
         2396  +  void * clientData,
         2397  +  Tcl_Interp *interp,
         2398  +  int objc,
         2399  +  Tcl_Obj *CONST objv[]
         2400  +){
         2401  +  int rc;
         2402  +  sqlite3 *db;
         2403  +  char *zName;
         2404  +  sqlite3_snapshot *pSnapshot = 0;
         2405  +
         2406  +  if( objc!=3 ){
         2407  +    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
         2408  +    return TCL_ERROR;
         2409  +  }
         2410  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
         2411  +  zName = Tcl_GetString(objv[2]);
         2412  +
         2413  +  rc = sqlite3_snapshot_get(db, zName, &pSnapshot);
         2414  +  if( rc!=SQLITE_OK ){
         2415  +    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
         2416  +    return TCL_ERROR;
         2417  +  }else{
         2418  +    Tcl_SetObjResult(interp, 
         2419  +        Tcl_NewByteArrayObj((unsigned char*)pSnapshot, sizeof(sqlite3_snapshot))
         2420  +    );
         2421  +    sqlite3_snapshot_free(pSnapshot);
         2422  +  }
         2423  +  return TCL_OK;
         2424  +}
         2425  +#endif /* SQLITE_ENABLE_SNAPSHOT */
         2426  +
         2427  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2428  +  /*
         2429  +  ** Usage: sqlite3_snapshot_open_blob DB DBNAME SNAPSHOT
         2430  +*/
         2431  +static int SQLITE_TCLAPI test_snapshot_open_blob(
         2432  +  void * clientData,
         2433  +  Tcl_Interp *interp,
         2434  +  int objc,
         2435  +  Tcl_Obj *CONST objv[]
         2436  +){
         2437  +  int rc;
         2438  +  sqlite3 *db;
         2439  +  char *zName;
         2440  +  unsigned char *pBlob;
         2441  +  int nBlob;
         2442  +
         2443  +  if( objc!=4 ){
         2444  +    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
         2445  +    return TCL_ERROR;
         2446  +  }
         2447  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
         2448  +  zName = Tcl_GetString(objv[2]);
         2449  +  pBlob = Tcl_GetByteArrayFromObj(objv[3], &nBlob);
         2450  +  if( nBlob!=sizeof(sqlite3_snapshot) ){
         2451  +    Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
         2452  +    return TCL_ERROR;
         2453  +  }
         2454  +  rc = sqlite3_snapshot_open(db, zName, (sqlite3_snapshot*)pBlob);
         2455  +  if( rc!=SQLITE_OK ){
         2456  +    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
         2457  +    return TCL_ERROR;
         2458  +  }
         2459  +  return TCL_OK;
         2460  +}
         2461  +#endif /* SQLITE_ENABLE_SNAPSHOT */
         2462  +
         2463  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2464  +/*
         2465  +** Usage: sqlite3_snapshot_cmp_blob SNAPSHOT1 SNAPSHOT2
         2466  +*/
         2467  +static int SQLITE_TCLAPI test_snapshot_cmp_blob(
         2468  +  void * clientData,
         2469  +  Tcl_Interp *interp,
         2470  +  int objc,
         2471  +  Tcl_Obj *CONST objv[]
         2472  +){
         2473  +  int res;
         2474  +  unsigned char *p1;
         2475  +  unsigned char *p2;
         2476  +  int n1;
         2477  +  int n2;
         2478  +
         2479  +  if( objc!=3 ){
         2480  +    Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
         2481  +    return TCL_ERROR;
         2482  +  }
         2483  +
         2484  +  p1 = Tcl_GetByteArrayFromObj(objv[1], &n1);
         2485  +  p2 = Tcl_GetByteArrayFromObj(objv[2], &n2);
         2486  +
         2487  +  if( n1!=sizeof(sqlite3_snapshot) || n1!=n2 ){
         2488  +    Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
         2489  +    return TCL_ERROR;
         2490  +  }
         2491  +
         2492  +  res = sqlite3_snapshot_cmp((sqlite3_snapshot*)p1, (sqlite3_snapshot*)p2);
         2493  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
         2494  +  return TCL_OK;
         2495  +}
         2496  +#endif /* SQLITE_ENABLE_SNAPSHOT */
         2497  +
  2391   2498   /*
  2392   2499   ** Usage: sqlite3_delete_database FILENAME
  2393   2500   */
  2394   2501   int sqlite3_delete_database(const char*);   /* in test_delete.c */
  2395   2502   static int SQLITE_TCLAPI test_delete_database(
  2396   2503     void * clientData,
  2397   2504     Tcl_Interp *interp,
................................................................................
  7535   7642   #endif
  7536   7643        { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
  7537   7644   #ifdef SQLITE_ENABLE_SNAPSHOT
  7538   7645        { "sqlite3_snapshot_get", test_snapshot_get, 0 },
  7539   7646        { "sqlite3_snapshot_open", test_snapshot_open, 0 },
  7540   7647        { "sqlite3_snapshot_free", test_snapshot_free, 0 },
  7541   7648        { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
         7649  +     { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
         7650  +     { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
         7651  +     { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
  7542   7652   #endif
  7543   7653        { "sqlite3_delete_database", test_delete_database, 0 },
  7544   7654     };
  7545   7655     static int bitmask_size = sizeof(Bitmask)*8;
  7546   7656     static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  7547   7657     int i;
  7548   7658     extern int sqlite3_sync_count, sqlite3_fullsync_count;

Changes to test/snapshot.test.

    22     22   # "PRAGMA journal_mode=memory", which fails if the database is in wal mode
    23     23   # and there are one or more existing connections.
    24     24   if {[permutation]=="inmemory_journal"} {
    25     25     finish_test
    26     26     return
    27     27   }
    28     28   
    29         -#-------------------------------------------------------------------------
    30         -# Check some error conditions in snapshot_get(). It is an error if:
    31         -#
    32         -#  1) snapshot_get() is called on a non-WAL database, or
    33         -#  2) there is an open write transaction on the database.
    34         -#
    35         -do_execsql_test 1.0 {
    36         -  CREATE TABLE t1(a, b);
    37         -  INSERT INTO t1 VALUES(1, 2);
    38         -  INSERT INTO t1 VALUES(3, 4);
    39         -}
    40         -
    41         -do_test 1.1.1 {
    42         -  execsql { BEGIN; SELECT * FROM t1; }
    43         -  list [catch { sqlite3_snapshot_get db main } msg] $msg
    44         -} {1 SQLITE_ERROR}
    45         -do_execsql_test 1.1.2 COMMIT
    46         -
    47         -do_test 1.2.1 {
    48         -  execsql {
    49         -    PRAGMA journal_mode = WAL;
    50         -    BEGIN;
    51         -      INSERT INTO t1 VALUES(5, 6);
    52         -      INSERT INTO t1 VALUES(7, 8);
           29  +foreach {tn tcl} {
           30  +  1 {
           31  +    proc snapshot_get {DB DBNAME} {
           32  +      uplevel [list sqlite3_snapshot_get $DB $DBNAME]
           33  +    }
           34  +    proc snapshot_open {DB DBNAME SNAPSHOT} {
           35  +      uplevel [list sqlite3_snapshot_open $DB $DBNAME $SNAPSHOT]
           36  +    }
           37  +    proc snapshot_free {SNAPSHOT} {
           38  +      uplevel [list sqlite3_snapshot_free $SNAPSHOT]
           39  +    }
           40  +    proc snapshot_cmp {SNAPSHOT1 SNAPSHOT2} {
           41  +      uplevel [list sqlite3_snapshot_cmp $SNAPSHOT1 $SNAPSHOT2]
           42  +    }
           43  +  }
           44  +
           45  +  2 {
           46  +    proc snapshot_get {DB DBNAME} {
           47  +      uplevel [list sqlite3_snapshot_get_blob $DB $DBNAME]
           48  +    }
           49  +    proc snapshot_open {DB DBNAME SNAPSHOT} {
           50  +      uplevel [list sqlite3_snapshot_open_blob $DB $DBNAME $SNAPSHOT]
           51  +    }
           52  +    proc snapshot_free {SNAPSHOT} {
           53  +    }
           54  +    proc snapshot_cmp {SNAPSHOT1 SNAPSHOT2} {
           55  +      uplevel [list sqlite3_snapshot_cmp_blob $SNAPSHOT1 $SNAPSHOT2]
           56  +    }
    53     57     }
    54         -  list [catch { sqlite3_snapshot_get db main } msg] $msg
    55         -} {1 SQLITE_ERROR}
    56         -do_execsql_test 1.3.2 COMMIT
           58  +} {
    57     59   
    58         -#-------------------------------------------------------------------------
    59         -# Check that a simple case works. Reuse the database created by the
    60         -# block of tests above.
    61         -#
    62         -do_execsql_test 2.1.0 {
    63         -  BEGIN;
    64         -    SELECT * FROM t1;
    65         -} {1 2 3 4 5 6 7 8}
           60  +  reset_db
           61  +  eval $tcl
    66     62   
    67         -do_test 2.1.1 {
    68         -  set snapshot [sqlite3_snapshot_get db main]
    69         -  execsql {
    70         -    COMMIT;
    71         -    INSERT INTO t1 VALUES(9, 10);
    72         -    SELECT * FROM t1;
           63  +  #-------------------------------------------------------------------------
           64  +  # Check some error conditions in snapshot_get(). It is an error if:
           65  +  #
           66  +  #  1) snapshot_get() is called on a non-WAL database, or
           67  +  #  2) there is an open write transaction on the database.
           68  +  #
           69  +  do_execsql_test $tn.1.0 {
           70  +    CREATE TABLE t1(a, b);
           71  +    INSERT INTO t1 VALUES(1, 2);
           72  +    INSERT INTO t1 VALUES(3, 4);
    73     73     }
    74         -} {1 2 3 4 5 6 7 8 9 10}
    75         -
    76         -do_test 2.1.2 {
    77         -  execsql BEGIN
    78         -  sqlite3_snapshot_open db main $snapshot
    79         -  execsql {
    80         -    SELECT * FROM t1;
    81         -  }
    82         -} {1 2 3 4 5 6 7 8}
    83         -
    84         -do_test 2.1.3 {
    85         -  sqlite3_snapshot_free $snapshot
    86         -  execsql COMMIT
    87         -} {}
    88         -
    89         -do_test 2.2.0 {
    90         -  sqlite3 db2 test.db
    91         -  execsql {
           74  +
           75  +  do_test $tn.1.1.1 {
           76  +    execsql { BEGIN; SELECT * FROM t1; }
           77  +    list [catch { snapshot_get db main } msg] $msg
           78  +  } {1 SQLITE_ERROR}
           79  +  do_execsql_test 1.1.2 COMMIT
           80  +
           81  +  do_test $tn.1.2.1 {
           82  +    execsql {
           83  +      PRAGMA journal_mode = WAL;
           84  +      BEGIN;
           85  +        INSERT INTO t1 VALUES(5, 6);
           86  +        INSERT INTO t1 VALUES(7, 8);
           87  +    }
           88  +    list [catch { snapshot_get db main } msg] $msg
           89  +  } {1 SQLITE_ERROR}
           90  +  do_execsql_test $tn.1.3.2 COMMIT
           91  +
           92  +  #-------------------------------------------------------------------------
           93  +  # Check that a simple case works. Reuse the database created by the
           94  +  # block of tests above.
           95  +  #
           96  +  do_execsql_test $tn.2.1.0 {
    92     97       BEGIN;
    93     98         SELECT * FROM t1;
    94         -  } db2
    95         -} {1 2 3 4 5 6 7 8 9 10}
    96         -
    97         -do_test 2.2.1 {
    98         -  set snapshot [sqlite3_snapshot_get db2 main]
    99         -  execsql {
   100         -    INSERT INTO t1 VALUES(11, 12);
   101         -    SELECT * FROM t1;
   102         -  }
   103         -} {1 2 3 4 5 6 7 8 9 10 11 12}
   104         -
   105         -do_test 2.2.2 {
   106         -  execsql BEGIN
   107         -  sqlite3_snapshot_open db main $snapshot
   108         -  execsql {
   109         -    SELECT * FROM t1;
   110         -  }
   111         -} {1 2 3 4 5 6 7 8 9 10}
   112         -
   113         -do_test 2.2.3 {
   114         -  sqlite3_snapshot_free $snapshot
   115         -  execsql COMMIT
   116         -  execsql COMMIT db2
   117         -  db2 close
   118         -} {}
   119         -
   120         -do_test 2.3.1 {
   121         -  execsql { DELETE FROM t1 WHERE a>6 }
   122         -  set snapshot [sqlite3_snapshot_get db main]
   123         -  execsql {
   124         -    INSERT INTO t1 VALUES('a', 'b');
   125         -    INSERT INTO t1 VALUES('c', 'd');
   126         -    SELECT * FROM t1;
   127         -  }
   128         -} {1 2 3 4 5 6 a b c d}
   129         -do_test 2.3.2 {
   130         -  execsql BEGIN
   131         -  sqlite3_snapshot_open db main $snapshot
   132         -  execsql { SELECT * FROM t1 }
   133         -} {1 2 3 4 5 6}
   134         -
   135         -do_test 2.3.3 {
   136         -  catchsql {
   137         -    INSERT INTO t1 VALUES('x','y')
   138         -  }
   139         -} {1 {database is locked}}
   140         -do_test 2.3.4 {
   141         -  execsql COMMIT
   142         -  sqlite3_snapshot_free $snapshot
   143         -} {}
   144         -
   145         -#-------------------------------------------------------------------------
   146         -# Check some errors in sqlite3_snapshot_open(). It is an error if:
   147         -#
   148         -#   1) the db is in auto-commit mode,
   149         -#   2) the db has an open (read or write) transaction,
   150         -#   3) the db is not a wal database,
   151         -#
   152         -# Reuse the database created by earlier tests.
   153         -#
   154         -do_execsql_test 3.0.0 {
   155         -  CREATE TABLE t2(x, y);
   156         -  INSERT INTO t2 VALUES('a', 'b');
   157         -  INSERT INTO t2 VALUES('c', 'd');
   158         -  BEGIN;
   159         -    SELECT * FROM t2;
   160         -} {a b c d}
   161         -do_test 3.0.1 {
   162         -  set snapshot [sqlite3_snapshot_get db main]
   163         -  execsql { COMMIT }
   164         -  execsql { INSERT INTO t2 VALUES('e', 'f'); }
   165         -} {}
   166         -
   167         -do_test 3.1 {
   168         -  list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
   169         -} {1 SQLITE_ERROR}
   170         -
   171         -do_test 3.2.1 {
   172         -  execsql {
           99  +  } {1 2 3 4 5 6 7 8}
          100  +
          101  +  do_test $tn.2.1.1 {
          102  +    set snapshot [snapshot_get db main]
          103  +    execsql {
          104  +      COMMIT;
          105  +      INSERT INTO t1 VALUES(9, 10);
          106  +      SELECT * FROM t1;
          107  +    }
          108  +  } {1 2 3 4 5 6 7 8 9 10}
          109  +
          110  +  do_test $tn.2.1.2 {
          111  +    execsql BEGIN
          112  +    snapshot_open db main $snapshot
          113  +    execsql {
          114  +      SELECT * FROM t1;
          115  +    }
          116  +  } {1 2 3 4 5 6 7 8}
          117  +
          118  +  do_test $tn.2.1.3 {
          119  +    snapshot_free $snapshot
          120  +    execsql COMMIT
          121  +  } {}
          122  +
          123  +  do_test $tn.2.2.0 {
          124  +    sqlite3 db2 test.db
          125  +    execsql {
          126  +      BEGIN;
          127  +        SELECT * FROM t1;
          128  +    } db2
          129  +  } {1 2 3 4 5 6 7 8 9 10}
          130  +
          131  +  do_test $tn.2.2.1 {
          132  +    set snapshot [snapshot_get db2 main]
          133  +    execsql {
          134  +      INSERT INTO t1 VALUES(11, 12);
          135  +      SELECT * FROM t1;
          136  +    }
          137  +  } {1 2 3 4 5 6 7 8 9 10 11 12}
          138  +
          139  +  do_test $tn.2.2.2 {
          140  +    execsql BEGIN
          141  +    snapshot_open db main $snapshot
          142  +    execsql {
          143  +      SELECT * FROM t1;
          144  +    }
          145  +  } {1 2 3 4 5 6 7 8 9 10}
          146  +
          147  +  do_test $tn.2.2.3 {
          148  +    snapshot_free $snapshot
          149  +    execsql COMMIT
          150  +    execsql COMMIT db2
          151  +    db2 close
          152  +  } {}
          153  +
          154  +  do_test $tn.2.3.1 {
          155  +    execsql { DELETE FROM t1 WHERE a>6 }
          156  +    set snapshot [snapshot_get db main]
          157  +    execsql {
          158  +      INSERT INTO t1 VALUES('a', 'b');
          159  +      INSERT INTO t1 VALUES('c', 'd');
          160  +      SELECT * FROM t1;
          161  +    }
          162  +  } {1 2 3 4 5 6 a b c d}
          163  +  do_test $tn.2.3.2 {
          164  +    execsql BEGIN
          165  +    snapshot_open db main $snapshot
          166  +    execsql { SELECT * FROM t1 }
          167  +  } {1 2 3 4 5 6}
          168  +
          169  +  do_test $tn.2.3.3 {
          170  +    catchsql {
          171  +      INSERT INTO t1 VALUES('x','y')
          172  +    }
          173  +  } {1 {database is locked}}
          174  +  do_test $tn.2.3.4 {
          175  +    execsql COMMIT
          176  +    snapshot_free $snapshot
          177  +  } {}
          178  +
          179  +  #-------------------------------------------------------------------------
          180  +  # Check some errors in snapshot_open(). It is an error if:
          181  +  #
          182  +  #   1) the db is in auto-commit mode,
          183  +  #   2) the db has an open (read or write) transaction,
          184  +  #   3) the db is not a wal database,
          185  +  #
          186  +  # Reuse the database created by earlier tests.
          187  +  #
          188  +  do_execsql_test $tn.3.0.0 {
          189  +    CREATE TABLE t2(x, y);
          190  +    INSERT INTO t2 VALUES('a', 'b');
          191  +    INSERT INTO t2 VALUES('c', 'd');
   173    192       BEGIN;
   174    193         SELECT * FROM t2;
   175         -  }
   176         -} {a b c d e f}
   177         -do_test 3.2.2 {
   178         -  list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
   179         -} {1 SQLITE_ERROR}
   180         -
   181         -do_test 3.2.3 {
   182         -  execsql {
   183         -    COMMIT;
   184         -    BEGIN;
   185         -      INSERT INTO t2 VALUES('g', 'h');
   186         -  }
   187         -  list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
   188         -} {1 SQLITE_ERROR}
   189         -do_execsql_test 3.2.4 COMMIT
   190         -
   191         -do_test 3.3.1 {
   192         -  execsql { PRAGMA journal_mode = DELETE }
   193         -  execsql { BEGIN }
   194         -  list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
   195         -} {1 SQLITE_ERROR}
   196         -
   197         -do_test 3.3.2 {
   198         -  sqlite3_snapshot_free $snapshot
   199         -  execsql COMMIT
   200         -} {}
   201         -
   202         -#-------------------------------------------------------------------------
   203         -# Check that SQLITE_BUSY_SNAPSHOT is returned if the specified snapshot
   204         -# no longer exists because the wal file has been checkpointed.
   205         -#
   206         -#   1. Reading a snapshot from the middle of a wal file is not possible
   207         -#      after the wal file has been checkpointed.
   208         -#
   209         -#   2. That a snapshot from the end of a wal file can not be read once
   210         -#      the wal file has been wrapped.
   211         -#
   212         -do_execsql_test 4.1.0 {
   213         -  PRAGMA journal_mode = wal;
   214         -  CREATE TABLE t3(i, j);
   215         -  INSERT INTO t3 VALUES('o', 't');
   216         -  INSERT INTO t3 VALUES('t', 'f');
   217         -  BEGIN;
   218         -    SELECT * FROM t3;
   219         -} {wal o t t f}
   220         -
   221         -do_test 4.1.1 {
   222         -  set snapshot [sqlite3_snapshot_get db main]
   223         -  execsql COMMIT
   224         -} {}
   225         -do_test 4.1.2 {
   226         -  execsql { 
   227         -    INSERT INTO t3 VALUES('f', 's'); 
   228         -    BEGIN;
   229         -  }
   230         -  sqlite3_snapshot_open db main $snapshot
   231         -  execsql { SELECT * FROM t3 }
   232         -} {o t t f}
   233         -
   234         -do_test 4.1.3 {
   235         -  execsql { 
   236         -    COMMIT;
   237         -    PRAGMA wal_checkpoint;
   238         -    BEGIN;
   239         -  }
   240         -  list [catch {sqlite3_snapshot_open db main $snapshot} msg] $msg
   241         -} {1 SQLITE_BUSY_SNAPSHOT}
   242         -do_test 4.1.4 {
   243         -  sqlite3_snapshot_free $snapshot
   244         -  execsql COMMIT
   245         -} {}
   246         -
   247         -do_test 4.2.1 {
   248         -  execsql {
   249         -    INSERT INTO t3 VALUES('s', 'e');
   250         -    INSERT INTO t3 VALUES('n', 't');
          194  +  } {a b c d}
          195  +  do_test $tn.3.0.1 {
          196  +    set snapshot [snapshot_get db main]
          197  +    execsql { COMMIT }
          198  +    execsql { INSERT INTO t2 VALUES('e', 'f'); }
          199  +  } {}
          200  +
          201  +  do_test $tn.3.1 {
          202  +    list [catch {snapshot_open db main $snapshot } msg] $msg
          203  +  } {1 SQLITE_ERROR}
          204  +
          205  +  do_test $tn.3.2.1 {
          206  +    execsql {
          207  +      BEGIN;
          208  +        SELECT * FROM t2;
          209  +    }
          210  +  } {a b c d e f}
          211  +  do_test $tn.3.2.2 {
          212  +    list [catch {snapshot_open db main $snapshot } msg] $msg
          213  +  } {1 SQLITE_ERROR}
          214  +
          215  +  do_test $tn.3.2.3 {
          216  +    execsql {
          217  +      COMMIT;
          218  +      BEGIN;
          219  +        INSERT INTO t2 VALUES('g', 'h');
          220  +    }
          221  +    list [catch {snapshot_open db main $snapshot } msg] $msg
          222  +  } {1 SQLITE_ERROR}
          223  +  do_execsql_test 3.2.4 COMMIT
          224  +
          225  +  do_test $tn.3.3.1 {
          226  +    execsql { PRAGMA journal_mode = DELETE }
          227  +    execsql { BEGIN }
          228  +    list [catch {snapshot_open db main $snapshot } msg] $msg
          229  +  } {1 SQLITE_ERROR}
          230  +
          231  +  do_test $tn.$tn.3.3.2 {
          232  +    snapshot_free $snapshot
          233  +    execsql COMMIT
          234  +  } {}
          235  +
          236  +  #-------------------------------------------------------------------------
          237  +  # Check that SQLITE_BUSY_SNAPSHOT is returned if the specified snapshot
          238  +  # no longer exists because the wal file has been checkpointed.
          239  +  #
          240  +  #   1. Reading a snapshot from the middle of a wal file is not possible
          241  +  #      after the wal file has been checkpointed.
          242  +  #
          243  +  #   2. That a snapshot from the end of a wal file can not be read once
          244  +  #      the wal file has been wrapped.
          245  +  #
          246  +  do_execsql_test $tn.4.1.0 {
          247  +    PRAGMA journal_mode = wal;
          248  +    CREATE TABLE t3(i, j);
          249  +    INSERT INTO t3 VALUES('o', 't');
          250  +    INSERT INTO t3 VALUES('t', 'f');
   251    251       BEGIN;
   252    252         SELECT * FROM t3;
   253         -  }
   254         -} {o t t f f s s e n t}
   255         -do_test 4.2.2 {
   256         -  set snapshot [sqlite3_snapshot_get db main]
   257         -  execsql {
   258         -    COMMIT;
   259         -    PRAGMA wal_checkpoint;
   260         -    BEGIN;
   261         -  }
   262         -  sqlite3_snapshot_open db main $snapshot
   263         -  execsql { SELECT * FROM t3 }
   264         -} {o t t f f s s e n t}
   265         -do_test 4.2.3 {
   266         -  execsql {
   267         -    COMMIT;
   268         -    INSERT INTO t3 VALUES('e', 't');
          253  +  } {wal o t t f}
          254  +
          255  +  do_test $tn.4.1.1 {
          256  +    set snapshot [snapshot_get db main]
          257  +    execsql COMMIT
          258  +  } {}
          259  +  do_test $tn.4.1.2 {
          260  +    execsql { 
          261  +      INSERT INTO t3 VALUES('f', 's'); 
          262  +      BEGIN;
          263  +    }
          264  +    snapshot_open db main $snapshot
          265  +    execsql { SELECT * FROM t3 }
          266  +  } {o t t f}
          267  +
          268  +  do_test $tn.4.1.3 {
          269  +    execsql { 
          270  +      COMMIT;
          271  +      PRAGMA wal_checkpoint;
          272  +      BEGIN;
          273  +    }
          274  +    list [catch {snapshot_open db main $snapshot} msg] $msg
          275  +  } {1 SQLITE_BUSY_SNAPSHOT}
          276  +  do_test $tn.4.1.4 {
          277  +    snapshot_free $snapshot
          278  +    execsql COMMIT
          279  +  } {}
          280  +
          281  +  do_test $tn.4.2.1 {
          282  +    execsql {
          283  +      INSERT INTO t3 VALUES('s', 'e');
          284  +      INSERT INTO t3 VALUES('n', 't');
          285  +      BEGIN;
          286  +        SELECT * FROM t3;
          287  +    }
          288  +  } {o t t f f s s e n t}
          289  +  do_test $tn.4.2.2 {
          290  +    set snapshot [snapshot_get db main]
          291  +    execsql {
          292  +      COMMIT;
          293  +      PRAGMA wal_checkpoint;
          294  +      BEGIN;
          295  +    }
          296  +    snapshot_open db main $snapshot
          297  +    execsql { SELECT * FROM t3 }
          298  +  } {o t t f f s s e n t}
          299  +  do_test $tn.4.2.3 {
          300  +    execsql {
          301  +      COMMIT;
          302  +      INSERT INTO t3 VALUES('e', 't');
          303  +      BEGIN;
          304  +    }
          305  +    list [catch {snapshot_open db main $snapshot} msg] $msg
          306  +  } {1 SQLITE_BUSY_SNAPSHOT}
          307  +  do_test $tn.4.2.4 {
          308  +    snapshot_free $snapshot
          309  +  } {}
          310  +
          311  +  #-------------------------------------------------------------------------
          312  +  # Check that SQLITE_BUSY is returned if a checkpoint is running when
          313  +  # sqlite3_snapshot_open() is called.
          314  +  #
          315  +  reset_db
          316  +  db close
          317  +  testvfs tvfs
          318  +  sqlite3 db test.db -vfs tvfs
          319  +
          320  +  do_execsql_test $tn.5.1 {
          321  +    PRAGMA journal_mode = wal;
          322  +    CREATE TABLE x1(x, xx, xxx);
          323  +    INSERT INTO x1 VALUES('z', 'zz', 'zzz');
   269    324       BEGIN;
   270         -  }
   271         -  list [catch {sqlite3_snapshot_open db main $snapshot} msg] $msg
   272         -} {1 SQLITE_BUSY_SNAPSHOT}
   273         -do_test 4.2.4 {
   274         -  sqlite3_snapshot_free $snapshot
   275         -} {}
   276         -
   277         -#-------------------------------------------------------------------------
   278         -# Check that SQLITE_BUSY is returned if a checkpoint is running when
   279         -# sqlite3_snapshot_open() is called.
   280         -#
   281         -reset_db
   282         -db close
   283         -testvfs tvfs
   284         -sqlite3 db test.db -vfs tvfs
   285         -
   286         -do_execsql_test 5.1 {
   287         -  PRAGMA journal_mode = wal;
   288         -  CREATE TABLE x1(x, xx, xxx);
   289         -  INSERT INTO x1 VALUES('z', 'zz', 'zzz');
   290         -  BEGIN;
   291         -    SELECT * FROM x1;
   292         -} {wal z zz zzz}
   293         -
   294         -do_test 5.2 {
   295         -  set ::snapshot [sqlite3_snapshot_get db main]
   296         -  sqlite3 db2 test.db -vfs tvfs
   297         -  execsql {
   298         -    INSERT INTO x1 VALUES('a', 'aa', 'aaa');
   299         -    COMMIT;
          325  +      SELECT * FROM x1;
          326  +  } {wal z zz zzz}
          327  +
          328  +  do_test $tn.5.2 {
          329  +    set ::snapshot [snapshot_get db main]
          330  +    sqlite3 db2 test.db -vfs tvfs
          331  +    execsql {
          332  +      INSERT INTO x1 VALUES('a', 'aa', 'aaa');
          333  +      COMMIT;
          334  +    }
          335  +  } {}
          336  +
          337  +  set t53 0
          338  +  proc write_callback {args} {
          339  +    do_test $tn.5.3.[incr ::t53] {
          340  +      execsql BEGIN
          341  +      list [catch { snapshot_open db main $::snapshot } msg] $msg
          342  +    } {1 SQLITE_BUSY}
          343  +    catchsql COMMIT
   300    344     }
   301         -} {}
   302    345   
   303         -set t53 0
   304         -proc write_callback {args} {
   305         -  do_test 5.3.[incr ::t53] {
   306         -    execsql BEGIN
   307         -    list [catch { sqlite3_snapshot_open db main $::snapshot } msg] $msg
   308         -  } {1 SQLITE_BUSY}
   309         -  catchsql COMMIT
   310         -}
   311         -
   312         -tvfs filter xWrite
   313         -tvfs script write_callback
   314         -db2 eval { PRAGMA wal_checkpoint }
   315         -db close
   316         -db2 close
   317         -tvfs delete
   318         -sqlite3_snapshot_free $snapshot
   319         -
   320         -#-------------------------------------------------------------------------
   321         -# Test that sqlite3_snapshot_get() may be called immediately after
   322         -# "BEGIN; PRAGMA user_version;". And that sqlite3_snapshot_open() may
   323         -# be called after opening the db handle and running the script
   324         -# "PRAGMA user_version; BEGIN".
   325         -reset_db
   326         -do_execsql_test 6.1 {
   327         -  PRAGMA journal_mode = wal;
   328         -  CREATE TABLE x1(x, xx, xxx);
   329         -  INSERT INTO x1 VALUES('z', 'zz', 'zzz');
   330         -  BEGIN;
   331         -    PRAGMA user_version;
   332         -} {wal 0}
   333         -do_test 6.2 {
   334         -  set ::snapshot [sqlite3_snapshot_get db main]
   335         -  execsql {
   336         -    INSERT INTO x1 VALUES('a', 'aa', 'aaa');
   337         -    COMMIT;
   338         -  }
   339         -} {}
   340         -do_test 6.3 {
   341         -  sqlite3 db2 test.db 
   342         -  db2 eval "PRAGMA user_version ; BEGIN"
   343         -  sqlite3_snapshot_open db2 main $::snapshot
   344         -  db2 eval { SELECT * FROM x1 }
   345         -} {z zz zzz}
   346         -do_test 6.4 {
          346  +  tvfs filter xWrite
          347  +  tvfs script write_callback
          348  +  db2 eval { PRAGMA wal_checkpoint }
          349  +  db close
   347    350     db2 close
   348         -  sqlite3 db2 test.db 
   349         -  db2 eval "PRAGMA application_id"
   350         -  db2 eval "BEGIN"
   351         -  sqlite3_snapshot_open db2 main $::snapshot
   352         -  db2 eval { SELECT * FROM x1 }
   353         -} {z zz zzz}
   354         -
   355         -do_test 6.5 {
   356         -  db2 close
   357         -  sqlite3 db2 test.db 
   358         -  db2 eval "BEGIN"
   359         -  list [catch {sqlite3_snapshot_open db2 main $::snapshot} msg] $msg
   360         -} {1 SQLITE_ERROR}
          351  +  tvfs delete
          352  +  snapshot_free $snapshot
          353  +
          354  +  #-------------------------------------------------------------------------
          355  +  # Test that sqlite3_snapshot_get() may be called immediately after
          356  +  # "BEGIN; PRAGMA user_version;". And that sqlite3_snapshot_open() may
          357  +  # be called after opening the db handle and running the script
          358  +  # "PRAGMA user_version; BEGIN".
          359  +  reset_db
          360  +  do_execsql_test $tn.6.1 {
          361  +    PRAGMA journal_mode = wal;
          362  +    CREATE TABLE x1(x, xx, xxx);
          363  +    INSERT INTO x1 VALUES('z', 'zz', 'zzz');
          364  +    BEGIN;
          365  +      PRAGMA user_version;
          366  +  } {wal 0}
          367  +  do_test $tn.6.2 {
          368  +    set ::snapshot [snapshot_get db main]
          369  +    execsql {
          370  +      INSERT INTO x1 VALUES('a', 'aa', 'aaa');
          371  +      COMMIT;
          372  +    }
          373  +  } {}
          374  +  do_test $tn.6.3 {
          375  +    sqlite3 db2 test.db 
          376  +    db2 eval "PRAGMA user_version ; BEGIN"
          377  +    snapshot_open db2 main $::snapshot
          378  +    db2 eval { SELECT * FROM x1 }
          379  +  } {z zz zzz}
          380  +  do_test $tn.6.4 {
          381  +    db2 close
          382  +    sqlite3 db2 test.db 
          383  +    db2 eval "PRAGMA application_id"
          384  +    db2 eval "BEGIN"
          385  +    snapshot_open db2 main $::snapshot
          386  +    db2 eval { SELECT * FROM x1 }
          387  +  } {z zz zzz}
          388  +
          389  +  do_test $tn.6.5 {
          390  +    db2 close
          391  +    sqlite3 db2 test.db 
          392  +    db2 eval "BEGIN"
          393  +    list [catch {snapshot_open db2 main $::snapshot} msg] $msg
          394  +  } {1 SQLITE_ERROR}
   361    395   
   362         -sqlite3_snapshot_free $snapshot
          396  +  snapshot_free $snapshot
   363    397   
   364         -#-------------------------------------------------------------------------
   365         -# The following tests investigate the sqlite3_snapshot_cmp() API.
   366         -#
   367         -
   368         -# Compare snapshots $p1 and $p2, checking that the result is $r.
   369         -#
   370         -proc do_snapshot_cmp_test {tn p1 p2 r} {
   371         -  uplevel [list do_test $tn.1 [list sqlite3_snapshot_cmp $p1 $p2] $r]
   372         -  uplevel [list do_test $tn.2 [list sqlite3_snapshot_cmp $p2 $p1] [expr $r*-1]]
   373         -  uplevel [list do_test $tn.3 [list sqlite3_snapshot_cmp $p1 $p1] 0]
   374         -  uplevel [list do_test $tn.4 [list sqlite3_snapshot_cmp $p2 $p2] 0]
   375         -}
          398  +  #-------------------------------------------------------------------------
          399  +  # The following tests investigate the sqlite3_snapshot_cmp() API.
          400  +  #
   376    401   
   377         -catch { db2 close }
   378         -reset_db
   379         -
   380         -do_execsql_test 7.1 {
   381         -  PRAGMA journal_mode = wal;
   382         -  CREATE TABLE t1(x);
   383         -} wal
   384         -
   385         -do_test 7.1.2 {
   386         -  execsql { BEGIN ; PRAGMA application_id }
   387         -  set p1 [sqlite3_snapshot_get db main]
   388         -  execsql {
   389         -    INSERT INTO t1 VALUES(10);
   390         -    COMMIT;
          402  +  # Compare snapshots $p1 and $p2, checking that the result is $r.
          403  +  #
          404  +  proc do_snapshot_cmp_test {tn p1 p2 r} {
          405  +    uplevel [list do_test $tn.1 [list snapshot_cmp $p1 $p2] $r]
          406  +    uplevel [list do_test $tn.2 [list snapshot_cmp $p2 $p1] [expr $r*-1]]
          407  +    uplevel [list do_test $tn.3 [list snapshot_cmp $p1 $p1] 0]
          408  +    uplevel [list do_test $tn.4 [list snapshot_cmp $p2 $p2] 0]
   391    409     }
   392         -  execsql { BEGIN ; PRAGMA application_id }
   393         -  set p2 [sqlite3_snapshot_get db main]
   394         -  execsql COMMIT
   395         -} {}
          410  +
          411  +  catch { db2 close }
          412  +  reset_db
          413  +
          414  +  do_execsql_test $tn.7.1 {
          415  +    PRAGMA journal_mode = wal;
          416  +    CREATE TABLE t1(x);
          417  +  } wal
          418  +
          419  +  do_test $tn.7.1.2 {
          420  +    execsql { BEGIN ; PRAGMA application_id }
          421  +    set p1 [snapshot_get db main]
          422  +    execsql {
          423  +      INSERT INTO t1 VALUES(10);
          424  +      COMMIT;
          425  +    }
          426  +    execsql { BEGIN ; PRAGMA application_id }
          427  +    set p2 [snapshot_get db main]
          428  +    execsql COMMIT
          429  +  } {}
   396    430   
   397         -do_snapshot_cmp_test 7.1.3 $p1 $p2 -1
   398         -sqlite3_snapshot_free $p1
   399         -sqlite3_snapshot_free $p2
          431  +  do_snapshot_cmp_test $tn.7.1.3 $p1 $p2 -1
          432  +  snapshot_free $p1
          433  +  snapshot_free $p2
   400    434   
   401         -do_execsql_test 7.2.1 {
   402         -  INSERT INTO t1 VALUES(11);
   403         -  INSERT INTO t1 VALUES(12);
   404         -  INSERT INTO t1 VALUES(13);
   405         -  BEGIN; 
   406         -    PRAGMA application_id;
   407         -} {0}
   408         -do_test 7.2.2 {
   409         -  set p1 [sqlite3_snapshot_get db main]
   410         -  execsql {
   411         -    COMMIT;
   412         -    INSERT INTO t1 VALUES(14);
   413         -    PRAGMA wal_checkpoint;
   414         -    BEGIN;
          435  +  do_execsql_test $tn.7.2.1 {
          436  +    INSERT INTO t1 VALUES(11);
          437  +    INSERT INTO t1 VALUES(12);
          438  +    INSERT INTO t1 VALUES(13);
          439  +    BEGIN; 
   415    440         PRAGMA application_id;
   416         -  }
   417         -  set p2 [sqlite3_snapshot_get db main]
   418         -  execsql COMMIT
   419         -} {}
          441  +  } {0}
          442  +  do_test $tn.7.2.2 {
          443  +    set p1 [snapshot_get db main]
          444  +    execsql {
          445  +      COMMIT;
          446  +      INSERT INTO t1 VALUES(14);
          447  +      PRAGMA wal_checkpoint;
          448  +      BEGIN;
          449  +        PRAGMA application_id;
          450  +    }
          451  +    set p2 [snapshot_get db main]
          452  +    execsql COMMIT
          453  +  } {}
   420    454   
   421         -do_snapshot_cmp_test 7.2.3 $p1 $p2 -1
   422         -sqlite3_snapshot_free $p2
          455  +  do_snapshot_cmp_test $tn.7.2.3 $p1 $p2 -1
          456  +  snapshot_free $p2
   423    457   
   424         -do_test 7.3.1 {
   425         -  execsql {
   426         -    INSERT INTO t1 VALUES(14);
   427         -    BEGIN;
   428         -      PRAGMA application_id;
   429         -  }
   430         -  set p2 [sqlite3_snapshot_get db main]
   431         -  execsql COMMIT
   432         -} {}
          458  +  do_test $tn.7.3.1 {
          459  +    execsql {
          460  +      INSERT INTO t1 VALUES(14);
          461  +      BEGIN;
          462  +        PRAGMA application_id;
          463  +    }
          464  +    set p2 [snapshot_get db main]
          465  +    execsql COMMIT
          466  +  } {}
   433    467   
   434         -do_snapshot_cmp_test 7.3.2 $p1 $p2 -1
   435         -sqlite3_snapshot_free $p1
   436         -sqlite3_snapshot_free $p2
          468  +  do_snapshot_cmp_test $tn.7.3.2 $p1 $p2 -1
          469  +  snapshot_free $p1
          470  +  snapshot_free $p2
          471  +}
   437    472   
   438    473   finish_test