/ Check-in [7e728965]
Login

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

Overview
Comment:Add the sqlite3_snapshot_cmp() interface (available only with SQLITE_ENABLE_SNAPSHOT).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7e7289655185e7643ead6d685922528bc4d9e0ae
User & Date: drh 2016-04-12 16:04:07
Context
2016-04-12
16:23
Improved localtime() support for WindowsCE check-in: 662c32af user: drh tags: trunk
16:10
Merge enhancements from trunk. check-in: 9682c043 user: drh tags: tempfiles-lazy-open
16:04
Add the sqlite3_snapshot_cmp() interface (available only with SQLITE_ENABLE_SNAPSHOT). check-in: 7e728965 user: drh tags: trunk
15:14
Update the documentation for sqlite3_snapshot_cmp() to make the circumstances under which the comparison is valid clearer. Add tests for the same. Closed-Leaf check-in: 8fc83474 user: dan tags: snapshot-cmp
11:58
Update the header comment on the memjournal.c file. No code changes. check-in: 07f10dea user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/sqlite.h.in.

  8123   8123   ** The application must eventually free every [sqlite3_snapshot] object
  8124   8124   ** using this routine to avoid a memory leak.
  8125   8125   **
  8126   8126   ** The [sqlite3_snapshot_free()] interface is only available when the
  8127   8127   ** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
  8128   8128   */
  8129   8129   SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
         8130  +
         8131  +/*
         8132  +** CAPI3REF: Compare the ages of two snapshot handles.
         8133  +** EXPERIMENTAL
         8134  +**
         8135  +** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
         8136  +** of two valid snapshot handles. 
         8137  +**
         8138  +** If the two snapshot handles are not associated with the same database 
         8139  +** file, the result of the comparison is undefined. 
         8140  +**
         8141  +** Additionally, the result of the comparison is only valid if both of the
         8142  +** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
         8143  +** last time the wal file was deleted. The wal file is deleted when the
         8144  +** database is changed back to rollback mode or when the number of database
         8145  +** clients drops to zero. If either snapshot handle was obtained before the 
         8146  +** wal file was last deleted, the value returned by this function 
         8147  +** is undefined.
         8148  +**
         8149  +** Otherwise, this API returns a negative value if P1 refers to an older
         8150  +** snapshot than P2, zero if the two handles refer to the same database
         8151  +** snapshot, and a positive value if P1 is a newer snapshot than P2.
         8152  +*/
         8153  +SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
         8154  +  sqlite3_snapshot *p1,
         8155  +  sqlite3_snapshot *p2
         8156  +);
  8130   8157   
  8131   8158   /*
  8132   8159   ** Undo the hack that converts floating point types to integer for
  8133   8160   ** builds on processors without floating point support.
  8134   8161   */
  8135   8162   #ifdef SQLITE_OMIT_FLOATING_POINT
  8136   8163   # undef double
  8137   8164   #endif
  8138   8165   
  8139   8166   #ifdef __cplusplus
  8140   8167   }  /* End of the 'extern "C"' block */
  8141   8168   #endif
  8142   8169   #endif /* _SQLITE3_H_ */

