for(i=0; i<nCol; i++){
int eType = *aRec++;
- assert( apOut[i]==0 );
+ assert( !apOut || apOut[i]==0 );
if( eType ){
- apOut[i] = sqlite3ValueNew(0);
- if( !apOut[i] ) return SQLITE_NOMEM;
+ if( apOut ){
+ apOut[i] = sqlite3ValueNew(0);
+ if( !apOut[i] ) return SQLITE_NOMEM;
+ }
if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
int nByte;
int enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
aRec += sessionVarintGet(aRec, &nByte);
- sqlite3ValueSetStr(apOut[i], nByte, aRec, enc, SQLITE_STATIC);
+ if( apOut ){
+ sqlite3ValueSetStr(apOut[i], nByte, aRec, enc, SQLITE_STATIC);
+ }
aRec += nByte;
}
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- sqlite3_int64 v = sessionGetI64(aRec);
- aRec += 8;
- if( eType==SQLITE_INTEGER ){
- sqlite3VdbeMemSetInt64(apOut[i], v);
- }else{
- double d;
- memcpy(&d, &i, 8);
- sqlite3VdbeMemSetDouble(apOut[i], d);
+ if( apOut ){
+ sqlite3_int64 v = sessionGetI64(aRec);
+ if( eType==SQLITE_INTEGER ){
+ sqlite3VdbeMemSetInt64(apOut[i], v);
+ }else{
+ double d;
+ memcpy(&d, &i, 8);
+ sqlite3VdbeMemSetDouble(apOut[i], d);
+ }
}
+ aRec += 8;
}
}
}
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 */
*/
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
}
}
+/*
+** 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
*/
Tcl_CreateObjCommand(
interp, "sqlite3session_foreach", test_sqlite3session_foreach, 0, 0
);
+ Tcl_CreateObjCommand(
+ interp, "sqlite3changeset_invert", test_sqlite3changeset_invert, 0, 0
+ );
return TCL_OK;
}
-C Add\sstart\sof\ssessions\sfeature.
-D 2011-03-08T19:22:51
+C Add\sa\sfunction\sto\sthe\ssession\sextension\sinvert\sa\schangeset.
+D 2011-03-09T11:17:05
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
-F ext/session/sqlite3session.c 88d87c48fde70fb03ae61b462527b82af561dda1
-F ext/session/sqlite3session.h b844cae3db05d2db363fd01050efe568b4e3ebec
-F ext/session/test_session.c 72b1af5ea65c91a14faa6524e284e101b6cee6ec
+F ext/session/sqlite3session.c 82d86bbdfb0e0b731c4e7f9ab9a418340205abe1
+F ext/session/sqlite3session.h d7fe09ca2e12fa6007f7df8344249111c9c78e5f
+F ext/session/test_session.c 7bc88e75a78248dbde3a666f7c25cb228542a60c
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk ae0868e05c76eaa8a0ae3d6927a949b1c8e810d7
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
-F test/session1.test eb069ae24c807089cdb42c06f156e6a4bc467e08
+F test/session1.test f0b04d2840b6a2fc9893096a1e1dadcd4f241993
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
F test/shared2.test 7f6ad2d857d0f4e5d6a0b9a897b5e56a6b6ea18c
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 093d8cd8e2f3a6af5d40cf810e396f4919eb5cef
-R d2860e2d38705a211d32d9cfd0828f6b
+P 269a81a37d7dbdcdec3c2322074916af0fbac91c
+R 06c861473767f41ba98f1b1628042bc2
U dan
-Z 881eaac7f67a95dfac0116385a169f79
+Z 8e42230c84fa0976b233cb2ac7764b8c
-269a81a37d7dbdcdec3c2322074916af0fbac91c
\ No newline at end of file
+75d5dff725dbb66d67d56ad042926f1daae56dbe
\ No newline at end of file
source $testdir/tester.tcl
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 {
CREATE TABLE t1(x, y);
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.2 { S delete } {}
do_test 1.3 { sqlite3session S db main } {S}
S delete
} {}
-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]
-}
-
+#-------------------------------------------------------------------------
+# Simple changeset tests. Also test the sqlite3changeset_invert()
+# function.
+#
do_test 2.1.1 {
execsql { DELETE FROM t1 }
sqlite3session S db main
{INSERT t1 {} {i 2 t Ayutthaya}}
{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 {
sqlite3session S db main
{DELETE t1 {i 2 t Ayutthaya} {}}
{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 {
sqlite3session S db main
{UPDATE t1 {{} {} t Ayutthaya} {{} {} t Surin}}
{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 {
sqlite3session S db main
execsql { INSERT INTO t1 VALUES(100, 'Bangkok') }
execsql { DELETE FROM t1 WHERE x = 100 }
} {}
-
-breakpoint
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