]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change SQLITE_TESTCTRL_INITMODE to SQLITE_TESTCTRL_IMPOSTER. Revise the order
authordrh <drh@noemail.net>
Fri, 30 Jan 2015 20:59:27 +0000 (20:59 +0000)
committerdrh <drh@noemail.net>
Fri, 30 Jan 2015 20:59:27 +0000 (20:59 +0000)
of parameters.  Give it the ability to reset the schema parse table so that
imposter tables can be erased.

FossilOrigin-Name: 42d5601739c90434e5adfda8fa99ef7b903877db

manifest
manifest.uuid
src/btree.c
src/build.c
src/main.c
src/shell.c
src/sqlite.h.in
src/sqliteInt.h
src/test1.c
test/imposter1.test [moved from test/initmode.test with 60% similarity]

index 09d4bc0fa8ceca770b9f6c8f5cacc3246e4c4627..f8fe7806e281fbd6b3d82ba9453bf5ea83b2ac82 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Added\sSQLITE_TESTCTRL_INITMODE\sfor\simproved\stestability.
-D 2015-01-30T15:52:26.210
+C Change\sSQLITE_TESTCTRL_INITMODE\sto\sSQLITE_TESTCTRL_IMPOSTER.\s\sRevise\sthe\sorder\nof\sparameters.\s\sGive\sit\sthe\sability\sto\sreset\sthe\sschema\sparse\stable\sso\sthat\nimposter\stables\scan\sbe\serased.
+D 2015-01-30T20:59:27.457
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -173,10 +173,10 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
 F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea
 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
 F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
-F src/btree.c 4c098bb6e8678e4596983862abf78f7a0fcb807e
+F src/btree.c 2a1245df0356a229bcd0fd87a8536b5067f16e82
 F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474
 F src/btreeInt.h a3d0ae1d511365e1a2b76ad10960dbe55c286f34
-F src/build.c f5cfd7b32216f695b995bbc7c1a395f6d451d11f
+F src/build.c eefaa4f1d86bc3c08023a61fdd1e695b47796975
 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
 F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463
 F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887
@@ -195,7 +195,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
 F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
 F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
 F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660
-F src/main.c 81ddebf2feb9cbd8c8ea160cdd979503f645d505
+F src/main.c ce38ddcedf33e5530b0e6c592809bb8822a6e8d0
 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
@@ -230,16 +230,16 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
 F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada
 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
 F src/select.c 1f2087523007c42900ffcbdeaef06a23ad9329fc
-F src/shell.c ed7cf7c29fb1a23d47179affc89cb447868fc976
-F src/sqlite.h.in 6910064681444efb5c467472499b56bb6bcee0f4
+F src/shell.c 22b4406b0b59efd14b3b351a5809dda517df6d30
+F src/sqlite.h.in 54678c21401909f72b221344dd560d285a1ba5eb
 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
 F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
-F src/sqliteInt.h eaf210295b551d4e40e622aec1b2261c0b28f844
+F src/sqliteInt.h c4e05f7489cd300f856e2283d5e61302ce826471
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 81712116e826b0089bb221b018929536b2b5406f
 F src/table.c e7a09215315a978057fb42c640f890160dbcc45e
 F src/tclsqlite.c b8014393a96a9781bb635c8b1f52fc9b77a2bfcf
-F src/test1.c 5dcdade99e77b7b9f7760106c80a83cf50f10e1e
+F src/test1.c 90fbedce75330d48d99eadb7d5f4223e86969585
 F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d
 F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622
 F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
@@ -630,6 +630,7 @@ F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
 F test/hexlit.test f9ecde8145bfc2341573473256c74ae37a200497
 F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f
 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
+F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 w test/initmode.test
 F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
@@ -655,7 +656,6 @@ F test/index7.test 917cf1e1c7439bb155abbeabec511b28945e157b
 F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
-F test/initmode.test 38bbaefeb47e034a162856e664a0da3b95e6999b
 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
@@ -1238,8 +1238,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 1797158db2a818134c5cba1578f69ed85948b980 3a6e2afe408d2b0c8166d00def2048568169d87a
-R 4fa14bf275b60ddd661b9bd3fb0ea0dd
-T +closed 3a6e2afe408d2b0c8166d00def2048568169d87a
+P 98e029134dc1300d3ecb48b41b5107ec69ba85db
+R ae5f14ccaf584de0786e4614152020d2
 U drh
