]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add a function to the session extension invert a changeset.
authordan <dan@noemail.net>
Wed, 9 Mar 2011 11:17:05 +0000 (11:17 +0000)
committerdan <dan@noemail.net>
Wed, 9 Mar 2011 11:17:05 +0000 (11:17 +0000)
FossilOrigin-Name: 75d5dff725dbb66d67d56ad042926f1daae56dbe

ext/session/sqlite3session.c
ext/session/sqlite3session.h
ext/session/test_session.c
manifest
manifest.uuid
test/session1.test

index eb024775fd84c24a56f2b921f167b70f70c10e63..0b6a985279378dd4af6d1d4d3efd91adc112341f 100644 (file)
@@ -839,28 +839,34 @@ static int sessionReadRecord(
 
   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;
       }
     }
   }
@@ -990,4 +996,82 @@ int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
   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 */
index a62b8b654e52cbcbc2caae22477651f8e75e1465..fe6ca2075b7036c73def18e79f0884d0e58d2ada 100644 (file)
@@ -121,5 +121,14 @@ int sqlite3changeset_new(
 */
 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
 
index 9c37fdb2855550cde2852769d4151437ca273227..1e8a9eccf6390bc234ca5d527e738ef2cee986c5 100644 (file)
@@ -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
 */
@@ -251,6 +280,9 @@ int TestSession_Init(Tcl_Interp *interp){
   Tcl_CreateObjCommand(
       interp, "sqlite3session_foreach", test_sqlite3session_foreach, 0, 0
   );
+  Tcl_CreateObjCommand(
+      interp, "sqlite3changeset_invert", test_sqlite3changeset_invert, 0, 0
+  );
   return TCL_OK;
 }
 
index 2183d773ea1ae9612909bda02bb421828cd3e571..2042e258c88f0e8539f997a60a773cad22c61015 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -98,9 +98,9 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
 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
@@ -639,7 +639,7 @@ F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
 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
@@ -913,7 +913,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 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
index 6c229ed51ef5fb3d5250a1fd61f6721d0978bbbb..07c3df47780df4f491c5c9b0da62581f32ca3537 100644 (file)
@@ -1 +1 @@
-269a81a37d7dbdcdec3c2322074916af0fbac91c
\ No newline at end of file
+75d5dff725dbb66d67d56ad042926f1daae56dbe
\ No newline at end of file
index 0cb225a2fd8930ccf91b0f403f27595df210ecc1..8a8a51cec64f6c78e1f1cdd67eb043226694e92a 100644 (file)
@@ -15,11 +15,35 @@ set testdir [file dirname $argv0]
 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}
@@ -47,16 +71,10 @@ do_test 1.13 {
   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
@@ -70,7 +88,12 @@ do_changeset_test 2.1.2 S {
   {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
@@ -82,7 +105,12 @@ do_changeset_test 2.2.2 S {
   {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
@@ -102,7 +130,12 @@ do_changeset_test 2.3.2 S {
   {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
@@ -110,9 +143,8 @@ do_test 2.4.1 {
   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