Changes to src/test1.c.

  2355   2355     }
  2356   2356     pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
  2357   2357     sqlite3_snapshot_free(pSnapshot);
  2358   2358     return TCL_OK;
  2359   2359   }
  2360   2360   #endif /* SQLITE_ENABLE_SNAPSHOT */
  2361   2361   
         2362  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2363  +/*
         2364  +** Usage: sqlite3_snapshot_cmp SNAPSHOT1 SNAPSHOT2
         2365  +*/
         2366  +static int test_snapshot_cmp(
         2367  +  void * clientData,
         2368  +  Tcl_Interp *interp,
         2369  +  int objc,
         2370  +  Tcl_Obj *CONST objv[]
         2371  +){
         2372  +  int res;
         2373  +  sqlite3_snapshot *p1;
         2374  +  sqlite3_snapshot *p2;
         2375  +  if( objc!=3 ){
         2376  +    Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
         2377  +    return TCL_ERROR;
         2378  +  }
         2379  +  p1 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         2380  +  p2 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[2]));
         2381  +  res = sqlite3_snapshot_cmp(p1, p2);
         2382  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
         2383  +  return TCL_OK;
         2384  +}
         2385  +#endif /* SQLITE_ENABLE_SNAPSHOT */
         2386  +
  2362   2387   /*
  2363   2388   ** Usage:  sqlite3_next_stmt  DB  STMT
  2364   2389   **
  2365   2390   ** Return the next statment in sequence after STMT.
  2366   2391   */
  2367   2392   static int test_next_stmt(
  2368   2393     void * clientData,
................................................................................
  7245   7270        { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
  7246   7271   #endif
  7247   7272        { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
  7248   7273   #ifdef SQLITE_ENABLE_SNAPSHOT
  7249   7274        { "sqlite3_snapshot_get", test_snapshot_get, 0 },
  7250   7275        { "sqlite3_snapshot_open", test_snapshot_open, 0 },
  7251   7276        { "sqlite3_snapshot_free", test_snapshot_free, 0 },
         7277  +     { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
  7252   7278   #endif
  7253   7279     };
  7254   7280     static int bitmask_size = sizeof(Bitmask)*8;
  7255   7281     static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  7256   7282     int i;
  7257   7283     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  7258   7284     extern int sqlite3_opentemp_count;

Changes to src/wal.c.

  3395   3395   }
  3396   3396   
  3397   3397   /* Try to open on pSnapshot when the next read-transaction starts
  3398   3398   */
  3399   3399   void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
  3400   3400     pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
  3401   3401   }
         3402  +
         3403  +/* 
         3404  +** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
         3405  +** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
         3406  +*/
         3407  +int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
         3408  +  WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
         3409  +  WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;
         3410  +
         3411  +  /* aSalt[0] is a copy of the value stored in the wal file header. It
         3412  +  ** is incremented each time the wal file is restarted.  */
         3413  +  if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1;
         3414  +  if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1;
         3415  +  if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1;
         3416  +  if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
         3417  +  return 0;
         3418  +}
  3402   3419   #endif /* SQLITE_ENABLE_SNAPSHOT */
  3403   3420   
  3404   3421   #ifdef SQLITE_ENABLE_ZIPVFS
  3405   3422   /*
  3406   3423   ** If the argument is not NULL, it points to a Wal object that holds a
  3407   3424   ** read-lock. This function returns the database page-size if it is known,
  3408   3425   ** or zero if it is not (or if pWal is NULL).

Changes to test/snapshot.test.

   360    360     db2 close
   361    361     sqlite3 db2 test.db 
   362    362     db2 eval "BEGIN"
   363    363     list [catch {sqlite3_snapshot_open db2 main $::snapshot} msg] $msg
   364    364   } {1 SQLITE_ERROR}
   365    365   
   366    366   sqlite3_snapshot_free $snapshot
          367  +
          368  +#-------------------------------------------------------------------------
          369  +# The following tests investigate the sqlite3_snapshot_cmp() API.
          370  +#
          371  +
          372  +# Compare snapshots $p1 and $p2, checking that the result is $r.
          373  +#
          374  +proc do_snapshot_cmp_test {tn p1 p2 r} {
          375  +  uplevel [list do_test $tn.1 [list sqlite3_snapshot_cmp $p1 $p2] $r]
          376  +  uplevel [list do_test $tn.2 [list sqlite3_snapshot_cmp $p2 $p1] [expr $r*-1]]
          377  +  uplevel [list do_test $tn.3 [list sqlite3_snapshot_cmp $p1 $p1] 0]
          378  +  uplevel [list do_test $tn.4 [list sqlite3_snapshot_cmp $p2 $p2] 0]
          379  +}
          380  +
          381  +catch { db2 close }
          382  +reset_db
          383  +
          384  +do_execsql_test 7.1 {
          385  +  PRAGMA journal_mode = wal;
          386  +  CREATE TABLE t1(x);
          387  +} wal
          388  +
          389  +do_test 7.1.2 {
          390  +  execsql { BEGIN ; PRAGMA application_id }
          391  +  set p1 [sqlite3_snapshot_get db main]
          392  +  execsql {
          393  +    INSERT INTO t1 VALUES(10);
          394  +    COMMIT;
          395  +  }
          396  +  execsql { BEGIN ; PRAGMA application_id }
          397  +  set p2 [sqlite3_snapshot_get db main]
          398  +  execsql COMMIT
          399  +} {}
          400  +
          401  +do_snapshot_cmp_test 7.1.3 $p1 $p2 -1
          402  +sqlite3_snapshot_free $p1
          403  +sqlite3_snapshot_free $p2
          404  +
          405  +do_execsql_test 7.2.1 {
          406  +  INSERT INTO t1 VALUES(11);
          407  +  INSERT INTO t1 VALUES(12);
          408  +  INSERT INTO t1 VALUES(13);
          409  +  BEGIN; 
          410  +    PRAGMA application_id;
          411  +} {0}
          412  +do_test 7.2.2 {
          413  +  set p1 [sqlite3_snapshot_get db main]
          414  +  execsql {
          415  +    COMMIT;
          416  +    INSERT INTO t1 VALUES(14);
          417  +    PRAGMA wal_checkpoint;
          418  +    BEGIN;
          419  +      PRAGMA application_id;
          420  +  }
          421  +  set p2 [sqlite3_snapshot_get db main]
          422  +  execsql COMMIT
          423  +} {}
          424  +
          425  +do_snapshot_cmp_test 7.2.3 $p1 $p2 -1
          426  +sqlite3_snapshot_free $p2
          427  +
          428  +do_test 7.3.1 {
          429  +  execsql {
          430  +    INSERT INTO t1 VALUES(14);
          431  +    BEGIN;
          432  +      PRAGMA application_id;
          433  +  }
          434  +  set p2 [sqlite3_snapshot_get db main]
          435  +  execsql COMMIT
          436  +} {}
          437  +
          438  +do_snapshot_cmp_test 7.3.2 $p1 $p2 -1
          439  +sqlite3_snapshot_free $p1
          440  +sqlite3_snapshot_free $p2
   367    441   
   368    442   finish_test