/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/sqlite.h.in.

8123
8124
8125
8126
8127
8128
8129



























8130
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
** The application must eventually free every [sqlite3_snapshot] object
** using this routine to avoid a memory leak.
**
** The [sqlite3_snapshot_free()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);




























/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* _SQLITE3_H_ */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













8123
8124
8125
8126
8127
8128
8129
8130
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145
8146
8147
8148
8149
8150
8151
8152
8153
8154
8155
8156
8157
8158
8159
8160
8161
8162
8163
8164
8165
8166
8167
8168
8169
** The application must eventually free every [sqlite3_snapshot] object
** using this routine to avoid a memory leak.
**
** The [sqlite3_snapshot_free()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);

/*
** CAPI3REF: Compare the ages of two snapshot handles.
** EXPERIMENTAL
**
** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
** of two valid snapshot handles. 
**
** If the two snapshot handles are not associated with the same database 
** file, the result of the comparison is undefined. 
**
** Additionally, the result of the comparison is only valid if both of the
** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
** last time the wal file was deleted. The wal file is deleted when the
** database is changed back to rollback mode or when the number of database
** clients drops to zero. If either snapshot handle was obtained before the 
** wal file was last deleted, the value returned by this function 
** is undefined.
**
** Otherwise, this API returns a negative value if P1 refers to an older
** snapshot than P2, zero if the two handles refer to the same database
** snapshot, and a positive value if P1 is a newer snapshot than P2.
*/
SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
  sqlite3_snapshot *p1,
  sqlite3_snapshot *p2
);

/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* _SQLITE3_H_ */

Changes to src/test1.c.

2355
2356
2357
2358
2359
2360
2361

























2362
2363
2364
2365
2366
2367
2368
....
7245
7246
7247
7248
7249
7250
7251

7252
7253
7254
7255
7256
7257
7258
  }
  pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
  sqlite3_snapshot_free(pSnapshot);
  return TCL_OK;
}
#endif /* SQLITE_ENABLE_SNAPSHOT */


























/*
** Usage:  sqlite3_next_stmt  DB  STMT
**
** Return the next statment in sequence after STMT.
*/
static int test_next_stmt(
  void * clientData,
................................................................................
     { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
#endif
     { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
#ifdef SQLITE_ENABLE_SNAPSHOT
     { "sqlite3_snapshot_get", test_snapshot_get, 0 },
     { "sqlite3_snapshot_open", test_snapshot_open, 0 },
     { "sqlite3_snapshot_free", test_snapshot_free, 0 },

#endif
  };
  static int bitmask_size = sizeof(Bitmask)*8;
  static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  int i;
  extern int sqlite3_sync_count, sqlite3_fullsync_count;
  extern int sqlite3_opentemp_count;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
....
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
  }
  pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
  sqlite3_snapshot_free(pSnapshot);
  return TCL_OK;
}
#endif /* SQLITE_ENABLE_SNAPSHOT */

#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** Usage: sqlite3_snapshot_cmp SNAPSHOT1 SNAPSHOT2
*/
static int test_snapshot_cmp(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int res;
  sqlite3_snapshot *p1;
  sqlite3_snapshot *p2;
  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
    return TCL_ERROR;
  }
  p1 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
  p2 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[2]));
  res = sqlite3_snapshot_cmp(p1, p2);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
  return TCL_OK;
}
#endif /* SQLITE_ENABLE_SNAPSHOT */

/*
** Usage:  sqlite3_next_stmt  DB  STMT
**
** Return the next statment in sequence after STMT.
*/
static int test_next_stmt(
  void * clientData,
................................................................................
     { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
#endif
     { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
#ifdef SQLITE_ENABLE_SNAPSHOT
     { "sqlite3_snapshot_get", test_snapshot_get, 0 },
     { "sqlite3_snapshot_open", test_snapshot_open, 0 },
     { "sqlite3_snapshot_free", test_snapshot_free, 0 },
     { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
#endif
  };
  static int bitmask_size = sizeof(Bitmask)*8;
  static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  int i;
  extern int sqlite3_sync_count, sqlite3_fullsync_count;
  extern int sqlite3_opentemp_count;

Changes to src/wal.c.

3395
3396
3397
3398
3399
3400
3401

















3402
3403
3404
3405
3406
3407
3408
}

/* Try to open on pSnapshot when the next read-transaction starts
*/
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
  pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
}

















#endif /* SQLITE_ENABLE_SNAPSHOT */

#ifdef SQLITE_ENABLE_ZIPVFS
/*
** If the argument is not NULL, it points to a Wal object that holds a
** read-lock. This function returns the database page-size if it is known,
** or zero if it is not (or if pWal is NULL).







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
}

/* Try to open on pSnapshot when the next read-transaction starts
*/
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
  pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
}

