diff options
Diffstat (limited to 'test/imposter1.test')
-rw-r--r-- | test/imposter1.test | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/test/imposter1.test b/test/imposter1.test new file mode 100644 index 0000000..196767b --- /dev/null +++ b/test/imposter1.test @@ -0,0 +1,141 @@ +# 2015-01-30 +# +# 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 tests for SQLite library. +# +# The focus of this file is adding extra entries in the symbol table +# 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 imposter + +# Create a bunch of data to sort against +# +do_test imposter-1.0 { + execsql { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d NOT NULL); + CREATE INDEX t1b ON t1(b); + CREATE UNIQUE INDEX t1c ON t1(c); + WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + 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 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 an imposter table that uses the same b-tree as t1 but which does + # not have the indexes + # + sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $t1_root + db eval {CREATE TABLE xt1(a,b,c,d)} + + # 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. + # + db eval { + CREATE TEMP TABLE chnglog(desc TEXT); + CREATE TEMP TRIGGER xt1_del AFTER DELETE ON xt1 BEGIN + INSERT INTO chnglog VALUES( + printf('DELETE t1: rowid=%d, a=%s, b=%s, c=%s, d=%s', + old.rowid, quote(old.a), quote(old.b), quote(old.c), + quote(old.d))); + END; + CREATE TEMP TRIGGER xt1_ins AFTER INSERT ON xt1 BEGIN + INSERT INTO chnglog VALUES( + printf('INSERT t1: rowid=%d, a=%s, b=%s, c=%s, d=%s', + new.rowid, quote(new.a), quote(new.b), quote(new.c), + quote(new.d))); + END; + } +} {} + +# The xt1 table has separate xt1.rowid and xt1.a columns. The xt1.rowid +# column corresponds to t1.rowid and t1.a, but the xt1.a column is always +# NULL +# +do_execsql_test imposter-1.1 { + SELECT rowid FROM xt1 WHERE a IS NOT NULL; +} {} +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; +} {} + + +# Make changes via the xt1 shadow table. This will not update the +# indexes on t1 nor check the uniqueness constraint on t1.c nor check +# the NOT NULL constraint on t1.d, resulting in a logically inconsistent +# database. +# +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; +} [list \ + {DELETE t1: rowid=5, a=NULL, b=1005, c=2005, d=3005} \ + {INSERT t1: rowid=99, a='hello', b=1099, c=2022, d=NULL} \ +] + +do_execsql_test imposter-1.4a { + PRAGMA integrity_check; +} {/NULL value in t1.d/} +do_execsql_test imposter-1.4b { + PRAGMA integrity_check; +} {/row # missing from index t1b/} +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 |