-Z b68a5e615b7688be627f33067b9af11c
+Z c23d2e36f9e88e779a131b19c0ee1b9b
index d36751134285f6fcd922802cfed0613430daf027..9eba1b1a5401baf9e1a85d06af0e3170ac218928 100644 (file)
@@ -1 +1 @@
-98e029134dc1300d3ecb48b41b5107ec69ba85db
\ No newline at end of file
+42d5601739c90434e5adfda8fa99ef7b903877db
\ No newline at end of file
index f9f76c2ebbc0b59483d5ee4029956b816326069e..eb5151351c68d3b4815da028b35d2e61588da34e 100644 (file)
@@ -175,6 +175,12 @@ static int hasSharedCacheTableLock(
     for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
       Index *pIdx = (Index *)sqliteHashData(p);
       if( pIdx->tnum==(int)iRoot ){
+        if( iTab ){
+          /* Two or more indexes share the same root page.  There must
+          ** be imposter tables.  So just return true.  The assert is not
+          ** useful in that case. */
+          return 1;
+        }
         iTab = pIdx->pTable->tnum;
       }
     }
index f02989bffebd95893333adaadf9a7ef7aa3328b0..7e3ce1b76aa6f0a6b127bcf2a5df7139998b3f27 100644 (file)
@@ -1731,11 +1731,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   assert( pPk!=0 );
   nPk = pPk->nKeyCol;
 
