]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add sqlite3_changeset_apply_v2() and apply_v2_strm() to the sessions module.
authordan <dan@noemail.net>
Tue, 13 Mar 2018 20:31:23 +0000 (20:31 +0000)
committerdan <dan@noemail.net>
Tue, 13 Mar 2018 20:31:23 +0000 (20:31 +0000)
FossilOrigin-Name: 445bfe977d9f3a891e08ef33237862ed047fe83e134ef3ed8b47ee0f5abd8cd6

ext/session/sessionrebase.test [new file with mode: 0644]
ext/session/sqlite3session.c
ext/session/sqlite3session.h
ext/session/test_session.c
manifest
manifest.uuid

diff --git a/ext/session/sessionrebase.test b/ext/session/sessionrebase.test
new file mode 100644 (file)
index 0000000..403b332
--- /dev/null
@@ -0,0 +1,125 @@
+# 2018 March 14
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+
+if {![info exists testdir]} {
+  set testdir [file join [file dirname [info script]] .. .. test]
+} 
+source [file join [file dirname [info script]] session_common.tcl]
+source $testdir/tester.tcl
+ifcapable !session {finish_test; return}
+
+set testprefix sessionrebase
+
+set ::lConflict [list]
+proc xConflict {args} {
+  set res [lindex $::lConflict 0]
+  set ::lConflict [lrange $::lConflict 1 end]
+  return $res
+}
+
+#-------------------------------------------------------------------------
+# The following test cases - 1.* - test that the rebase blobs output by
+# sqlite3_changeset_apply_v2 look correct in some simple cases. The blob
+# is itself a changeset, containing records determined as follows:
+#
+#   * For each conflict resolved with REPLACE, the rebase blob contains
+#     a DELETE record. All fields other than the PK fields are undefined.
+#
+#   * For each conflict resolved with OMIT, the rebase blob contains an
+#     INSERT record. For an INSERT or UPDATE operation, the indirect flag
+#     is clear and all updated fields are defined. For a DELETE operation,
+#     the indirect flag is set and all non-PK fields left undefined.
+#
+proc do_apply_v2_test {tn sql modsql conflict_handler res} {
+  
+  execsql BEGIN
+  sqlite3session S db main
+  S attach *
+  execsql $sql
+  set changeset [S changeset]
+  S delete
+  execsql ROLLBACK
+
+  execsql BEGIN
+  execsql $modsql
+  set ::lConflict $conflict_handler
+  set blob [sqlite3changeset_apply_v2 db $changeset xConflict]
+  execsql ROLLBACK
+
+  uplevel [list do_test $tn [list changeset_to_list $blob] [list {*}$res]]
+}
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+  INSERT INTO t1 VALUES(1, 'value A');
+}
+
+do_apply_v2_test 1.1.1 {
+  UPDATE t1 SET b = 'value B' WHERE a=1;
+} {
+  UPDATE t1 SET b = 'value C' WHERE a=1;
+} {
+  OMIT
+} {
+  {INSERT t1 0 X. {} {i 1 t {value B}}}
+}
+do_apply_v2_test 1.1.2 {
+  UPDATE t1 SET b = 'value B' WHERE a=1;
+} {
+  UPDATE t1 SET b = 'value C' WHERE a=1;
+} {
+  REPLACE
+} {
+  {DELETE t1 0 X. {i 1 {} {}} {}}
+}
+
+do_apply_v2_test 1.2.1 {
+  INSERT INTO t1 VALUES(2, 'first');
+} {
+  INSERT INTO t1 VALUES(2, 'second');
+} {
+  OMIT
+} {
+  {INSERT t1 0 X. {} {i 2 t first}}
+}
+do_apply_v2_test 1.2.2 {
+  INSERT INTO t1 VALUES(2, 'first');
+} {
+  INSERT INTO t1 VALUES(2, 'second');
+} {
+  REPLACE
+} {
+  {DELETE t1 0 X. {i 2 {} {}} {}}
+}
+
+do_apply_v2_test 1.3.1 {
+  DELETE FROM t1 WHERE a=1;
+} {
+  UPDATE t1 SET b='value D' WHERE a=1;
+} {
+  OMIT
+} {
+  {INSERT t1 1 X. {} {i 1 {} {}}}
+}
+do_apply_v2_test 1.3.2 {
+  DELETE FROM t1 WHERE a=1;
+} {
+  UPDATE t1 SET b='value D' WHERE a=1;
+} {
+  REPLACE
+} {
+  {DELETE t1 0 X. {i 1 {} {}} {}}
+}
+
+
+finish_test
index 9b96c5ca6f01bbf7f0af6303eff3d40162a29c10..c8d66bb5be3739db99ebf2a7dde3adc1741c64e3 100644 (file)
@@ -3410,6 +3410,8 @@ struct SessionApplyCtx {
   int bStat1;                     /* True if table is sqlite_stat1 */
   int bDeferConstraints;          /* True to defer constraints */
   SessionBuffer constraints;      /* Deferred constraints are stored here */
+  SessionBuffer rebase;           /* Rebase information (if any) here */
+  int bRebaseStarted;             /* If table header is already in rebase */
 };
 
 /*
@@ -3791,6 +3793,60 @@ static int sessionSeekToRow(
   return rc;
 }
 
+static int sessionRebaseAdd(
+  SessionApplyCtx *p, 
+  int eType, 
+  sqlite3_changeset_iter *pIter
+){
+  int rc = SQLITE_OK;
+  int i;
+  int eOp = pIter->op;
+  if( p->bRebaseStarted==0 ){
+    /* Append a table-header to the rebase buffer */
+    const char *zTab = pIter->zTab;
+    sessionAppendByte(&p->rebase, 'T', &rc);
+    sessionAppendVarint(&p->rebase, p->nCol, &rc);
+    sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc);
+    sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc);
+    p->bRebaseStarted = 1;
+  }
+
+  assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
+  assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
+
+  if( eType==SQLITE_CHANGESET_REPLACE ){
+    sessionAppendByte(&p->rebase, SQLITE_DELETE, &rc);
+    sessionAppendByte(&p->rebase, 0, &rc);
+    for(i=0; i<p->nCol; i++){
+      if( p->abPK[i]==0 ){
+        sessionAppendByte(&p->rebase, 0, &rc);
+      }else{
+        sqlite3_value *pVal = 0;
+        if( eOp==SQLITE_INSERT ){
+          sqlite3changeset_new(pIter, i, &pVal);
+        }else{
+          sqlite3changeset_old(pIter, i, &pVal);
+        }
+        sessionAppendValue(&p->rebase, pVal, &rc);
+      }
+    }
+  }else{
+    sessionAppendByte(&p->rebase, SQLITE_INSERT, &rc);
+    sessionAppendByte(&p->rebase, eOp==SQLITE_DELETE, &rc);
+    for(i=0; i<p->nCol; i++){
+      sqlite3_value *pVal = 0;
+      if( eOp!=SQLITE_INSERT && p->abPK[i] ){
+        sqlite3changeset_old(pIter, i, &pVal);
+      }else{
+        sqlite3changeset_new(pIter, i, &pVal);
+      }
+      sessionAppendValue(&p->rebase, pVal, &rc);
+    }
+  }
+
+  return rc;
+}
+
 /*
 ** Invoke the conflict handler for the change that the changeset iterator
 ** currently points to.
@@ -3866,7 +3922,7 @@ static int sessionConflictHandler(
       u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
       int nBlob = pIter->in.iNext - pIter->in.iCurrent;
       sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
-      res = SQLITE_CHANGESET_OMIT;
+      return SQLITE_OK;
     }else{
       /* No other row with the new.* primary key. */
       res = xConflict(pCtx, eType+1, pIter);
