]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix handling of schema mismatches in sqlite3session.c so that it matches the docs...
authordan <dan@noemail.net>
Thu, 24 Mar 2011 16:04:54 +0000 (16:04 +0000)
committerdan <dan@noemail.net>
Thu, 24 Mar 2011 16:04:54 +0000 (16:04 +0000)
FossilOrigin-Name: 506a0d7a710e1ff2f367821e73f5080fcf63fbc5

ext/session/session3.test [new file with mode: 0644]
ext/session/sqlite3session.c
ext/session/sqlite3session.h
manifest
manifest.uuid

diff --git a/ext/session/session3.test b/ext/session/session3.test
new file mode 100644 (file)
index 0000000..e07032f
--- /dev/null
@@ -0,0 +1,88 @@
+# 2011 March 24
+#
+# 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 session module.
+#
+
+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
+
+set testprefix session3
+
+# These tests - session3-1.* - verify that the session module behaves
+# correctly when confronted with a schema mismatch when applying a 
+# changeset (in function sqlite3changeset_apply()).
+#
+#   session3-1.1.*: Table does not exist in target db.
+#   session3-1.2.*: Table has wrong number of columns in target db.
+#   session3-1.3.*: Table has wrong PK columns in target db.
+#
+
+db close
+sqlite3_shutdown
+test_sqlite3_log log
+sqlite3 db test.db
+
+proc log {code msg} { lappend ::log $code $msg }
+
+forcedelete test.db2
+sqlite3 db2 test.db2
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a PRIMARY KEY, b);
+}
+do_test 1.1 {
+  set ::log {}
+  do_then_apply_sql {
+    INSERT INTO t1 VALUES(1, 2);
+    INSERT INTO t1 VALUES(3, 4);
+  }
+  set ::log
+} {SQLITE_SCHEMA {sqlite3changeset_apply(): no such table: t1}}
+
+do_test 1.2.0 {
+  execsql { CREATE TABLE t1(a PRIMARY KEY, b, c) } db2
+} {}
+do_test 1.2.1 {
+  set ::log {}
+  do_then_apply_sql {
+    INSERT INTO t1 VALUES(5, 6);
+    INSERT INTO t1 VALUES(7, 8);
+  }
+  set ::log
+} {SQLITE_SCHEMA {sqlite3changeset_apply(): table t1 has 3 columns, expected 2}}
+
+do_test 1.3.0 {
+  execsql { 
+    DROP TABLE t1;
+    CREATE TABLE t1(a, b PRIMARY KEY);
+  } db2
+} {}
+do_test 1.3.1 {
+  set ::log {}
+  do_then_apply_sql {
+    INSERT INTO t1 VALUES(9, 10);
+    INSERT INTO t1 VALUES(11, 12);
+  }
+  set ::log
+} {SQLITE_SCHEMA {sqlite3changeset_apply(): primary key mismatch for table t1}}
+
+
+catch { db close }
+catch { db2 close }
+sqlite3_shutdown
+test_sqlite3_log
+sqlite3_initialize
+
+finish_test
+
index 4ab8bb32ce815195fe9872afa702410a67a5a6fa..c64f567f90ecea8de793de14ce464bf9fe68a425 100644 (file)
@@ -544,7 +544,7 @@ static int sessionTableInfo(
   sqlite3 *db,                    /* Database connection */
   const char *zDb,                /* Name of attached database (e.g. "main") */
   const char *zThis,              /* Table name */
-  int nCol,                       /* Expected number of columns */
+  int *pnCol,                     /* OUT: number of columns */
   const char **pzTab,             /* OUT: Copy of zThis */
   const char ***pazCol,           /* OUT: Array of column names for table */
   u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
@@ -577,9 +577,6 @@ static int sessionTableInfo(
   }
   rc = sqlite3_reset(pStmt);
 
-  if( nDbCol!=nCol ){
-    rc = SQLITE_SCHEMA;
-  }
   if( rc==SQLITE_OK ){
     nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
     pAlloc = sqlite3_malloc(nByte);
@@ -589,9 +586,9 @@ static int sessionTableInfo(
   }
   if( rc==SQLITE_OK ){
     azCol = (char **)pAlloc;
-    pAlloc = (u8 *)&azCol[nCol];
+    pAlloc = (u8 *)&azCol[nDbCol];
     abPK = (u8 *)pAlloc;
-    pAlloc = &abPK[nCol];
+    pAlloc = &abPK[nDbCol];
     if( pzTab ){
       memcpy(pAlloc, zThis, nThis+1);
       *pzTab = (char *)pAlloc;
@@ -619,9 +616,11 @@ static int sessionTableInfo(
   if( rc==SQLITE_OK ){
     *pazCol = (const char **)azCol;
     *pabPK = abPK;
+    *pnCol = nDbCol;
   }else{
     *pazCol = 0;
     *pabPK = 0;
+    *pnCol = 0;
     if( pzTab ) *pzTab = 0;
     sqlite3_free(azCol);
   }
@@ -648,11 +647,13 @@ static int sessionTableInfo(
 static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
   if( pTab->nCol==0 ){
     assert( pTab->azCol==0 || pTab->abPK==0 );
-    pTab->nCol = sqlite3_preupdate_count(pSession->db);
     pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, 
-        pTab->zName, pTab->nCol, 0, &pTab->azCol, &pTab->abPK
+        pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->abPK
     );
-  }else if( pTab->nCol!=sqlite3_preupdate_count(pSession->db) ){
+  }
+  if( pSession->rc==SQLITE_OK 
+   && pTab->nCol!=sqlite3_preupdate_count(pSession->db) 
+  ){
     pSession->rc = SQLITE_SCHEMA;
   }
   return pSession->rc;
@@ -2402,6 +2403,7 @@ int sqlite3changeset_apply(
   ),
   void *pCtx                      /* First argument passed to xConflict */
 ){
+  int schemaMismatch = 0;
   sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
   int rc;                         /* Return code */
   const char *zTab = 0;           /* Name of current table */
@@ -2420,9 +2422,13 @@ int sqlite3changeset_apply(
     int bReplace = 0;
     int bRetry = 0;
     const char *zNew;
+    
     sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
 
     if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
+      u8 *abPK;
+
+      schemaMismatch = 0;
       sqlite3_free(sApply.azCol);
       sqlite3_finalize(sApply.pDelete);
       sqlite3_finalize(sApply.pUpdate); 
@@ -2430,23 +2436,47 @@ int sqlite3changeset_apply(
       sqlite3_finalize(sApply.pSelect);
       memset(&sApply, 0, sizeof(sApply));
       sApply.db = db;
-      sApply.nCol = nCol;
 
+      sqlite3changeset_pk(pIter, &abPK, 0);
       rc = sessionTableInfo(
-          db, "main", zNew, nCol, &zTab, &sApply.azCol, &sApply.abPK);
+          db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+      );
+      if( rc!=SQLITE_OK ) break;
 
-      if( rc!=SQLITE_OK 
-       || (rc = sessionSelectRow(db, zTab, &sApply))
+      if( sApply.nCol==0 ){
+        schemaMismatch = 1;
+        sqlite3_log(SQLITE_SCHEMA, 
+            "sqlite3changeset_apply(): no such table: %s", zTab
+        );
+      }
+      else if( sApply.nCol!=nCol ){
+        schemaMismatch = 1;
+        sqlite3_log(SQLITE_SCHEMA, 
+            "sqlite3changeset_apply(): table %s has %d columns, expected %d", 
+            zTab, sApply.nCol, nCol
+        );
+      }
+      else if( memcmp(sApply.abPK, abPK, nCol)!=0 ){
+        schemaMismatch = 1;
+        sqlite3_log(SQLITE_SCHEMA, 
+            "sqlite3changeset_apply(): primary key mismatch for table %s", zTab
+        );
+      }
+      else if( 
+          (rc = sessionSelectRow(db, zTab, &sApply))
        || (rc = sessionUpdateRow(db, zTab, &sApply))
        || (rc = sessionDeleteRow(db, zTab, &sApply))
        || (rc = sessionInsertRow(db, zTab, &sApply))
       ){
         break;
       }
-
       nTab = strlen(zTab);
     }
 
+    /* If there is a schema mismatch on the current table, proceed to the
+    ** next change. A log message has already been issued. */
+    if( schemaMismatch ) continue;
+
     rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
 
     if( rc==SQLITE_OK && bRetry ){
index b6ea72522d8c877d07b4f8d61faaffb4def67b18..5d19379ec8b0f9a195f2b55909c2bd9b4c5de053 100644 (file)
@@ -48,7 +48,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
 **
 ** The session object will be used to create changesets for tables in
 ** database zDb, where zDb is either "main", or "temp", or the name of an
-** attached database. It is not an error if database zDb does not exist
+** attached database. It is not an error if database zDb is not attached
 ** to the database when the session object is created.
 */
 int sqlite3session_create(
index edccb68924349cf375b8d7746db96812e8baf6e2..e59c27fb7534c65b2e3b82d3a24d6b91e20fe097 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Store\sprimary\skey\sdefinitions\sfor\smodified\stables\sin\schangesets.\sAdd\sthe\ssqlite3changeset_pk()\sAPI\sto\sextract\sthis\sdata\sfrom\sa\schangeset\siterator.
-D 2011-03-24T11:22:59
+C Fix\shandling\sof\sschema\smismatches\sin\ssqlite3session.c\sso\sthat\sit\smatches\sthe\sdocs\sin\ssqlite3session.h.
+D 2011-03-24T16:04:55
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -101,10 +101,11 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
 F ext/session/session1.test b2da15b9d727d7f4e5fe95599b32b92d93b5a970
 F ext/session/session2.test 8da094318ac88953478c43d0bfb0aa723ee0e379
+F ext/session/session3.test b8b9ff7efcb19234892c406dba8bd56792560efe
 F ext/session/session_common.tcl fb91560b6dbd086010df8b3a137a452f1ac21a28
 F ext/session/sessionfault.test d7e6154a30e85622d0733b1a1e3c63e9b8b7004b
-F ext/session/sqlite3session.c 886827f10de75576baf9f9d860414fa155e1c8c1
-F ext/session/sqlite3session.h 8d3e00c0a2e323e6f47b1204ec9ff714ca3bee4a
+F ext/session/sqlite3session.c cf91fe0efb0728c219c8bc2b2174a49758fbd3f8
+F ext/session/sqlite3session.h 900d900bb6a827f84754fc252a05638e0f413a6e
 F ext/session/test_session.c e0f500ec5e20478afc2c7998133e8acea7ec5104
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
@@ -923,7 +924,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 9c3a6e479988e96086bef00c79dbce508a14da0d
-R f502a856cffb82507c875b00a2fb9d4d
+P 54298ee5ed183d1f1c49524f25e8ae1407f3d4b5
+R 73cd0f1e5ce098769e9cee2c7d1f1ebc
 U dan
-Z 3fdb3d84abab55a6e9fe1eeceb839a7c
+Z 8a40e5171d2567a1ae6ca1b697973f9a
index 12934424cdf9ad7f59f6a66209e84e3cafb822ee..e8475cfcd081f4b4ecee413be0018aa6b97efdf3 100644 (file)
@@ -1 +1 @@
-54298ee5ed183d1f1c49524f25e8ae1407f3d4b5
\ No newline at end of file
+506a0d7a710e1ff2f367821e73f5080fcf63fbc5
\ No newline at end of file