]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Changes to the sesssions module ensure that tables appear within changesets and patch...
authordan <dan@noemail.net>
Thu, 1 Oct 2015 16:35:57 +0000 (16:35 +0000)
committerdan <dan@noemail.net>
Thu, 1 Oct 2015 16:35:57 +0000 (16:35 +0000)
FossilOrigin-Name: 7695890230dc1e0c6db9b7aa509db2039c7f7239

ext/session/session1.test
ext/session/session2.test
ext/session/sessionB.test
ext/session/sessionF.test [new file with mode: 0644]
ext/session/session_common.tcl
ext/session/sqlite3session.c
ext/session/sqlite3session.h
manifest
manifest.uuid

index fc74a1e84e15afb30317a75fd11e7d651cd7e0f8..7aebe8c000344769d7a5df483b980e54a98d225e 100644 (file)
@@ -20,17 +20,6 @@ ifcapable !session {finish_test; return}
 
 set testprefix session1
 
-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 PRIMARY KEY, y);
   INSERT INTO t1 VALUES('abc', 'def');
index 0035e39dbf60b36aa1ce92e4bffd81b37757f1cd..cd8c2869e79b507d132f63e9c06b7ed90b6c1985 100644 (file)
@@ -298,8 +298,8 @@ foreach {tn sql changeset} {
     DELETE FROM t1 WHERE 1;
     UPDATE t2 SET x = 34;
   } { 
-    {UPDATE t2 0 .X {i 36 i 37} {i 34 {} {}}}
     {DELETE t1 0 X {i 35} {}}
+    {UPDATE t2 0 .X {i 36 i 37} {i 34 {} {}}}
   }
 } {
   do_iterator_test 5.$tn * $sql $changeset
@@ -413,8 +413,8 @@ do_iterator_test 6.1.8 * {
   SELECT indirect(0);
   UPDATE t4 SET a = 'two' WHERE b = 1;
 } {
-  {INSERT t4 0 .X {} {t two i 1}} 
   {INSERT t3 1 .X {} {t two i 1}}
+  {INSERT t4 0 .X {} {t two i 1}} 
 }
 
 sqlite3session S db main
index f1af5d213c3691be6295937bd2c06987cc5b9945..eae41f76ad17913e71f202cdcd001e5e72d40274 100644 (file)
@@ -31,16 +31,6 @@ set testprefix sessionB
 # 3.*: Test that sqlite3changeset_invert() works with patchset blobs. 
 #      Correct behaviour is to return SQLITE_CORRUPT.
 
-proc do_patchset_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 patchset] { lappend x [set c] }
-    set x
-  }]] [list $r]
-}
-
 proc do_sql2patchset_test {tn sql res} {
   sqlite3session S db main
   S attach *
diff --git a/ext/session/sessionF.test b/ext/session/sessionF.test
new file mode 100644 (file)
index 0000000..ba57bf8
--- /dev/null
@@ -0,0 +1,295 @@
+# 2015 June 02
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# This file implements regression tests for the sessions module.
+# Specifically, it tests that tables appear in the correct order
+# within changesets and patchsets.
+#
+
+
+
+if {![info exists testdir]} {
+  set testdir [file join [file dirname [info script]] .. .. test]
+} 
+source [file join [file dirname [info script]] session_common.tcl]
+source $testdir/tester.tcl
+ifcapable !session {finish_test; return}
+set testprefix sessionF
+
+#
+# Test plan:
+#
+#    1.*: Test that sqlite3session_changeset() and sqlite3session_patchset()
+#         output tables in the right order.
+#
+#    2.*: Test that sqlite3session_invert() does not modify the order of
+#         tables within a changeset.
+#
+#    3.*: Test that sqlite3session_concat outputs tables in the right order.
+#
+
+# Create a db schema to use.
+#
+do_execsql_test 1.0 {
+  CREATE TABLE t3(e PRIMARY KEY, f);
+  CREATE TABLE t1(a PRIMARY KEY, b);
+  CREATE TABLE t2(c PRIMARY KEY, d);
+}
+
+#-----------------------------------------------------------------------
+# 1.* - changeset() and patchset().
+#
+
+foreach {tn setup result} {
+  1 {
+    S attach *
+  } {
+    {INSERT t2 0 X. {} {i 2 t two}} 
+    {INSERT t1 0 X. {} {i 1 t one}} 
+    {INSERT t3 0 X. {} {i 3 t three}}
+  }
+
+  2 {
+    S attach t1
+    S attach *
+  } {
+    {INSERT t1 0 X. {} {i 1 t one}} 
+    {INSERT t2 0 X. {} {i 2 t two}} 
+    {INSERT t3 0 X. {} {i 3 t three}}
+  }
+
+  3 {
+    S attach t3
+    S attach t2
+    S attach t1
+  } {
+    {INSERT t3 0 X. {} {i 3 t three}}
+    {INSERT t2 0 X. {} {i 2 t two}} 
+    {INSERT t1 0 X. {} {i 1 t one}} 
+  }
+} {
+  execsql {
+    DELETE FROM t1;
+    DELETE FROM t2;
+    DELETE FROM t3;
+  }
+  sqlite3session S db main
+  eval $setup
+
+  do_execsql_test 1.$tn.1 {
+    INSERT INTO t2 VALUES(2, 'two');
+    INSERT INTO t1 VALUES(1, 'one');
+    INSERT INTO t3 VALUES(3, 'three');
+  }
+
+  do_changeset_test 1.1.$tn.2 S $result
+  do_patchset_test  1.1.$tn.3 S $result
+
+  S delete
+}
+
+foreach {tn setup result} {
+  1 {
+    S attach *
+  } {
+    {INSERT t2 0 X. {} {i 4 t four}} 
+    {INSERT t2 0 X. {} {i 5 t five}}
+    {INSERT t1 0 X. {} {i 1 t one}} 
+    {INSERT t3 0 X. {} {i 6 t six}}
+  }
+
+  2 {
+    S attach t1
+    S attach *
+  } {
+    {INSERT t1 0 X. {} {i 1 t one}} 
+    {INSERT t2 0 X. {} {i 4 t four}} 
+    {INSERT t2 0 X. {} {i 5 t five}}
+    {INSERT t3 0 X. {} {i 6 t six}}
+  }
+
+  3 {
+    S attach t3
+    S attach t2
+    S attach t1
+  } {
+    {INSERT t3 0 X. {} {i 6 t six}}
+    {INSERT t2 0 X. {} {i 4 t four}} 
+    {INSERT t2 0 X. {} {i 5 t five}}
+    {INSERT t1 0 X. {} {i 1 t one}} 
+  }
+} {
+  execsql {
+    DELETE FROM t1;
+    DELETE FROM t2;
+    DELETE FROM t3;
+  }
+  sqlite3session S db main
+  eval $setup
+
+  do_execsql_test 1.$tn.1 {
+    INSERT INTO t2 VALUES(2, 'two');
+    INSERT INTO t1 VALUES(1, 'one');
+    DELETE FROM t2;
+    INSERT INTO t2 VALUES(4, 'four');
+    INSERT INTO t2 VALUES(5, 'five');
+    INSERT INTO t3 VALUES(6, 'six');
+  }
+
+  do_changeset_test 1.2.$tn.2 S $result
+  do_patchset_test 1.2.$tn.2 S $result
+
+  S delete
+}
+
+#-------------------------------------------------------------------------
+# 2.* - invert()
+#
+
+foreach {tn setup result} {
+  1 {
+    S attach *
+  } {
+    {DELETE t2 0 X. {i 4 t four} {}} 
+    {DELETE t2 0 X. {i 5 t five} {}} 
+    {DELETE t1 0 X. {i 1 t one} {}}
+    {DELETE t3 0 X. {i 6 t six} {}} 
+  }
+
+  2 {
+    S attach t1
+    S attach *
+  } {
+    {DELETE t1 0 X. {i 1 t one} {}}
+    {DELETE t2 0 X. {i 4 t four} {}} 
+    {DELETE t2 0 X. {i 5 t five} {}} 
+    {DELETE t3 0 X. {i 6 t six} {}} 
+  }
+
+  3 {
+    S attach t3
+    S attach t2
+    S attach t1
+  } {
+    {DELETE t3 0 X. {i 6 t six} {}} 
+    {DELETE t2 0 X. {i 4 t four} {}} 
+    {DELETE t2 0 X. {i 5 t five} {}} 
+    {DELETE t1 0 X. {i 1 t one} {}}
+  }
+} {
+  execsql {
+    DELETE FROM t1;
+    DELETE FROM t2;
+    DELETE FROM t3;
+  }
+  sqlite3session S db main
+  eval $setup
+
+  do_execsql_test 1.$tn.1 {
+    INSERT INTO t2 VALUES(2, 'two');
+    INSERT INTO t1 VALUES(1, 'one');
+    DELETE FROM t2;
+    INSERT INTO t2 VALUES(4, 'four');
+    INSERT INTO t2 VALUES(5, 'five');
+    INSERT INTO t3 VALUES(6, 'six');
+  }
+
+  do_changeset_invert_test 2.$tn.2 S $result
+
+  S delete
+}
+
+#-------------------------------------------------------------------------
+# 3.* - concat()
+#
+foreach {tn setup1 sql1 setup2 sql2 result} {
+  1 {
+    S attach *
+  } {
+    INSERT INTO t1 VALUES(1, 'one');
+    INSERT INTO t2 VALUES(2, 'two');
+  } {
+    S attach t2
+    S attach t1
+  } {
+    INSERT INTO t1 VALUES(3, 'three');
+    INSERT INTO t2 VALUES(4, 'four');
+  } {
+    {INSERT t1 0 X. {} {i 1 t one}} 
+    {INSERT t1 0 X. {} {i 3 t three}} 
+    {INSERT t2 0 X. {} {i 2 t two}}
+    {INSERT t2 0 X. {} {i 4 t four}}
+  }
+
+  1 {
+    S attach t2
+    S attach t1
+  } {
+    INSERT INTO t1 VALUES(1, 'one');
+    INSERT INTO t2 VALUES(2, 'two');
+  } {
+    S attach *
+  } {
+    INSERT INTO t1 VALUES(3, 'three');
+    INSERT INTO t2 VALUES(4, 'four');
+  } {
+    {INSERT t2 0 X. {} {i 2 t two}}
+    {INSERT t2 0 X. {} {i 4 t four}}
+    {INSERT t1 0 X. {} {i 1 t one}} 
+    {INSERT t1 0 X. {} {i 3 t three}} 
+  }
+
+  1 {
+    S attach *
+  } {
+    INSERT INTO t2 VALUES(2, 'two');
+  } {
+    S attach *
+  } {
+    INSERT INTO t1 VALUES(3, 'three');
+    INSERT INTO t2 VALUES(4, 'four');
+    INSERT INTO t3 VALUES(5, 'five');
+  } {
+    {INSERT t2 0 X. {} {i 2 t two}}
+    {INSERT t2 0 X. {} {i 4 t four}}
+    {INSERT t1 0 X. {} {i 3 t three}} 
+    {INSERT t3 0 X. {} {i 5 t five}} 
+  }
+
+} {
+  execsql {
+    DELETE FROM t1;
+    DELETE FROM t2;
+    DELETE FROM t3;
+  }
+  sqlite3session S db main
+  eval $setup1
+  execsql $sql1
+  set c1 [S changeset]
+  S delete
+
+  sqlite3session S db main
+  eval $setup2
+  execsql $sql2
+  set c2 [S changeset]
+  S delete
+
+  set res [list]
+  sqlite3session_foreach x [sqlite3changeset_concat $c1 $c2] {
+    lappend res $x
+  }
+
+  do_test 3.$tn { set res } [list {*}$result]
+}
+
+
+finish_test
+
index f27ad11dc05c82b61d77c91211a5bf05d9474e2e..38eebec0a01edd027e3e1f80726bd74c848ff6b2 100644 (file)
@@ -9,6 +9,28 @@ proc do_changeset_test {tn session res} {
   }]] [list $r]
 }
 
