-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
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
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
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
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
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
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
-98e029134dc1300d3ecb48b41b5107ec69ba85db
\ No newline at end of file
+42d5601739c90434e5adfda8fa99ef7b903877db
\ No newline at end of file
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;
}
}
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;
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;
}
}
{ "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;
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;
#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
/*
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 */
} 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;
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;
}
}
# 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);
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.
#
# 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;
} {}
# 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;
{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