/* 
** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
*/
int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
  WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
  WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;

  /* aSalt[0] is a copy of the value stored in the wal file header. It
  ** is incremented each time the wal file is restarted.  */
  if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1;
  if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1;
  if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1;
  if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
  return 0;
}
#endif /* SQLITE_ENABLE_SNAPSHOT */

#ifdef SQLITE_ENABLE_ZIPVFS
/*
** If the argument is not NULL, it points to a Wal object that holds a
** read-lock. This function returns the database page-size if it is known,
** or zero if it is not (or if pWal is NULL).

Changes to test/snapshot.test.

360
361
362
363
364
365
366
367










































































368
  db2 close
  sqlite3 db2 test.db 
  db2 eval "BEGIN"
  list [catch {sqlite3_snapshot_open db2 main $::snapshot} msg] $msg
} {1 SQLITE_ERROR}

sqlite3_snapshot_free $snapshot











































































finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  db2 close
  sqlite3 db2 test.db 
  db2 eval "BEGIN"
  list [catch {sqlite3_snapshot_open db2 main $::snapshot} msg] $msg
} {1 SQLITE_ERROR}

sqlite3_snapshot_free $snapshot

#-------------------------------------------------------------------------
# The following tests investigate the sqlite3_snapshot_cmp() API.
#

# Compare snapshots $p1 and $p2, checking that the result is $r.
#
proc do_snapshot_cmp_test {tn p1 p2 r} {
  uplevel [list do_test $tn.1 [list sqlite3_snapshot_cmp $p1 $p2] $r]
  uplevel [list do_test $tn.2 [list sqlite3_snapshot_cmp $p2 $p1] [expr $r*-1]]
  uplevel [list do_test $tn.3 [list sqlite3_snapshot_cmp $p1 $p1] 0]
  uplevel [list do_test $tn.4 [list sqlite3_snapshot_cmp $p2 $p2] 0]
}

catch { db2 close }
reset_db

do_execsql_test 7.1 {
  PRAGMA journal_mode = wal;
  CREATE TABLE t1(x);
} wal

do_test 7.1.2 {
  execsql { BEGIN ; PRAGMA application_id }
  set p1 [sqlite3_snapshot_get db main]
  execsql {
    INSERT INTO t1 VALUES(10);
    COMMIT;
  }
  execsql { BEGIN ; PRAGMA application_id }
  set p2 [sqlite3_snapshot_get db main]
  execsql COMMIT
} {}

do_snapshot_cmp_test 7.1.3 $p1 $p2 -1
sqlite3_snapshot_free $p1
sqlite3_snapshot_free $p2

do_execsql_test 7.2.1 {
  INSERT INTO t1 VALUES(11);
  INSERT INTO t1 VALUES(12);
  INSERT INTO t1 VALUES(13);
  BEGIN; 
    PRAGMA application_id;
} {0}
do_test 7.2.2 {
  set p1 [sqlite3_snapshot_get db main]
  execsql {
    COMMIT;
    INSERT INTO t1 VALUES(14);
    PRAGMA wal_checkpoint;
    BEGIN;
      PRAGMA application_id;
  }
  set p2 [sqlite3_snapshot_get db main]
  execsql COMMIT
} {}

do_snapshot_cmp_test 7.2.3 $p1 $p2 -1
sqlite3_snapshot_free $p2

do_test 7.3.1 {
  execsql {
    INSERT INTO t1 VALUES(14);
    BEGIN;
      PRAGMA application_id;
  }
  set p2 [sqlite3_snapshot_get db main]
  execsql COMMIT
} {}

do_snapshot_cmp_test 7.3.2 $p1 $p2 -1
sqlite3_snapshot_free $p1
sqlite3_snapshot_free $p2

finish_test