From 46de0728802703082967d4c563d12a2b5d154e57 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 20 Oct 2018 13:48:09 +0000 Subject: [PATCH] Add the sqlite3changeset_start_v2() - a new version of _start() that accepts a flags parameter - and a streaming equivalent to the sessions module. Also add the SQLITE_CHANGESETSTART_INVERT flag, used with start_v2() to invert a changeset while iterating through it. FossilOrigin-Name: cbedcb9aaefdfe00453efbdf0eac6c15e1f53bbe8fff2e7d534a5adf23be04f5 --- ext/session/sessioninvert.test | 47 +++++++++++++++++++++++++++++--- ext/session/sqlite3session.c | 18 +++++++++++++ ext/session/sqlite3session.h | 34 ++++++++++++++++++++++- ext/session/test_session.c | 49 +++++++++++++++++++++++++--------- manifest | 18 ++++++------- manifest.uuid | 2 +- 6 files changed, 141 insertions(+), 27 deletions(-) diff --git a/ext/session/sessioninvert.test b/ext/session/sessioninvert.test index 52260af215..49205f6b26 100644 --- a/ext/session/sessioninvert.test +++ b/ext/session/sessioninvert.test @@ -20,7 +20,13 @@ ifcapable !session {finish_test; return} set testprefix sessioninvert -proc do_invert_test {tn sql} { +proc iter_invert {C} { + set x [list] + sqlite3session_foreach -invert c $C { lappend x $c } + set x +} + +proc do_invert_test {tn sql {iter {}}} { forcecopy test.db test.db2 sqlite3 db2 test.db2 @@ -38,6 +44,10 @@ proc do_invert_test {tn sql} { sqlite3changeset_apply_v2 -invert db3 $C {} uplevel [list do_test $tn.3 [list compare_db db db3] {}] + if {$iter!=""} { + uplevel [list do_test $tn.4 [list iter_invert $C] [list {*}$iter]] + } + catch { db2 close } catch { db3 close } } @@ -58,24 +68,44 @@ do_execsql_test 1.0 { do_invert_test 1.1 { INSERT INTO t1 VALUES(7, 'seven', 'vii'); +} { + {DELETE t1 0 X.. {i 7 t seven t vii} {}} } do_invert_test 1.2 { DELETE FROM t1 WHERE a<4; +} { + {INSERT t1 0 X.. {} {i 1 t one t i}} + {INSERT t1 0 X.. {} {i 2 t two t ii}} + {INSERT t1 0 X.. {} {i 3 t three t iii}} } -do_invert_test 1.2 { +do_invert_test 1.3 { UPDATE t1 SET c=5; +} { + {UPDATE t1 0 X.. {i 1 {} {} i 5} {{} {} {} {} t i}} + {UPDATE t1 0 X.. {i 2 {} {} i 5} {{} {} {} {} t ii}} + {UPDATE t1 0 X.. {i 3 {} {} i 5} {{} {} {} {} t iii}} + {UPDATE t1 0 X.. {i 4 {} {} i 5} {{} {} {} {} t iv}} + {UPDATE t1 0 X.. {i 5 {} {} i 5} {{} {} {} {} t v}} + {UPDATE t1 0 X.. {i 6 {} {} i 5} {{} {} {} {} t vi}} } -do_invert_test 1.3 { +do_invert_test 1.4 { UPDATE t1 SET b = a+1 WHERE a%2; DELETE FROM t2; INSERT INTO t1 VALUES(10, 'ten', NULL); } -do_invert_test 1.4 { +do_invert_test 1.5 { UPDATE t2 SET d = d-1; +} { + {UPDATE t2 0 .XX {i 2 t three t iii} {i 3 {} {} {} {}}} + {UPDATE t2 0 .XX {i 1 t two t ii} {i 2 {} {} {} {}}} + {UPDATE t2 0 .XX {i 5 t six t vi} {i 6 {} {} {} {}}} + {UPDATE t2 0 .XX {i 3 t four t iv} {i 4 {} {} {} {}}} + {UPDATE t2 0 .XX {i 0 t one t i} {i 1 {} {} {} {}}} + {UPDATE t2 0 .XX {i 4 t five t v} {i 5 {} {} {} {}}} } do_execsql_test 2.0 { @@ -90,10 +120,15 @@ do_execsql_test 2.0 { do_invert_test 2.1 { INSERT INTO sqlite_stat1 VALUES('t3', 'idx2', '1 2 3'); +} { + {DELETE sqlite_stat1 0 XX. {t t3 t idx2 t {1 2 3}} {}} } do_invert_test 2.2 { DELETE FROM sqlite_stat1; +} { + {INSERT sqlite_stat1 0 XX. {} {t t1 t sqlite_autoindex_t1_1 t {6 1}}} + {INSERT sqlite_stat1 0 XX. {} {t t2 t sqlite_autoindex_t2_1 t {6 1 1}}} } do_invert_test 2.3 { @@ -112,6 +147,10 @@ do_test 3.0 { } {1 SQLITE_CORRUPT} do_test 3.1 { + list [catch { sqlite3session_foreach -invert db2 $P {} } msg] $msg +} {1 SQLITE_CORRUPT} + +do_test 3.2 { sqlite3changeset_apply_v2 db2 $P {} compare_db db db2 } {} diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index a1ca9a78b1..1a7f003eb6 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -2579,6 +2579,15 @@ int sqlite3changeset_start( ){ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0); } +int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int nChangeset, /* Size of buffer pChangeset in bytes */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert); +} /* ** Streaming version of sqlite3changeset_start(). @@ -2590,6 +2599,15 @@ int sqlite3changeset_start_strm( ){ return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0); } +int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert); +} /* ** If the SessionInput object passed as the only argument is a streaming diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index a9fbed94ef..b9303635e7 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -473,12 +473,38 @@ int sqlite3session_isempty(sqlite3_session *pSession); ** consecutively. There is no chance that the iterator will visit a change ** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
SQLITE_CHANGESETAPPLY_INVERT
+** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* @@ -1133,7 +1159,7 @@ int sqlite3changeset_apply_v2( ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* Combination of SESSION_APPLY_* flags */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* @@ -1552,6 +1578,12 @@ int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), diff --git a/ext/session/test_session.c b/ext/session/test_session.c index 6eba2114c7..016050fdba 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -981,31 +981,56 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach( Tcl_Obj *pCS; Tcl_Obj *pScript; int isCheckNext = 0; + int isInvert = 0; TestStreamInput sStr; memset(&sStr, 0, sizeof(sStr)); - if( objc>1 ){ + while( objc>1 ){ char *zOpt = Tcl_GetString(objv[1]); - isCheckNext = (strcmp(zOpt, "-next")==0); + int nOpt = strlen(zOpt); + if( zOpt[0]!='-' ) break; + if( nOpt<=7 && 0==sqlite3_strnicmp(zOpt, "-invert", nOpt) ){ + isInvert = 1; + }else + if( nOpt<=5 && 0==sqlite3_strnicmp(zOpt, "-next", nOpt) ){ + isCheckNext = 1; + }else{ + break; + } + objv++; + objc--; } - if( objc!=4+isCheckNext ){ - Tcl_WrongNumArgs(interp, 1, objv, "?-next? VARNAME CHANGESET SCRIPT"); + if( objc!=4 ){ + Tcl_WrongNumArgs( + interp, 1, objv, "?-next? ?-invert? VARNAME CHANGESET SCRIPT"); return TCL_ERROR; } - pVarname = objv[1+isCheckNext]; - pCS = objv[2+isCheckNext]; - pScript = objv[3+isCheckNext]; + pVarname = objv[1]; + pCS = objv[2]; + pScript = objv[3]; pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset); sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR); - if( sStr.nStream==0 ){ - rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + if( isInvert ){ + int f = SQLITE_CHANGESETSTART_INVERT; + if( sStr.nStream==0 ){ + rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, f); + }else{ + void *pCtx = (void*)&sStr; + sStr.aData = (unsigned char*)pChangeset; + sStr.nData = nChangeset; + rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f); + } }else{ - sStr.aData = (unsigned char*)pChangeset; - sStr.nData = nChangeset; - rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr); + if( sStr.nStream==0 ){ + rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + }else{ + sStr.aData = (unsigned char*)pChangeset; + sStr.nData = nChangeset; + rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr); + } } if( rc!=SQLITE_OK ){ return test_session_error(interp, rc, 0); diff --git a/manifest b/manifest index 748230c555..2cea732c3d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Take\ssteps\sto\savoid\sa\spotential\sinteger\soverflow\sin\ssessionBufferGrow(). -D 2018-10-18T15:17:18.844 +C Add\sthe\ssqlite3changeset_start_v2()\s-\sa\snew\sversion\sof\s_start()\sthat\saccepts\sa\sflags\sparameter\s-\sand\sa\sstreaming\sequivalent\sto\sthe\ssessions\smodule.\sAlso\sadd\sthe\sSQLITE_CHANGESETSTART_INVERT\sflag,\sused\swith\sstart_v2()\sto\sinvert\sa\schangeset\swhile\siterating\sthrough\sit. +D 2018-10-20T13:48:09.884 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -413,13 +413,13 @@ F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28 F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7 F ext/session/sessionfault2.test 555a8504de03d59b369ef20209585da5aeb2671dedabc4584e9ffe6269689185 -F ext/session/sessioninvert.test d4d8a89990de35e8e56d4d14d14bc7f191aa6f4c2b3731c7ce0fe64b640d29d3 +F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b2953cf48683fb2724169 F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc -F ext/session/sqlite3session.c 7c1875f0c124a1bd18beb95ef0fd7ce288e553c883d2f258b921d4612995a258 -F ext/session/sqlite3session.h 1b0b2bd69ae4cba5fd5fee050ef79707d45a1a3eed41077a92d14556fdcc1f6e -F ext/session/test_session.c 9447482597c7569e49b3db152a300920a4b634d5de86508a94e4338df99b3fda +F ext/session/sqlite3session.c 7b9ae0d7f3f89551c893ad5beafe831df1c097623f6abc983dad7b6dbca726cb +F ext/session/sqlite3session.h 11f229ec3f123da40c31500b01a2f6807185293d9173a5e0aa5be42ad70ab85d +F ext/session/test_session.c 4699405b2afcf6833c11358cdb9da50f8f5d2b7123f44b3e2cef1cfb88c9fa39 F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e629edbe2648 @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d4b6406e7f5ba06ac73ab9fdef57232b2459e0af12420ed946ebed6aef46f0b1 -R e7a7201238f957af096a10fc5c94b75d +P f7affa2e708d1b4c7c47157bcb18e9f79611ca45a93ebc88de6dc96f84a677e7 +R 3605ff60956926e38b591288ff5e2c64 U dan -Z 58cb59871e256ea172e37001653f6319 +Z 32299de6da54da0b9ad3507fdc1f1f73 diff --git a/manifest.uuid b/manifest.uuid index f1588fde60..a6502f7411 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f7affa2e708d1b4c7c47157bcb18e9f79611ca45a93ebc88de6dc96f84a677e7 \ No newline at end of file +cbedcb9aaefdfe00453efbdf0eac6c15e1f53bbe8fff2e7d534a5adf23be04f5 \ No newline at end of file -- 2.47.2