+proc do_patchset_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 patchset] { 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]
+}
+
 
 proc do_conflict_test {tn args} {
   proc xConflict {args} { 
index 0937c9bb324c9f8da0403a1cac498a9513a9176f..546a22a072346fd05ffbc44856c88715b2164a29 100644 (file)
@@ -1188,7 +1188,7 @@ static int sessionFindTable(
     ){
       rc = sqlite3session_attach(pSession, zName);
       if( rc==SQLITE_OK ){
-        pRet = pSession->pTable;
+        for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
         assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
       }
     }
@@ -1675,12 +1675,17 @@ int sqlite3session_attach(
       if( !pTab ){
         rc = SQLITE_NOMEM;
       }else{
-        /* Populate the new SessionTable object and link it into the list. */
+        /* Populate the new SessionTable object and link it into the list.
+        ** The new object must be linked onto the end of the list, not 
+        ** simply added to the start of it in order to ensure that tables
+        ** appear in the correct order when a changeset or patchset is
+        ** eventually generated. */
+        SessionTable **ppTab;
         memset(pTab, 0, sizeof(SessionTable));
         pTab->zName = (char *)&pTab[1];
         memcpy(pTab->zName, zName, nName+1);
-        pTab->pNext = pSession->pTable;
-        pSession->pTable = pTab;
+        for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext);
+        *ppTab = pTab;
       }
     }
   }
