From: dan Date: Tue, 13 Jan 2026 19:59:47 +0000 (+0000) Subject: Allow the APIs on this branch to be used to create patchsets as well as changesets. X-Git-Tag: major-release~22^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c289cf57a72cc317963a0d590c54cf02cd839aa6;p=thirdparty%2Fsqlite.git Allow the APIs on this branch to be used to create patchsets as well as changesets. FossilOrigin-Name: 8699fe5b24c8aeb5e552aa7f4995f2b50dd33d1febd23ec1c07c8fc72497da72 --- diff --git a/ext/session/sessionchange2.test b/ext/session/sessionchange2.test index 4a211d8c93..6a508ef221 100644 --- a/ext/session/sessionchange2.test +++ b/ext/session/sessionchange2.test @@ -186,7 +186,6 @@ foreach {tn script error} { grp delete } - do_test 3.2.1 { sqlite3changegroup grp grp schema db main @@ -201,5 +200,133 @@ do_test 3.2.2 { grp delete +#------------------------------------------------------------------------- +reset_db +do_execsql_test 3.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + CREATE TABLE t2(a, b); +} + +proc do_changegroup_script_test {tn script changeset patchset} { + +breakpoint + sqlite3changegroup grp + grp schema db main + eval $script + do_test $tn.1 { + changeset_to_list [grp output] + } [list {*}$changeset] + grp delete + + sqlite3changegroup grp + grp config patchset 1 + grp schema db main + eval $script + do_test $tn.2 { + changeset_to_list [grp output] + } [list {*}$patchset] + grp delete + +} + +proc do_changegroup_patchset_test {tn script patchset} { + + sqlite3changegroup grp + grp config patchset 1 + grp schema db main + eval $script + do_test $tn { + changeset_to_list [grp output] + } [list {*}$patchset] + grp delete + +} + +do_changegroup_script_test 3.1 { + grp change_begin UPDATE t1 0 + grp change_int64 old 0 123 + grp change_int64 old 1 456 + grp change_int64 new 1 789 + grp change_finish false + + grp change_begin INSERT t1 0 + grp change_int64 new 0 124 + grp change_text new 1 hello_world + grp change_finish false + + grp change_begin DELETE t1 0 + grp change_int64 old 0 125 + grp change_double old 1 45.67 + grp change_finish false +} { + {DELETE t1 0 X. {i 125 f 45.67} {}} + {INSERT t1 0 X. {} {i 124 t hello_world}} + {UPDATE t1 0 X. {i 123 i 456} {{} {} i 789}} +} { + {DELETE t1 0 X. {i 125 {} {}} {}} + {INSERT t1 0 X. {} {i 124 t hello_world}} + {UPDATE t1 0 X. {i 123 {} {}} {{} {} i 789}} +} + +do_changegroup_script_test 3.1.2 { + grp change_begin INSERT t1 0 + grp change_int64 new 0 124 + grp change_text new 1 hello_world + grp change_finish false +} { + {INSERT t1 0 X. {} {i 124 t hello_world}} +} { + {INSERT t1 0 X. {} {i 124 t hello_world}} +} + +do_changegroup_patchset_test 3.2 { + grp change_begin UPDATE t1 0 + grp change_int64 old 0 123 + grp change_int64 new 1 789 + grp change_finish false + + grp change_begin DELETE t1 1 + grp change_int64 old 0 122 + grp change_finish false +} { + {DELETE t1 1 X. {i 122 {} {}} {}} + {UPDATE t1 0 X. {i 123 {} {}} {{} {} i 789}} +} + +do_changegroup_patchset_test 3.3 { + grp change_begin DELETE t1 0 + grp change_int64 old 0 123 + grp change_finish false +} { + {DELETE t1 0 X. {i 123 {} {}} {}} +} + +do_changegroup_script_test 3.4 { + grp change_begin INSERT t1 0 + grp change_int64 new 0 124 + grp change_text new 1 hello_world + grp change_finish false + + grp change_begin DELETE t1 0 + grp change_int64 old 0 124 + grp change_text old 1 hello_world + grp change_finish false + + grp change_begin INSERT t1 0 + grp change_int64 new 0 1000 + grp change_blob new 1 abcd + grp change_finish false + + grp change_begin UPDATE t1 0 + grp change_int64 old 0 1000 + grp change_blob old 1 abcd + grp change_blob new 1 bcda + grp change_finish false +} { + {INSERT t1 0 X. {} {i 1000 b bcda}} +} { + {INSERT t1 0 X. {} {i 1000 b bcda}} +} + finish_test diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 278810e12c..feabdf5c12 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -6271,6 +6271,33 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp){ return rc; } +/* +** Configure a changegroup object. +*/ +int sqlite3changegroup_config( + sqlite3_changegroup *pGrp, + int op, + void *pArg +){ + int rc = SQLITE_OK; + + switch( op ){ + case SQLITE_CHANGEGROUP_CONFIG_PATCHSET: { + int arg = *(int*)pArg; + if( pGrp->pList==0 && arg>=0 ){ + pGrp->bPatch = (arg>0); + } + *(int*)pArg = pGrp->bPatch; + break; + } + default: + rc = SQLITE_MISUSE; + break; + } + + return rc; +} + /* ** Provide a database schema to the changegroup object. */ @@ -6879,6 +6906,10 @@ int sqlite3changegroup_change_begin( return rc; } +/* +** This function does processing common to the _change_int64(), _change_text() +** and other similar APIs. +*/ static int checkChangeParams( sqlite3_changegroup *pGrp, int bNew, @@ -6992,6 +7023,7 @@ int sqlite3changegroup_change_text( pBuf->aBuf[0] = SQLITE_TEXT; pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nText)); memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nText); + pBuf->nBuf += nText; return SQLITE_OK; } @@ -7017,6 +7049,7 @@ int sqlite3changegroup_change_blob( pBuf->aBuf[0] = SQLITE_BLOB; pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nVal)); memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nVal); + pBuf->nBuf += nVal; return SQLITE_OK; } @@ -7033,7 +7066,6 @@ int sqlite3changegroup_change_finish( if( bDiscard==0 ){ int nBuf = pGrp->cd.pTab->nCol; - int nRec = 0; u8 eUndef = SQLITE_NULL; if( pGrp->cd.eOp==SQLITE_UPDATE ){ for(ii=0; ii0)!=(aBuf[ii+nBuf].nBuf>0) ){ + }else + if( pGrp->bPatch==0 && (aBuf[ii].nBuf>0)!=(aBuf[ii+nBuf].nBuf>0) ){ *pzErr = sqlite3_mprintf( "invalid change: column %d " "- old.* value is %sdefined but new.* is %sdefined", @@ -7063,17 +7096,20 @@ int sqlite3changegroup_change_finish( } } eUndef = 0x00; - nBuf = nBuf * 2; + if( pGrp->bPatch==0 ) nBuf = nBuf * 2; }else{ for(ii=0; iicd.pTab->abPK[ii]; + if( (pGrp->cd.eOp==SQLITE_INSERT || pGrp->bPatch==0 || isPK) + && aBuf[ii].nBuf==0 + ){ *pzErr = sqlite3_mprintf( "invalid change: column %d is undefined", ii ); rc = SQLITE_ERROR; break; } - if( aBuf[ii].nBuf==1 && pGrp->cd.pTab->abPK[ii] ){ + if( aBuf[ii].nBuf==1 && isPK ){ *pzErr = sqlite3_mprintf( "invalid change: null value in PK" ); @@ -7083,13 +7119,19 @@ int sqlite3changegroup_change_finish( } } + pGrp->cd.record.nBuf = 0; for(ii=0; iicd.aBuf[ii]; - nRec += (pBuf->nBuf ? pBuf->nBuf : 1); - } - if( 0==sessionBufferGrow(&pGrp->cd.record, nRec, &rc) ){ - for(ii=0; iicd.aBuf[ii]; + SessionBuffer *p = &pGrp->cd.aBuf[ii]; + if( pGrp->bPatch ){ + if( pGrp->cd.pTab->abPK[ii]==0 ){ + if( pGrp->cd.eOp==SQLITE_UPDATE ){ + p += pGrp->cd.pTab->nCol; + }else if( pGrp->cd.eOp==SQLITE_DELETE ){ + continue; + } + } + } + if( 0==sessionBufferGrow(&pGrp->cd.record, p->nBuf?p->nBuf:1, &rc) ){ if( p->nBuf ){ memcpy(&pGrp->cd.record.aBuf[pGrp->cd.record.nBuf],p->aBuf,p->nBuf); pGrp->cd.record.nBuf += p->nBuf; @@ -7097,6 +7139,8 @@ int sqlite3changegroup_change_finish( pGrp->cd.record.aBuf[pGrp->cd.record.nBuf++] = eUndef; } } + } + if( rc==SQLITE_OK ){ rc = sessionOneChangeToHash( pGrp, pGrp->cd.pTab, @@ -7110,6 +7154,7 @@ int sqlite3changegroup_change_finish( } } + /* Reset all aBuf[] entries to "undefined". */ { int nZero = pGrp->cd.pTab->nCol; if( pGrp->cd.eOp==SQLITE_UPDATE ) nZero += nZero; diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index 1c3af0e0b7..36dfc504e9 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -1853,6 +1853,43 @@ int sqlite3session_config(int op, void *pArg); */ #define SQLITE_SESSION_CONFIG_STRMSIZE 1 +/* +** CAPI3REF: Configure a changegroup object +** +** Configure the changegroup object passes as the first argument. +** At present the only valid value for the second parameter is +** [SQLITE_CHANGEGROUP_CONFIG_PATCHSET]. +*/ +int sqlite3changegroup_config(sqlite3_changegroup*, int, void *pArg); + +/* +** CAPI3REF: Options for sqlite3changegroup_config(). +** +** The following values may passed as the the 2nd parameter to +** sqlite3session_object_config(). +** +**
SQLITE_CHANGEGROUP_CONFIG_PATCHSET
+** A changegroup object generates either a changeset or patchset. Usually, +** which is determined by whether the first call to sqlite3changegroup_add() +** is passed a changeset or a patchset. Or, if the first changes are added +** to the changegroup object using the sqlite3changegroup_change_xxx() +** APIs, then this option may be used to configure whether the changegroup +** object generates a changeset or patchset. +** +** When this option is invoked, parameter pArg must point to a value of +** type int. If the changegroup currently contains zero changes, and the +** value of the int variable is zero or greater than zero, then the +** changegroup is configured to generate a changeset or patchset, +** respectively. It is not an error if the changegroup is not configured +** because it has already started accumuting changes, just a no-op. +** +** Before returning, the int variable is set to 0 if the changegroup is +** configured to generate a changeset, or 1 if it is configured to generate +** a patchset. +*/ +#define SQLITE_CHANGEGROUP_CONFIG_PATCHSET 1 + + /* ** CAPI3REF: Begin adding a change to a changegroup ** @@ -1982,7 +2019,8 @@ int sqlite3changegroup_change_blob( ** returned. ** ** If paramter bDiscard is zero, then an attempt is made to add the current -** change to the changegroup. This requires that: +** change to the changegroup. Assuming the changegroup is configured to +** produce a changeset (not a patchset), this requires that: ** ** * If the change is an INSERT or DELETE, then a value must be specified ** for all columns of the new.* or old.* record, respectively. @@ -2005,6 +2043,12 @@ int sqlite3changegroup_change_blob( ** current change is combined with the existing change as for ** sqlite3changegroup_add(). ** +** For a patchset, all of the above rules apply except that it doesn't matter +** whether or not values are provided for the non-PK old.* record columns +** for an UPDATE or DELETE change. This means that code used to produce +** a changeset using the sqlite3changegroup_change_xxx() APIs may also +** be used to produce patchsets. +** ** If the call is successful, SQLITE_OK is returned. Otherwise, if an error ** occurs, an SQLite error code is returned. If an error is returned and ** parameter pzErr is not NULL, then (*pzErr) may be set to point to a buffer diff --git a/ext/session/test_session.c b/ext/session/test_session.c index d868db3758..03929284db 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -1570,6 +1570,8 @@ static int SQLITE_TCLAPI test_changegroup_cmd( { "change_text", 3, "[new|old] ICOL VALUE" }, /* 9 */ { "change_blob", 3, "[new|old] ICOL VALUE" }, /* 10 */ { "change_finish", 1, "BDISCARD" }, /* 11 */ + + { "config", 2, "OPTION INTVAL" }, /* 12 */ { 0, 0, 0 } }; int rc = TCL_OK; @@ -1778,6 +1780,35 @@ static int SQLITE_TCLAPI test_changegroup_cmd( break; } + case 12: { /* config */ + struct OptionName { + const char *zOpt; + int op; + } aOp[] = { + { "patchset", SQLITE_CHANGEGROUP_CONFIG_PATCHSET }, + { 0, 0 } + }; + int iIdx = 0; + int iArg = 0; + rc = Tcl_GetIndexFromObjStruct( + interp, objv[2], aOp, sizeof(aOp[0]), "option", 0, &iIdx + ); + if( rc==TCL_OK + && (rc = Tcl_GetIntFromObj(interp, objv[3], &iArg))==TCL_OK + ){ + int op = aOp[iIdx].op; + void *pArg = (void*)&iArg; + + rc = sqlite3changegroup_config(p->pGrp, op, pArg); + if( rc!=SQLITE_OK ){ + rc = test_session_error(interp, rc, 0); + }else{ + Tcl_SetObjResult(interp, Tcl_NewIntObj(iArg)); + } + } + break; + } + default: { /* delete */ assert( iSub==3 ); Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); diff --git a/manifest b/manifest index e8378621b9..c4852e1c4a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sAPI\sto\sthe\ssessions\smodule\sto\sadd\schanges\sone\sat\sa\stime\sto\san\ssqlite3_changegroup\sobject. -D 2026-01-12T16:39:27.740 +C Allow\sthe\sAPIs\son\sthis\sbranch\sto\sbe\sused\sto\screate\spatchsets\sas\swell\sas\schangesets. +D 2026-01-13T19:59:47.818 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -562,7 +562,7 @@ F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b8541 F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf F ext/session/sessionblob.test 87faf667870b72f08e91969abd9f52a383ab7b514506ee194d64a39d8faff00a F ext/session/sessionchange.test 6618cb1c1338a4b6df173b6ac42d09623fb71269962abf23ebb7617fe9f45a50 -F ext/session/sessionchange2.test 9f8eef9a673e9cdc0c0d8eee0fe4f27295ae6e491a449542a44ba23e763c4258 +F ext/session/sessionchange2.test 601d8151b7faeef300355b9eaea65c26d823746e83ccaa8d674198a12d6641dd F ext/session/sessionconflict.test 19e4a53795c4c930bfec49e809311e09b2a9e202d9446e56d7a8b139046a0c07 x F ext/session/sessiondiff.test e89f7aedcdd89e5ebac3a455224eb553a171e9586fc3e1e6a7b3388d2648ba8d F ext/session/sessionfault.test c2b43d01213b389a3f518e90775fca2120812ba51e50444c4066962263e45c11 @@ -578,9 +578,9 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795 F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc -F ext/session/sqlite3session.c f13ff9db3d1a492820fe9845739561a9336f066a606adf14ed679a7a6450bfa8 -F ext/session/sqlite3session.h d45d8dcc32bd0454b65fbb08d2a86f6d68d918f3c9dbf01dbe8540ee81954003 -F ext/session/test_session.c 86f5dae26de28f7091fc4913b4b8880ce764f24fb8d76eafba8c0a33125b2462 +F ext/session/sqlite3session.c 16c36e63d41e2d0f6a8d4593618f221185064ab01d49b8514cb5e710642bdb67 +F ext/session/sqlite3session.h cb6d25b573751afd9668f9ae8f1c7819df30916f43cc4c06b57749a6c2ce3e10 +F ext/session/test_session.c c4164b818cbdfaa3ebbcde31a9a620a63478478154715276ce09bced8918429b F ext/wasm/GNUmakefile c3d007dd181527283d8674c812cc60518353f1f69c9a9d3008f10f53cea4a3c1 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259 @@ -2192,11 +2192,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b57a8215f4259a0aae188b7ee5060f8ff48919303179aae80b58b43ed3b991f5 -R 3bc6861aec8f49b745d80fe907b58d8c -T *branch * changegroup-change-api -T *sym-changegroup-change-api * -T -sym-trunk * +P 27150a8c22dc5331efa9e97637eae3741682bc14ae993f0b7672ccc63c37f1f9 +R f6f93392cfb2ac7fdf4dfeb41e3a044d U dan -Z a079c2735ef0be18051333989922e875 +Z b3689361f6f700b24a921b70fab2026e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4f43bd9551..4b3655ff91 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -27150a8c22dc5331efa9e97637eae3741682bc14ae993f0b7672ccc63c37f1f9 +8699fe5b24c8aeb5e552aa7f4995f2b50dd33d1febd23ec1c07c8fc72497da72