-  /* Make sure every column of the PRIMARY KEY is NOT NULL */
-  for(i=0; i<nPk; i++){
-    pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+  /* Make sure every column of the PRIMARY KEY is NOT NULL.  (Except,
+  ** do not enforce this for imposter tables.) */
+  if( !db->init.imposterTable ){
+    for(i=0; i<nPk; i++){
+      pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+    }
+    pPk->uniqNotNull = 1;
   }
-  pPk->uniqNotNull = 1;
 
   /* The root page of the PRIMARY KEY is the table root page */
   pPk->tnum = pTab->tnum;
index 0d6f1be2461f9232e38e41be759733eeaaf3f83c..11585e7dc5be02d9c7452cee6fd4d1ac3d87aff3 100644 (file)
@@ -3599,15 +3599,30 @@ int sqlite3_test_control(int op, ...){
       break;
     }
 
-    /*   sqlite3_test_control(SQLITE_TESTCTRL_INITMODE, db, busy, iDb, newTnum);
+    /*   sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum);
     **
-    ** Set the db->init.busy, db->init.iDb, and db->init.tnum fields.
+    ** This test control is used to create imposter tables.  "db" is a pointer
+    ** to the database connection.  dbName is the database name (ex: "main" or
+    ** "temp") which will receive the imposter.  "onOff" turns imposter mode on
+    ** or off.  "tnum" is the root page of the b-tree to which the imposter
+    ** table should connect.
+    **
+    ** Enable imposter mode only when the schema has already been parsed.  Then
+    ** run a single CREATE TABLE statement to construct the imposter table in the
+    ** parsed schema.  Then turn imposter mode back off again.
+    **
+    ** If onOff==0 and tnum>0 then reset the schema for all databases, causing
+    ** the schema to be reparsed the next time it is needed.  This has the
+    ** effect of erasing all imposter tables.
     */
-    case SQLITE_TESTCTRL_INITMODE: {
+    case SQLITE_TESTCTRL_IMPOSTER: {
       sqlite3 *db = va_arg(ap, sqlite3*);
-      db->init.busy = va_arg(ap,int);
-      db->init.iDb = va_arg(ap,int);
+      db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
+      db->init.busy = db->init.imposterTable = va_arg(ap,int);
       db->init.newTnum = va_arg(ap,int);
+      if( db->init.busy==0 && db->init.newTnum>0 ){
+        sqlite3ResetAllSchemasOfConnection(db);
+      }
       break;
     }
   }
index 1a191e0fd0b555e659ba99b36df8283cb7ed3269..3130f4c6de7e95c0abded9d3c39867c12e3a242c 100644 (file)
@@ -3536,7 +3536,7 @@ static int do_meta_command(char *zLine, ShellState *p){
       { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
       { "byteorder",             SQLITE_TESTCTRL_BYTEORDER              },
       { "never_corrupt",         SQLITE_TESTCTRL_NEVER_CORRUPT          },
-      { "initmode",              SQLITE_TESTCTRL_INITMODE               },
+      { "imposter",              SQLITE_TESTCTRL_IMPOSTER               },
     };
     int testctrl = -1;
     int rc = 0;
@@ -3629,14 +3629,14 @@ static int do_meta_command(char *zLine, ShellState *p){
           break;
 #endif
 
-        case SQLITE_TESTCTRL_INITMODE:
+        case SQLITE_TESTCTRL_IMPOSTER:
           if( nArg==5 ){
             rc = sqlite3_test_control(testctrl, p->db, 
-                          integerValue(azArg[2]),
+                          azArg[2],
                           integerValue(azArg[3]),
                           integerValue(azArg[4]));
           }else{
-            fprintf(stderr,"Usage: .testctrl initmode fBusy iDb newTnum\n");
+            fprintf(stderr,"Usage: .testctrl initmode dbName onoff tnum\n");
             rc = 1;
           }
           break;
index 722b9235a24ec92ac9993cdde45f63f8198f7713..f256cea45de74aa851572327f2c7a39e96ece57e 100644 (file)
@@ -6260,7 +6260,7 @@ int sqlite3_test_control(int op, ...);
 #define SQLITE_TESTCTRL_BYTEORDER               22
 #define SQLITE_TESTCTRL_ISINIT                  23
 #define SQLITE_TESTCTRL_SORTER_MMAP             24
-#define SQLITE_TESTCTRL_INITMODE                25
+#define SQLITE_TESTCTRL_IMPOSTER                25
 #define SQLITE_TESTCTRL_LAST                    25
 
 /*
index 379456d5f524aa7dabc5623c0e4a0b1df4947766..0bc6f679dde91d3a23c508693734e490646e6b8b 100644 (file)
@@ -1087,6 +1087,7 @@ struct sqlite3 {
     u8 iDb;                     /* Which db file is being initialized */
     u8 busy;                    /* TRUE if currently initializing */
     u8 orphanTrigger;           /* Last statement is orphaned TEMP trigger */
+    u8 imposterTable;           /* Building an imposter table */
   } init;
   int nVdbeActive;              /* Number of VDBEs currently running */
   int nVdbeRead;                /* Number of active VDBEs that read or write */
index b9503cf3940d683ad6b59cbbac4fd0c5b5cfd266..a87fcd859de0940e3dd7059432438b176ae2d3fb 100644 (file)
@@ -5915,7 +5915,7 @@ static int test_test_control(
   } aVerb[] = {
     { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, 
     { "SQLITE_TESTCTRL_SORTER_MMAP",     SQLITE_TESTCTRL_SORTER_MMAP     }, 
-    { "SQLITE_TESTCTRL_INITMODE",        SQLITE_TESTCTRL_INITMODE        },
+    { "SQLITE_TESTCTRL_IMPOSTER",        SQLITE_TESTCTRL_IMPOSTER        },
   };
   int iVerb;
   int iFlag;
@@ -5957,18 +5957,19 @@ static int test_test_control(
       break;
     }
 
-    case SQLITE_TESTCTRL_INITMODE: {
-      int fBusy, iDb, newTnum;
+    case SQLITE_TESTCTRL_IMPOSTER: {
+      int onOff, tnum;
+      const char *zDbName;
       sqlite3 *db;
       if( objc!=6 ){
-        Tcl_WrongNumArgs(interp, 2, objv, "DB fBusy iDb newTnum");
+        Tcl_WrongNumArgs(interp, 2, objv, "DB dbName onOff tnum");
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
-      if( Tcl_GetIntFromObj(interp, objv[3], &fBusy) ) return TCL_ERROR;
-      if( Tcl_GetIntFromObj(interp, objv[4], &iDb) ) return TCL_ERROR;
-      if( Tcl_GetIntFromObj(interp, objv[5], &newTnum) ) return TCL_ERROR;
-      sqlite3_test_control(SQLITE_TESTCTRL_INITMODE, db, fBusy, iDb, newTnum);
+      zDbName = Tcl_GetString(objv[3]);
+      if( Tcl_GetIntFromObj(interp, objv[4], &onOff) ) return TCL_ERROR;
+      if( Tcl_GetIntFromObj(interp, objv[5], &tnum) ) return TCL_ERROR;
+      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum);
       break;
     }
   }
similarity index 60%
rename from test/initmode.test
rename to test/imposter1.test
index ce3f675857eece793c4c5c44ef559713f0a635a3..196767be15e45b8ed0e7a6c5cb70514c1448570b 100644 (file)
 # This file implements tests for SQLite library.
 #
 # The focus of this file is adding extra entries in the symbol table
-# using sqlite3_test_control(SQLITE_TESTCTRL_INITMODE) and verifying that
+# using sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER) and verifying that
 # SQLite handles those as expected.
 #
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
-set testprefix initmode
+set testprefix imposter
 
 # Create a bunch of data to sort against
 #
-do_test initmode-1.0 {
+do_test imposter-1.0 {
   execsql {
     CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d NOT NULL);
     CREATE INDEX t1b ON t1(b);
@@ -31,15 +31,21 @@ do_test initmode-1.0 {
       INSERT INTO t1(a,b,c,d) SELECT i,1000+i,2000+i,3000+i FROM c;
   }
   set t1_root [db one {SELECT rootpage FROM sqlite_master WHERE name='t1'}]
-  set t1a_root [db one {SELECT rootpage FROM sqlite_master WHERE name='t1a'}]
   set t1b_root [db one {SELECT rootpage FROM sqlite_master WHERE name='t1b'}]
+  set t1c_root [db one {SELECT rootpage FROM sqlite_master WHERE name='t1c'}]
 
-  # Create a shadow table that uses the same b-tree as t1 but which does
+  # Create an imposter table that uses the same b-tree as t1 but which does
   # not have the indexes
   #
-  sqlite3_test_control SQLITE_TESTCTRL_INITMODE db 1 0 $t1_root
+  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $t1_root
   db eval {CREATE TABLE xt1(a,b,c,d)}
-  sqlite3_test_control SQLITE_TESTCTRL_INITMODE db 0 0 0
+
+  # And create an imposter table for the t1c index.
+  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $t1c_root
+  db eval {CREATE TABLE xt1c(c,rowid,PRIMARY KEY(c,rowid))WITHOUT ROWID;}
+
+  # Go out of imposter mode for now.
+  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
 
   # Create triggers to record changes to xt1.
   #
@@ -64,10 +70,10 @@ do_test initmode-1.0 {
 # column corresponds to t1.rowid and t1.a, but the xt1.a column is always
 # NULL
 #
-do_execsql_test initmode-1.1 {
+do_execsql_test imposter-1.1 {
   SELECT rowid FROM xt1 WHERE a IS NOT NULL;
 } {}
-do_execsql_test initmode-1.2 {
+do_execsql_test imposter-1.2 {
   SELECT a,b,c,d FROM t1 EXCEPT SELECT rowid,b,c,d FROM xt1;
   SELECT rowid,b,c,d FROM xt1 EXCEPT SELECT a,b,c,d FROM t1;
 } {}
@@ -78,7 +84,7 @@ do_execsql_test initmode-1.2 {
 # the NOT NULL constraint on t1.d, resulting in a logically inconsistent
 # database.
 #
-do_execsql_test initmode-1.3 {
+do_execsql_test imposter-1.3 {
   DELETE FROM xt1 WHERE rowid=5;
   INSERT INTO xt1(rowid,a,b,c,d) VALUES(99,'hello',1099,2022,NULL);
   SELECT * FROM chnglog ORDER BY rowid;
@@ -87,14 +93,49 @@ do_execsql_test initmode-1.3 {
   {INSERT t1:  rowid=99, a='hello', b=1099, c=2022, d=NULL} \
 ]
 
-do_execsql_test initmode-1.4a {
+do_execsql_test imposter-1.4a {
   PRAGMA integrity_check;
 } {/NULL value in t1.d/}
-do_execsql_test initmode-1.4b {
+do_execsql_test imposter-1.4b {
   PRAGMA integrity_check;
 } {/row # missing from index t1b/}
-do_execsql_test initmode-1.4c {
+do_execsql_test imposter-1.4c {
   PRAGMA integrity_check;
 } {/row # missing from index t1c/}
 
+# Cleanup the corruption.
+# Then demonstrate that the xt1c imposter table can insert non-unique
+# and NULL values into the UNIQUE index.
+#
+do_execsql_test imposter-2.0 {
+  DELETE FROM t1;
+  WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10)
+   INSERT INTO t1(a,b,c,d) SELECT i,i,i,i FROM c;
+  UPDATE xt1c SET c=NULL WHERE rowid=5;
+  PRAGMA integrity_check;
+} {/row # missing from index t1c/}
+
+do_execsql_test imposter-2.1 {
+  DELETE FROM t1;
+  WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10)
+   INSERT INTO t1(a,b,c,d) SELECT i,i,i,i FROM c;
+  UPDATE xt1c SET c=99 WHERE rowid IN (5,7,9);
+  SELECT c FROM t1 ORDER BY c;
+} {1 2 3 4 6 8 10 99 99 99}
+do_execsql_test imposter-2.2 {
+  UPDATE xt1 SET c=99 WHERE rowid IN (5,7,9);
+  PRAGMA integrity_check;
+} {/non-unique entry in index t1c/}
+
+# Erase the imposter tables
+#
+do_test imposter-3.1 {
+  sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 1
+  db eval {
+    DELETE FROM t1 WHERE rowid IN (5,7,9);
+    PRAGMA integrity_check;
+  }
+} {ok}
+
+
 finish_test