mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Add a function to the session extension invert a changeset.
FossilOrigin-Name: 75d5dff725dbb66d67d56ad042926f1daae56dbe
This commit is contained in:
@@ -839,28 +839,34 @@ static int sessionReadRecord(
|
|||||||
|
|
||||||
for(i=0; i<nCol; i++){
|
for(i=0; i<nCol; i++){
|
||||||
int eType = *aRec++;
|
int eType = *aRec++;
|
||||||
assert( apOut[i]==0 );
|
assert( !apOut || apOut[i]==0 );
|
||||||
if( eType ){
|
if( eType ){
|
||||||
apOut[i] = sqlite3ValueNew(0);
|
if( apOut ){
|
||||||
if( !apOut[i] ) return SQLITE_NOMEM;
|
apOut[i] = sqlite3ValueNew(0);
|
||||||
|
if( !apOut[i] ) return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
|
if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
|
||||||
int nByte;
|
int nByte;
|
||||||
int enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
|
int enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
|
||||||
aRec += sessionVarintGet(aRec, &nByte);
|
aRec += sessionVarintGet(aRec, &nByte);
|
||||||
sqlite3ValueSetStr(apOut[i], nByte, aRec, enc, SQLITE_STATIC);
|
if( apOut ){
|
||||||
|
sqlite3ValueSetStr(apOut[i], nByte, aRec, enc, SQLITE_STATIC);
|
||||||
|
}
|
||||||
aRec += nByte;
|
aRec += nByte;
|
||||||
}
|
}
|
||||||
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
|
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
|
||||||
sqlite3_int64 v = sessionGetI64(aRec);
|
if( apOut ){
|
||||||
aRec += 8;
|
sqlite3_int64 v = sessionGetI64(aRec);
|
||||||
if( eType==SQLITE_INTEGER ){
|
if( eType==SQLITE_INTEGER ){
|
||||||
sqlite3VdbeMemSetInt64(apOut[i], v);
|
sqlite3VdbeMemSetInt64(apOut[i], v);
|
||||||
}else{
|
}else{
|
||||||
double d;
|
double d;
|
||||||
memcpy(&d, &i, 8);
|
memcpy(&d, &i, 8);
|
||||||
sqlite3VdbeMemSetDouble(apOut[i], d);
|
sqlite3VdbeMemSetDouble(apOut[i], d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
aRec += 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -990,4 +996,82 @@ int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Invert a changeset object.
|
||||||
|
*/
|
||||||
|
int sqlite3changeset_invert(
|
||||||
|
int nChangeset, /* Number of bytes in input */
|
||||||
|
void *pChangeset, /* Input changeset */
|
||||||
|
int *pnInverted, /* OUT: Number of bytes in output changeset */
|
||||||
|
void **ppInverted /* OUT: Inverse of pChangeset */
|
||||||
|
){
|
||||||
|
u8 *aOut;
|
||||||
|
u8 *aIn;
|
||||||
|
int i;
|
||||||
|
int nCol = 0;
|
||||||
|
|
||||||
|
/* Zero the output variables in case an error occurs. */
|
||||||
|
*ppInverted = 0;
|
||||||
|
*pnInverted = 0;
|
||||||
|
if( nChangeset==0 ) return SQLITE_OK;
|
||||||
|
|
||||||
|
aOut = (u8 *)sqlite3_malloc(nChangeset);
|
||||||
|
if( !aOut ) return SQLITE_NOMEM;
|
||||||
|
aIn = (u8 *)pChangeset;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while( i<nChangeset ){
|
||||||
|
u8 eType = aIn[i];
|
||||||
|
switch( eType ){
|
||||||
|
case 'T': {
|
||||||
|
int nByte = 1 + sessionVarintGet(&aIn[i+1], &nCol);
|
||||||
|
nByte += 1 + strlen((char *)&aIn[i+nByte]);
|
||||||
|
memcpy(&aOut[i], &aIn[i], nByte);
|
||||||
|
i += nByte;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SQLITE_INSERT:
|
||||||
|
case SQLITE_DELETE: {
|
||||||
|
int nByte;
|
||||||
|
u8 *aEnd = &aIn[i+1];
|
||||||
|
|
||||||
|
sessionReadRecord(&aEnd, nCol, 0);
|
||||||
|
aOut[i] = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
|
||||||
|
nByte = aEnd - &aIn[i+1];
|
||||||
|
memcpy(&aOut[i+1], &aIn[i+1], nByte);
|
||||||
|
i += 1 + nByte;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SQLITE_UPDATE: {
|
||||||
|
int nByte1; /* Size of old.* record in bytes */
|
||||||
|
int nByte2; /* Size of new.* record in bytes */
|
||||||
|
u8 *aEnd = &aIn[i+1];
|
||||||
|
|
||||||
|
sessionReadRecord(&aEnd, nCol, 0);
|
||||||
|
nByte1 = aEnd - &aIn[i+1];
|
||||||
|
sessionReadRecord(&aEnd, nCol, 0);
|
||||||
|
nByte2 = aEnd - &aIn[i+1] - nByte1;
|
||||||
|
|
||||||
|
aOut[i] = SQLITE_UPDATE;
|
||||||
|
memcpy(&aOut[i+1], &aIn[i+1+nByte1], nByte2);
|
||||||
|
memcpy(&aOut[i+1+nByte2], &aIn[i+1], nByte1);
|
||||||
|
|
||||||
|
i += 1 + nByte1 + nByte2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
sqlite3_free(aOut);
|
||||||
|
return SQLITE_CORRUPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pnInverted = nChangeset;
|
||||||
|
*ppInverted = (void *)aOut;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* #ifdef SQLITE_ENABLE_SESSION */
|
#endif /* #ifdef SQLITE_ENABLE_SESSION */
|
||||||
|
@@ -121,5 +121,14 @@ int sqlite3changeset_new(
|
|||||||
*/
|
*/
|
||||||
int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
|
int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Invert a changeset object.
|
||||||
|
*/
|
||||||
|
int sqlite3changeset_invert(
|
||||||
|
int nIn, void *pIn, /* Input changeset */
|
||||||
|
int *pnOut, void **ppOut /* OUT: Inverse of input */
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -168,6 +168,35 @@ static void test_append_value(Tcl_Obj *pList, sqlite3_value *pVal){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** sqlite3changeset_invert CHANGESET
|
||||||
|
*/
|
||||||
|
static int test_sqlite3changeset_invert(
|
||||||
|
void * clientData,
|
||||||
|
Tcl_Interp *interp,
|
||||||
|
int objc,
|
||||||
|
Tcl_Obj *CONST objv[]
|
||||||
|
){
|
||||||
|
int rc; /* Return code from changeset_invert() */
|
||||||
|
void *aChangeset; /* Input changeset */
|
||||||
|
int nChangeSet; /* Size of buffer aChangeset in bytes */
|
||||||
|
void *aOut; /* Output changeset */
|
||||||
|
int nOut; /* Size of buffer aOut in bytes */
|
||||||
|
|
||||||
|
if( objc!=2 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 1, objv, "CHANGESET");
|
||||||
|
}
|
||||||
|
aChangeset = (void *)Tcl_GetByteArrayFromObj(objv[1], &nChangeSet);
|
||||||
|
|
||||||
|
rc = sqlite3changeset_invert(nChangeSet, aChangeset, &nOut, &aOut);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return test_session_error(interp, rc);
|
||||||
|
}
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj((unsigned char *)aOut, nOut));
|
||||||
|
sqlite3_free(aOut);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** sqlite3session_foreach VARNAME CHANGESET SCRIPT
|
** sqlite3session_foreach VARNAME CHANGESET SCRIPT
|
||||||
*/
|
*/
|
||||||
@@ -251,6 +280,9 @@ int TestSession_Init(Tcl_Interp *interp){
|
|||||||
Tcl_CreateObjCommand(
|
Tcl_CreateObjCommand(
|
||||||
interp, "sqlite3session_foreach", test_sqlite3session_foreach, 0, 0
|
interp, "sqlite3session_foreach", test_sqlite3session_foreach, 0, 0
|
||||||
);
|
);
|
||||||
|
Tcl_CreateObjCommand(
|
||||||
|
interp, "sqlite3changeset_invert", test_sqlite3changeset_invert, 0, 0
|
||||||
|
);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
manifest
18
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Add\sstart\sof\ssessions\sfeature.
|
C Add\sa\sfunction\sto\sthe\ssession\sextension\sinvert\sa\schangeset.
|
||||||
D 2011-03-08T19:22:51
|
D 2011-03-09T11:17:05
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -98,9 +98,9 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
|||||||
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
||||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||||
F ext/session/sqlite3session.c 88d87c48fde70fb03ae61b462527b82af561dda1
|
F ext/session/sqlite3session.c 82d86bbdfb0e0b731c4e7f9ab9a418340205abe1
|
||||||
F ext/session/sqlite3session.h b844cae3db05d2db363fd01050efe568b4e3ebec
|
F ext/session/sqlite3session.h d7fe09ca2e12fa6007f7df8344249111c9c78e5f
|
||||||
F ext/session/test_session.c 72b1af5ea65c91a14faa6524e284e101b6cee6ec
|
F ext/session/test_session.c 7bc88e75a78248dbde3a666f7c25cb228542a60c
|
||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||||
F main.mk ae0868e05c76eaa8a0ae3d6927a949b1c8e810d7
|
F main.mk ae0868e05c76eaa8a0ae3d6927a949b1c8e810d7
|
||||||
@@ -639,7 +639,7 @@ F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
|||||||
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
||||||
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
||||||
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
||||||
F test/session1.test eb069ae24c807089cdb42c06f156e6a4bc467e08
|
F test/session1.test f0b04d2840b6a2fc9893096a1e1dadcd4f241993
|
||||||
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
|
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
|
||||||
F test/shared2.test 7f6ad2d857d0f4e5d6a0b9a897b5e56a6b6ea18c
|
F test/shared2.test 7f6ad2d857d0f4e5d6a0b9a897b5e56a6b6ea18c
|
||||||
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
||||||
@@ -913,7 +913,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P 093d8cd8e2f3a6af5d40cf810e396f4919eb5cef
|
P 269a81a37d7dbdcdec3c2322074916af0fbac91c
|
||||||
R d2860e2d38705a211d32d9cfd0828f6b
|
R 06c861473767f41ba98f1b1628042bc2
|
||||||
U dan
|
U dan
|
||||||
Z 881eaac7f67a95dfac0116385a169f79
|
Z 8e42230c84fa0976b233cb2ac7764b8c
|
||||||
|
@@ -1 +1 @@
|
|||||||
269a81a37d7dbdcdec3c2322074916af0fbac91c
|
75d5dff725dbb66d67d56ad042926f1daae56dbe
|
@@ -15,11 +15,35 @@ set testdir [file dirname $argv0]
|
|||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
set ::testprefix session1
|
set ::testprefix session1
|
||||||
|
|
||||||
|
proc do_changeset_test {tn session res} {
|
||||||
|
set r [list]
|
||||||
|
foreach x $res {lappend r $x}
|
||||||
|
uplevel do_test $tn [list [subst -nocommands {
|
||||||
|
set x [list]
|
||||||
|
sqlite3session_foreach c [$session changeset] { lappend x [set c] }
|
||||||
|
set x
|
||||||
|
}]] [list $r]
|
||||||
|
}
|
||||||
|
|
||||||
|
proc do_changeset_invert_test {tn session res} {
|
||||||
|
set r [list]
|
||||||
|
foreach x $res {lappend r $x}
|
||||||
|
uplevel do_test $tn [list [subst -nocommands {
|
||||||
|
set x [list]
|
||||||
|
set changeset [sqlite3changeset_invert [$session changeset]]
|
||||||
|
sqlite3session_foreach c [set changeset] { lappend x [set c] }
|
||||||
|
set x
|
||||||
|
}]] [list $r]
|
||||||
|
}
|
||||||
|
|
||||||
do_execsql_test 1.0 {
|
do_execsql_test 1.0 {
|
||||||
CREATE TABLE t1(x, y);
|
CREATE TABLE t1(x, y);
|
||||||
INSERT INTO t1 VALUES('abc', 'def');
|
INSERT INTO t1 VALUES('abc', 'def');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test creating, attaching tables to and deleting session objects.
|
||||||
|
#
|
||||||
do_test 1.1 { sqlite3session S db main } {S}
|
do_test 1.1 { sqlite3session S db main } {S}
|
||||||
do_test 1.2 { S delete } {}
|
do_test 1.2 { S delete } {}
|
||||||
do_test 1.3 { sqlite3session S db main } {S}
|
do_test 1.3 { sqlite3session S db main } {S}
|
||||||
@@ -47,16 +71,10 @@ do_test 1.13 {
|
|||||||
S delete
|
S delete
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
proc do_changeset_test {tn session res} {
|
#-------------------------------------------------------------------------
|
||||||
set r [list]
|
# Simple changeset tests. Also test the sqlite3changeset_invert()
|
||||||
foreach x $res {lappend r $x}
|
# function.
|
||||||
uplevel do_test $tn [list [subst -nocommands {
|
#
|
||||||
set x [list]
|
|
||||||
sqlite3session_foreach c [$session changeset] { lappend x [set c] }
|
|
||||||
set x
|
|
||||||
}]] [list $r]
|
|
||||||
}
|
|
||||||
|
|
||||||
do_test 2.1.1 {
|
do_test 2.1.1 {
|
||||||
execsql { DELETE FROM t1 }
|
execsql { DELETE FROM t1 }
|
||||||
sqlite3session S db main
|
sqlite3session S db main
|
||||||
@@ -70,7 +88,12 @@ do_changeset_test 2.1.2 S {
|
|||||||
{INSERT t1 {} {i 2 t Ayutthaya}}
|
{INSERT t1 {} {i 2 t Ayutthaya}}
|
||||||
{INSERT t1 {} {i 3 t Thonburi}}
|
{INSERT t1 {} {i 3 t Thonburi}}
|
||||||
}
|
}
|
||||||
do_test 2.1.3 { S delete } {}
|
do_changeset_invert_test 2.1.3 S {
|
||||||
|
{DELETE t1 {i 1 t Sukhothai} {}}
|
||||||
|
{DELETE t1 {i 2 t Ayutthaya} {}}
|
||||||
|
{DELETE t1 {i 3 t Thonburi} {}}
|
||||||
|
}
|
||||||
|
do_test 2.1.4 { S delete } {}
|
||||||
|
|
||||||
do_test 2.2.1 {
|
do_test 2.2.1 {
|
||||||
sqlite3session S db main
|
sqlite3session S db main
|
||||||
@@ -82,7 +105,12 @@ do_changeset_test 2.2.2 S {
|
|||||||
{DELETE t1 {i 2 t Ayutthaya} {}}
|
{DELETE t1 {i 2 t Ayutthaya} {}}
|
||||||
{DELETE t1 {i 3 t Thonburi} {}}
|
{DELETE t1 {i 3 t Thonburi} {}}
|
||||||
}
|
}
|
||||||
do_test 2.2.3 { S delete } {}
|
do_changeset_invert_test 2.2.3 S {
|
||||||
|
{INSERT t1 {} {i 1 t Sukhothai}}
|
||||||
|
{INSERT t1 {} {i 2 t Ayutthaya}}
|
||||||
|
{INSERT t1 {} {i 3 t Thonburi}}
|
||||||
|
}
|
||||||
|
do_test 2.2.4 { S delete } {}
|
||||||
|
|
||||||
do_test 2.3.1 {
|
do_test 2.3.1 {
|
||||||
sqlite3session S db main
|
sqlite3session S db main
|
||||||
@@ -102,7 +130,12 @@ do_changeset_test 2.3.2 S {
|
|||||||
{UPDATE t1 {{} {} t Ayutthaya} {{} {} t Surin}}
|
{UPDATE t1 {{} {} t Ayutthaya} {{} {} t Surin}}
|
||||||
{UPDATE t1 {i 3 t Thonburi} {i 20 t Thapae}}
|
{UPDATE t1 {i 3 t Thonburi} {i 20 t Thapae}}
|
||||||
}
|
}
|
||||||
do_test 2.3.3 { S delete } {}
|
do_changeset_invert_test 2.3.3 S {
|
||||||
|
{UPDATE t1 {i 10 {} {}} {i 1 {} {}}}
|
||||||
|
{UPDATE t1 {{} {} t Surin} {{} {} t Ayutthaya}}
|
||||||
|
{UPDATE t1 {i 20 t Thapae} {i 3 t Thonburi}}
|
||||||
|
}
|
||||||
|
do_test 2.3.4 { S delete } {}
|
||||||
|
|
||||||
do_test 2.4.1 {
|
do_test 2.4.1 {
|
||||||
sqlite3session S db main
|
sqlite3session S db main
|
||||||
@@ -110,9 +143,8 @@ do_test 2.4.1 {
|
|||||||
execsql { INSERT INTO t1 VALUES(100, 'Bangkok') }
|
execsql { INSERT INTO t1 VALUES(100, 'Bangkok') }
|
||||||
execsql { DELETE FROM t1 WHERE x = 100 }
|
execsql { DELETE FROM t1 WHERE x = 100 }
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
breakpoint
|
|
||||||
do_changeset_test 2.4.2 S {}
|
do_changeset_test 2.4.2 S {}
|
||||||
do_test 2.4.3 { S delete } {}
|
do_changeset_invert_test 2.4.3 S {}
|
||||||
|
do_test 2.4.4 { S delete } {}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
Reference in New Issue
Block a user