@@ -3892,6 +3948,9 @@ static int sessionConflictHandler(
         rc = SQLITE_MISUSE;
         break;
     }
+    if( rc==SQLITE_OK ){
+      rc = sessionRebaseAdd(p, res, pIter);
+    }
   }
 
   return rc;
@@ -4067,42 +4126,42 @@ static int sessionApplyOneWithRetry(
   int rc;
 
   rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
-  assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) );
-
-  /* If the bRetry flag is set, the change has not been applied due to an
-  ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
-  ** a row with the correct PK is present in the db, but one or more other
-  ** fields do not contain the expected values) and the conflict handler 
-  ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
-  ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
-  ** the SQLITE_CHANGESET_DATA problem.  */
-  if( bRetry ){
-    assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
-    rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
-  }
-
-  /* If the bReplace flag is set, the change is an INSERT that has not
-  ** been performed because the database already contains a row with the
-  ** specified primary key and the conflict handler returned
-  ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
-  ** before reattempting the INSERT.  */
-  else if( bReplace ){
-    assert( pIter->op==SQLITE_INSERT );
-    rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
-    if( rc==SQLITE_OK ){
-      rc = sessionBindRow(pIter, 
-          sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
-      sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
-    }
-    if( rc==SQLITE_OK ){
-      sqlite3_step(pApply->pDelete);
-      rc = sqlite3_reset(pApply->pDelete);
-    }
-    if( rc==SQLITE_OK ){
+  if( rc==SQLITE_OK ){
+    /* If the bRetry flag is set, the change has not been applied due to an
+    ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
+    ** a row with the correct PK is present in the db, but one or more other
+    ** fields do not contain the expected values) and the conflict handler 
+    ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
+    ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
+    ** the SQLITE_CHANGESET_DATA problem.  */
+    if( bRetry ){
+      assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
       rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
     }
-    if( rc==SQLITE_OK ){
-      rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
+
+    /* If the bReplace flag is set, the change is an INSERT that has not
+    ** been performed because the database already contains a row with the
+    ** specified primary key and the conflict handler returned
+    ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
+    ** before reattempting the INSERT.  */
+    else if( bReplace ){
+      assert( pIter->op==SQLITE_INSERT );
+      rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
+      if( rc==SQLITE_OK ){
+        rc = sessionBindRow(pIter, 
+            sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
+        sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
+      }
+      if( rc==SQLITE_OK ){
+        sqlite3_step(pApply->pDelete);
+        rc = sqlite3_reset(pApply->pDelete);
+      }
+      if( rc==SQLITE_OK ){
+        rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
+      }
+      if( rc==SQLITE_OK ){
+        rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
+      }
     }
   }
 
@@ -4178,7 +4237,8 @@ static int sessionChangesetApply(
     int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
     sqlite3_changeset_iter *p     /* Handle describing change and conflict */
   ),
-  void *pCtx                      /* First argument passed to xConflict */
+  void *pCtx,                     /* First argument passed to xConflict */
+  void **ppRebase, int *pnRebase  /* OUT: Rebase information */
 ){
   int schemaMismatch = 0;
   int rc;                         /* Return code */
@@ -4219,6 +4279,7 @@ static int sessionChangesetApply(
       memset(&sApply, 0, sizeof(sApply));
       sApply.db = db;
       sApply.bDeferConstraints = 1;
+      sApply.bRebaseStarted = 0;
 
       /* If an xFilter() callback was specified, invoke it now. If the 
       ** xFilter callback returns zero, skip this table. If it returns
@@ -4328,16 +4389,48 @@ static int sessionChangesetApply(
     sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
   }
 
+  if( rc==SQLITE_OK && ppRebase && pnRebase ){
+    *ppRebase = (void*)sApply.rebase.aBuf;
+    *pnRebase = sApply.rebase.nBuf;
+    sApply.rebase.aBuf = 0;
+  }
   sqlite3_finalize(sApply.pInsert);
   sqlite3_finalize(sApply.pDelete);
   sqlite3_finalize(sApply.pUpdate);
   sqlite3_finalize(sApply.pSelect);
   sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
   sqlite3_free((char*)sApply.constraints.aBuf);
+  sqlite3_free((char*)sApply.rebase.aBuf);
   sqlite3_mutex_leave(sqlite3_db_mutex(db));
   return rc;
 }
 
+int sqlite3changeset_apply_v2(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  int nChangeset,                 /* Size of changeset in bytes */
+  void *pChangeset,               /* Changeset blob */
+  int(*xFilter)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    const char *zTab              /* Table name */
+  ),
+  int(*xConflict)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
+    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
+  ),
+  void *pCtx,                     /* First argument passed to xConflict */
+  void **ppRebase, int *pnRebase
+){
+  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
+  int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
+  if( rc==SQLITE_OK ){
+    rc = sessionChangesetApply(
+        db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase
+    );
+  }
+  return rc;
+}
+
 /*
 ** Apply the changeset passed via pChangeset/nChangeset to the main database
 ** attached to handle "db". Invoke the supplied conflict handler callback
@@ -4358,12 +4451,9 @@ int sqlite3changeset_apply(
   ),
   void *pCtx                      /* First argument passed to xConflict */
 ){
-  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
-  int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
-  if( rc==SQLITE_OK ){
-    rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
-  }
-  return rc;
+  return sqlite3changeset_apply_v2(
+      db, nChangeset, pChangeset, xFilter, xConflict, pCtx, 0, 0
+  );
 }
 
 /*
@@ -4371,7 +4461,7 @@ int sqlite3changeset_apply(
 ** attached to handle "db". Invoke the supplied conflict handler callback
 ** to resolve any conflicts encountered while applying the change.
 */
-int sqlite3changeset_apply_strm(
+int sqlite3changeset_apply_v2_strm(
   sqlite3 *db,                    /* Apply change to "main" db of this handle */
   int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
   void *pIn,                                          /* First arg for xInput */
@@ -4384,15 +4474,37 @@ int sqlite3changeset_apply_strm(
     int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
     sqlite3_changeset_iter *p     /* Handle describing change and conflict */
   ),
-  void *pCtx                      /* First argument passed to xConflict */
+  void *pCtx,                     /* First argument passed to xConflict */
+  void **ppRebase, int *pnRebase
 ){
   sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
   int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
   if( rc==SQLITE_OK ){
-    rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
+    rc = sessionChangesetApply(
+        db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase
+    );
   }
   return rc;
 }
+int sqlite3changeset_apply_strm(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+  void *pIn,                                          /* First arg for xInput */
+  int(*xFilter)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    const char *zTab              /* Table name */
+  ),
+  int(*xConflict)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
+    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
+  ),
+  void *pCtx                      /* First argument passed to xConflict */
+){
+  return sqlite3changeset_apply_v2_strm(
+      db, xInput, pIn, xFilter, xConflict, pCtx, 0, 0
+  );
+}
 
 /*
 ** sqlite3_changegroup handle.
index 407ec6a62b8eeb87f37e2e871bef2a98c1272f32..c6a2332b8d5722171b29bc886fae285e793bf421 100644 (file)
@@ -1103,6 +1103,23 @@ int sqlite3changeset_apply(
   void *pCtx                      /* First argument passed to xConflict */
 );
 