@@ -4220,19 +4225,26 @@ static int sessionChangesetToHash(
         if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
       }
       if( !pTab ){
+        SessionTable **ppTab;
+
         pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
         if( !pTab ){
           rc = SQLITE_NOMEM;
           break;
         }
         memset(pTab, 0, sizeof(SessionTable));
-        pTab->pNext = pGrp->pList;
         pTab->nCol = nCol;
         pTab->abPK = (u8*)&pTab[1];
         memcpy(pTab->abPK, abPK, nCol);
         pTab->zName = (char*)&pTab->abPK[nCol];
         memcpy(pTab->zName, zNew, nNew+1);
-        pGrp->pList = pTab;
+
+        /* The new object must be linked on to the end of the list, not
+        ** simply added to the start of it. This is to ensure that the
+        ** tables within the output of sqlite3changegroup_output() are in 
+        ** the right order.  */
+        for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
+        *ppTab = pTab;
       }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
         rc = SQLITE_SCHEMA;
         break;
index f2df143e1a1cc2490e6ecd979d17e10376740f24..71f02159cf5f6de6ac5fc7c89055a834ad409cfd 100644 (file)
@@ -206,6 +206,14 @@ void sqlite3session_table_filter(
 ** a database with a compatible schema using the [sqlite3changeset_apply()]
 ** API.
 **
+** Within a changeset generated by this function, all changes related to a
+** single table are grouped together. In other words, when iterating through
+** a changeset or when applying a changeset to a database, all changes related
+** to a single table are processed before moving on to the next table. Tables
+** are sorted in the same order in which they were attached (or auto-attached)
+** to the sqlite3_session object. The order in which the changes related to
+** a single table are stored is undefined.
+**
 ** Following a successful call to this function, it is the responsibility of
 ** the caller to eventually free the buffer that *ppChangeset points to using
 ** [sqlite3_free()].
@@ -358,6 +366,11 @@ int sqlite3session_diff(
 ** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
 ** is passed to the sqlite3changeset_apply() API. Other conflict types work
 ** in the same way as for changesets.
+**
+** Changes within a patchset are ordered in the same way as for changesets
+** generated by the sqlite3session_changeset() function (i.e. all changes for
+** a single table are grouped together, tables appear in the order in which
+** they were attached to the session object).
 */
 int sqlite3session_patchset(
   sqlite3_session *pSession,      /* Session object */
@@ -659,6 +672,9 @@ int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
 **   <li> For each UPDATE change, the old.* and new.* values are exchanged.
 ** </ul>
 **
+** This function does not change the order in which changes appear within
+** the changeset. It merely reverses the sense of each individual change.
+**
 ** If successful, a pointer to a buffer containing the inverted changeset
 ** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
 ** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
@@ -833,6 +849,15 @@ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
 ** were themselves changesets, the output is a changeset. Or, if the
 ** inputs were patchsets, the output is also a patchset.
 **
+** As with the output of the sqlite3session_changeset() and
+** sqlite3session_patchset() functions, all changes related to a single
+** table are grouped together in the output of this function. Tables appear
+** in the same order as for the very first changeset added to the changegroup.
+** If the second or subsequent changesets added to the changegroup contain
+** changes for tables that do not appear in the first changeset, they are
+** appended onto the end of the output changeset, again in the order in
+** which they are first encountered.
+**
 ** If an error occurs, an SQLite error code is returned and the output
 ** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
 ** is returned and the output variables are set to the size of and a 
index bcf5b0db01d06ab063ccf5320c0616207d878c55..794f8813033b5f1d058df0855bc2cd5f0b5c3127 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\srecent\senhancements\sfrom\strunk,\sand\sespecially\sthe\sfix\sfor\nticket\s[1b266395d6bc10].
-D 2015-09-30T14:50:39.955
+C Changes\sto\sthe\ssesssions\smodule\sensure\sthat\stables\sappear\swithin\schangesets\sand\spatchsets\sin\sthe\ssame\sorder\sthat\sthey\swere\sattached\sto\sthe\ssessions\sobject.
+D 2015-10-01T16:35:57.175
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in fdcfdc361f0a3723da9b48b967f259f7aaff3ad5
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -256,8 +256,8 @@ F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a
-F ext/session/session1.test d4f53b9b5add7eeb358e535d6e18552142092429
-F ext/session/session2.test a95a2d270b32638c1acba7cb9c81856712d469ac
+F ext/session/session1.test 5dab50ce55c859e829bae24f0787013f51775fc5
+F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
 F ext/session/session3.test a7a9ce59b8d1e49e2cc23d81421ac485be0eea01
 F ext/session/session4.test a6ed685da7a5293c5d6f99855bcf41dbc352ca84
 F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169
@@ -265,14 +265,15 @@ F ext/session/session6.test 443789bc2fca12e4f7075cf692c60b8a2bea1a26
 F ext/session/session8.test 8e194b3f655d861ca36de5d4de53f702751bab3b
 F ext/session/session9.test 5409d90d8141881d08285ed1c2c0d8d10fb92069
 F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f
-F ext/session/sessionB.test 06961b7c3641151f5d23088250ecad132501113c
+F ext/session/sessionB.test 886252dcb7e692e62ef7e357456200912e367823
 F ext/session/sessionC.test 3982f8577b0744c5ce3aaef7cfeb5bd903f17fe4
 F ext/session/sessionD.test d4744c78334162851d2a2f285c7e603e31b49aa2
 F ext/session/sessionE.test e60a238c47f0feb3bb707e7f35e22be09c7e8f26
-F ext/session/session_common.tcl f4b7b59c617edf0c9b00d94cd93498d225d43837
+F ext/session/sessionF.test c2f178d4dfd723a5fd94a730ea2ccb44c669e3ce
+F ext/session/session_common.tcl a1293167d14774b5e728836720497f40fe4ea596
 F ext/session/sessionfault.test bef044d0952c0d62c31c8d2400be72c8684545cc
-F ext/session/sqlite3session.c 78e5b310cd6e655e9166f40dc8a319c0c866cfdc
-F ext/session/sqlite3session.h 772cffe38f11bd62f434eabf080157eabf3d553e
+F ext/session/sqlite3session.c 1ace1d1e4cb32cf60ca6e8ed1ae8d4c9f99ca458
+F ext/session/sqlite3session.h 64e9e7f185725ef43b97f4a9a0c0df0669844f1d
 F ext/session/test_session.c 187bd344c5ae9d5be85e22ef7c3010f0c17307ce
 F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220
 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
@@ -1409,7 +1410,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P c91065f8edb1e54076791716fc20d3fcfe3070dc e796c0efb6cf17444b53af75046daf7d8fa82f78
-R 0237333bf6dc63bf0c4f4c66d7918366
-U drh
-Z 5f6cedfd7517312f688a69652091b608
+P b2face9aa95ade96a5666c70b6b31064c1ad0977
+R 67f4bc03b9ceb2707f867778f6790d70
+U dan
+Z c3622f418cca20fcda99ae888e36e276
index 75c74a20e29bcf8cb02d40b03c4c01746d00e13f..5274d2fafab92ba9b87abf6284ff7e0808b9169b 100644 (file)
@@ -1 +1 @@
-b2face9aa95ade96a5666c70b6b31064c1ad0977
\ No newline at end of file
+7695890230dc1e0c6db9b7aa509db2039c7f7239
\ No newline at end of file