aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/session/sessionrebase.test125
-rw-r--r--ext/session/sqlite3session.c202
-rw-r--r--ext/session/sqlite3session.h33
-rw-r--r--ext/session/test_session.c52
-rw-r--r--manifest20
-rw-r--r--manifest.uuid2
6 files changed, 372 insertions, 62 deletions
diff --git a/ext/session/sessionrebase.test b/ext/session/sessionrebase.test
new file mode 100644
index 000000000..403b3320d
--- /dev/null
+++ b/ext/session/sessionrebase.test
@@ -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
diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c
index 9b96c5ca6..c8d66bb5b 100644
--- a/ext/session/sqlite3session.c
+++ b/ext/session/sqlite3session.c
@@ -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.
diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h
index 407ec6a62..c6a2332b8 100644
--- a/ext/session/sqlite3session.h
+++ b/ext/session/sqlite3session.h
@@ -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,
diff --git a/ext/session/test_session.c b/ext/session/test_session.c
index 411354cc0..dd2d9977a 100644
--- a/ext/session/test_session.c
+++ b/ext/session/test_session.c
@@ -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,12 +768,40 @@ 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
*/
static int SQLITE_TCLAPI test_sqlite3changeset_apply_replace_all(
@@ -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 },
diff --git a/manifest b/manifest
index 6228a1957..5e08ac632 100644
--- 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
diff --git a/manifest.uuid b/manifest.uuid
index a718ce146..1e1f7573d 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-0171d4a71ca7911a9fd409a42eeed0eda4521b6e48df5cd058364c0a736313b7 \ No newline at end of file
+445bfe977d9f3a891e08ef33237862ed047fe83e134ef3ed8b47ee0f5abd8cd6 \ No newline at end of file