+int sqlite3changeset_apply_v2(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  int nChangeset,                 /* Size of changeset in bytes */
+  void *pChangeset,               /* Changeset blob */
+  int(*xFilter)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    const char *zTab              /* Table name */
+  ),
+  int(*xConflict)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
+    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
+  ),
+  void *pCtx,                     /* First argument passed to xConflict */
+  void **ppRebase, int *pnRebase
+);
+
 /* 
 ** CAPI3REF: Constants Passed To The Conflict Handler
 **
@@ -1303,6 +1320,22 @@ int sqlite3changeset_apply_strm(
   ),
   void *pCtx                      /* First argument passed to xConflict */
 );
+int sqlite3changeset_apply_v2_strm(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+  void *pIn,                                          /* First arg for xInput */
+  int(*xFilter)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    const char *zTab              /* Table name */
+  ),
+  int(*xConflict)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
+    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
+  ),
+  void *pCtx,                     /* First argument passed to xConflict */
+  void **ppRebase, int *pnRebase
+);
 int sqlite3changeset_concat_strm(
   int (*xInputA)(void *pIn, void *pData, int *pnData),
   void *pInA,
index 411354cc02d41415bc18f8b6924d8d413cea6799..dd2d9977aa8276563babe6168afa6670e24a3f15 100644 (file)
@@ -711,10 +711,8 @@ static int testStreamInput(
 }
 
 
-/*
-** sqlite3changeset_apply DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?
-*/
-static int SQLITE_TCLAPI test_sqlite3changeset_apply(
+static int SQLITE_TCLAPI testSqlite3changesetApply(
+  int bV2,
   void * clientData,
   Tcl_Interp *interp,
   int objc,
@@ -727,6 +725,8 @@ static int SQLITE_TCLAPI test_sqlite3changeset_apply(
   int nChangeset;                 /* Size of buffer aChangeset in bytes */
   TestConflictHandler ctx;
   TestStreamInput sStr;
+  void *pRebase = 0;
+  int nRebase = 0;
 
   memset(&sStr, 0, sizeof(sStr));
   sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
@@ -748,9 +748,16 @@ static int SQLITE_TCLAPI test_sqlite3changeset_apply(
   ctx.interp = interp;
 
   if( sStr.nStream==0 ){
-    rc = sqlite3changeset_apply(db, nChangeset, pChangeset, 
-        (objc==5) ? test_filter_handler : 0, test_conflict_handler, (void *)&ctx
-    );
+    if( bV2==0 ){
+      rc = sqlite3changeset_apply(db, nChangeset, pChangeset, 
+          (objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx
+      );
+    }else{
+      rc = sqlite3changeset_apply_v2(db, nChangeset, pChangeset, 
+          (objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx,
+          &pRebase, &nRebase
+      );
+    }
   }else{
     sStr.aData = (unsigned char*)pChangeset;
     sStr.nData = nChangeset;
@@ -761,11 +768,39 @@ static int SQLITE_TCLAPI test_sqlite3changeset_apply(
 
   if( rc!=SQLITE_OK ){
     return test_session_error(interp, rc, 0);
+  }else{
+    Tcl_ResetResult(interp);
+    if( bV2 && pRebase ){
+      Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pRebase, nRebase));
+    }
   }
-  Tcl_ResetResult(interp);
+  sqlite3_free(pRebase);
   return TCL_OK;
 }
 
+/*
+** sqlite3changeset_apply DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?
+*/
+static int SQLITE_TCLAPI test_sqlite3changeset_apply(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  return testSqlite3changesetApply(0, clientData, interp, objc, objv);
+}
+/*
+** sqlite3changeset_apply_v2 DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?
+*/
+static int SQLITE_TCLAPI test_sqlite3changeset_apply_v2(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  return testSqlite3changesetApply(1, clientData, interp, objc, objv);
+}
+
 /*
 ** sqlite3changeset_apply_replace_all DB CHANGESET 
 */
@@ -1029,6 +1064,7 @@ int TestSession_Init(Tcl_Interp *interp){
     { "sqlite3changeset_invert", test_sqlite3changeset_invert },
     { "sqlite3changeset_concat", test_sqlite3changeset_concat },
     { "sqlite3changeset_apply", test_sqlite3changeset_apply },
+    { "sqlite3changeset_apply_v2", test_sqlite3changeset_apply_v2 },
     { "sqlite3changeset_apply_replace_all", 
       test_sqlite3changeset_apply_replace_all },
     { "sql_exec_changeset", test_sql_exec_changeset },
index 6228a1957810188494989b7e2ac447f7577096a5..5e08ac632cc5bc4da31d76df809577a4d3f6382a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\stypo\scausing\sSQLITE_LOG_CACHE_SPILL\sbuilds\sto\sfail.
-D 2018-03-12T21:09:16.462
+C Add\ssqlite3_changeset_apply_v2()\sand\sapply_v2_strm()\sto\sthe\ssessions\smodule.
+D 2018-03-13T20:31:23.940
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 7016fc56c6b9bfe5daac4f34be8be38d8c0b5fab79ccbfb764d3b23bf1c6fff3
@@ -400,11 +400,12 @@ F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28
 F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
 F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
 F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
+F ext/session/sessionrebase.test b4ac7545e3c69deaeab061c2bf36ad9e99aa6c38db94c340d7e48a230a9d4be8
 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e
 F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
-F ext/session/sqlite3session.c 9edfaaa74977ddecd7bbd94e8f844d9b0f6eec22d1d547e806361670db814c1e
-F ext/session/sqlite3session.h 2e1584b030fbd841cefdce15ba984871978d305f586da2d1972f6e1958fa10b1
-F ext/session/test_session.c eb0bd6c1ea791c1d66ee4ef94c16500dad936386
+F ext/session/sqlite3session.c 564e609f3086510d319e8abc0899fa79131d071b7dc01138e1b75bbf4a43cb03
+F ext/session/sqlite3session.h 8fe499b736633021094b814cf128691587f19c1943e372a23db37175bdeb8c67
+F ext/session/test_session.c 6c45bee58063f2c3d1edc213833d72f0a3ec651cbe27393b9e4a054e711b7c44
 F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
 F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
@@ -1712,7 +1713,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 61eeb48f03f8a9a32330a5cae4387bb4e5618078cf669a5831910f99126900ec
-R cc8ceb6c97c49d267aa8c6c8a3936381
+P 0171d4a71ca7911a9fd409a42eeed0eda4521b6e48df5cd058364c0a736313b7
+R 1a6994480e1e2c2b73e68977f31547a3
+T *branch * sessions-rebase
+T *sym-sessions-rebase *
+T -sym-trunk *
 U dan
-Z 467f1d68de166a5be6bc42e03b4e2dce
+Z d8bbc56681a1d6ff1f4fb97dc44d1b66
index a718ce14606385201f92f2e3f2f41ecc20153472..1e1f7573de0446eb03cb3ffe73b53ad863e2a87a 100644 (file)
@@ -1 +1 @@
-0171d4a71ca7911a9fd409a42eeed0eda4521b6e48df5cd058364c0a736313b7
\ No newline at end of file
+445bfe977d9f3a891e08ef33237862ed047fe83e134ef3ed8b47ee0f5abd8cd6
\ No newline at end of file