11fe0537eSdrh# 2013-07-31 21fe0537eSdrh# 31fe0537eSdrh# The author disclaims copyright to this source code. In place of 41fe0537eSdrh# a legal notice, here is a blessing: 51fe0537eSdrh# 61fe0537eSdrh# May you do good and not evil. 71fe0537eSdrh# May you find forgiveness for yourself and forgive others. 81fe0537eSdrh# May you share freely, never taking more than you give. 91fe0537eSdrh# 101fe0537eSdrh#*********************************************************************** 111fe0537eSdrh# 121fe0537eSdrh# Test cases for partial indices 131fe0537eSdrh# 141fe0537eSdrh 151fe0537eSdrh 161fe0537eSdrhset testdir [file dirname $argv0] 171fe0537eSdrhsource $testdir/tester.tcl 181fe0537eSdrh 19c3c16cbdSdanifcapable !vtab { 20c3c16cbdSdan finish_test 21c3c16cbdSdan return 22c3c16cbdSdan} 23c3c16cbdSdan 241fe0537eSdrhload_static_extension db wholenumber; 251fe0537eSdrhdo_test index6-1.1 { 2666518ca7Sdrh # Able to parse and manage partial indices 271fe0537eSdrh execsql { 28721dfcf5Sdrh CREATE TABLE t1(a,b,c); 291fe0537eSdrh CREATE INDEX t1a ON t1(a) WHERE a IS NOT NULL; 301fe0537eSdrh CREATE INDEX t1b ON t1(b) WHERE b>10; 311fe0537eSdrh CREATE VIRTUAL TABLE nums USING wholenumber; 32721dfcf5Sdrh INSERT INTO t1(a,b,c) 33721dfcf5Sdrh SELECT CASE WHEN value%3!=0 THEN value END, value, value 341fe0537eSdrh FROM nums WHERE value<=20; 351fe0537eSdrh SELECT count(a), count(b) FROM t1; 3666518ca7Sdrh PRAGMA integrity_check; 371fe0537eSdrh } 3866518ca7Sdrh} {14 20 ok} 391fe0537eSdrh 405f33f375Sdrh# Make sure the count(*) optimization works correctly with 415f33f375Sdrh# partial indices. Ticket [a5c8ed66cae16243be6] 2013-10-03. 425f33f375Sdrh# 435f33f375Sdrhdo_execsql_test index6-1.1.1 { 445f33f375Sdrh SELECT count(*) FROM t1; 455f33f375Sdrh} {20} 465f33f375Sdrh 4766518ca7Sdrh# Error conditions during parsing... 4866518ca7Sdrh# 493780be11Sdrhdo_test index6-1.2 { 503780be11Sdrh catchsql { 51721dfcf5Sdrh CREATE INDEX bad1 ON t1(a,b) WHERE x IS NOT NULL; 523780be11Sdrh } 53721dfcf5Sdrh} {1 {no such column: x}} 543780be11Sdrhdo_test index6-1.3 { 553780be11Sdrh catchsql { 563780be11Sdrh CREATE INDEX bad1 ON t1(a,b) WHERE EXISTS(SELECT * FROM t1); 573780be11Sdrh } 583780be11Sdrh} {1 {subqueries prohibited in partial index WHERE clauses}} 593780be11Sdrhdo_test index6-1.4 { 603780be11Sdrh catchsql { 613780be11Sdrh CREATE INDEX bad1 ON t1(a,b) WHERE a!=?1; 623780be11Sdrh } 633780be11Sdrh} {1 {parameters prohibited in partial index WHERE clauses}} 643780be11Sdrhdo_test index6-1.5 { 653780be11Sdrh catchsql { 663780be11Sdrh CREATE INDEX bad1 ON t1(a,b) WHERE a!=random(); 673780be11Sdrh } 683780be11Sdrh} {1 {functions prohibited in partial index WHERE clauses}} 693780be11Sdrhdo_test index6-1.6 { 703780be11Sdrh catchsql { 713780be11Sdrh CREATE INDEX bad1 ON t1(a,b) WHERE a NOT LIKE 'abc%'; 723780be11Sdrh } 733780be11Sdrh} {1 {functions prohibited in partial index WHERE clauses}} 743780be11Sdrh 758a9789b6Sdrhdo_test index6-1.10 { 768a9789b6Sdrh execsql { 778a9789b6Sdrh ANALYZE; 788a9789b6Sdrh SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; 798a9789b6Sdrh PRAGMA integrity_check; 808a9789b6Sdrh } 81721dfcf5Sdrh} {{} 20 t1a {14 1} t1b {10 1} ok} 828a9789b6Sdrh 8366518ca7Sdrh# STAT1 shows the partial indices have a reduced number of 8466518ca7Sdrh# rows. 8566518ca7Sdrh# 868a9789b6Sdrhdo_test index6-1.11 { 878a9789b6Sdrh execsql { 888a9789b6Sdrh UPDATE t1 SET a=b; 898a9789b6Sdrh ANALYZE; 908a9789b6Sdrh SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; 918a9789b6Sdrh PRAGMA integrity_check; 928a9789b6Sdrh } 93721dfcf5Sdrh} {{} 20 t1a {20 1} t1b {10 1} ok} 948a9789b6Sdrh 958a9789b6Sdrhdo_test index6-1.11 { 968a9789b6Sdrh execsql { 978a9789b6Sdrh UPDATE t1 SET a=NULL WHERE b%3!=0; 988a9789b6Sdrh UPDATE t1 SET b=b+100; 998a9789b6Sdrh ANALYZE; 1008a9789b6Sdrh SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; 1018a9789b6Sdrh PRAGMA integrity_check; 1028a9789b6Sdrh } 103721dfcf5Sdrh} {{} 20 t1a {6 1} t1b {20 1} ok} 1048a9789b6Sdrh 1058a9789b6Sdrhdo_test index6-1.12 { 1068a9789b6Sdrh execsql { 1078a9789b6Sdrh UPDATE t1 SET a=CASE WHEN b%3!=0 THEN b END; 1088a9789b6Sdrh UPDATE t1 SET b=b-100; 1098a9789b6Sdrh ANALYZE; 1108a9789b6Sdrh SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; 1118a9789b6Sdrh PRAGMA integrity_check; 1128a9789b6Sdrh } 113721dfcf5Sdrh} {{} 20 t1a {13 1} t1b {10 1} ok} 1148a9789b6Sdrh 1158a9789b6Sdrhdo_test index6-1.13 { 1168a9789b6Sdrh execsql { 1178a9789b6Sdrh DELETE FROM t1 WHERE b BETWEEN 8 AND 12; 1188a9789b6Sdrh ANALYZE; 1198a9789b6Sdrh SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; 1208a9789b6Sdrh PRAGMA integrity_check; 1218a9789b6Sdrh } 122721dfcf5Sdrh} {{} 15 t1a {10 1} t1b {8 1} ok} 1238a9789b6Sdrh 1248a9789b6Sdrhdo_test index6-1.14 { 1258a9789b6Sdrh execsql { 1268a9789b6Sdrh REINDEX; 1278a9789b6Sdrh ANALYZE; 1288a9789b6Sdrh SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; 1298a9789b6Sdrh PRAGMA integrity_check; 1308a9789b6Sdrh } 131721dfcf5Sdrh} {{} 15 t1a {10 1} t1b {8 1} ok} 132721dfcf5Sdrh 133721dfcf5Sdrhdo_test index6-1.15 { 134721dfcf5Sdrh execsql { 135721dfcf5Sdrh CREATE INDEX t1c ON t1(c); 136721dfcf5Sdrh ANALYZE; 137721dfcf5Sdrh SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; 138721dfcf5Sdrh PRAGMA integrity_check; 139721dfcf5Sdrh } 140721dfcf5Sdrh} {t1a {10 1} t1b {8 1} t1c {15 1} ok} 1413780be11Sdrh 14266518ca7Sdrh# Queries use partial indices as appropriate times. 14366518ca7Sdrh# 14466518ca7Sdrhdo_test index6-2.1 { 14566518ca7Sdrh execsql { 14666518ca7Sdrh CREATE TABLE t2(a,b); 14766518ca7Sdrh INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000; 1487de2a1faSdan UPDATE t2 SET a=NULL WHERE b%2==0; 14966518ca7Sdrh CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL; 15066518ca7Sdrh SELECT count(*) FROM t2 WHERE a IS NOT NULL; 15166518ca7Sdrh } 1527de2a1faSdan} {500} 15366518ca7Sdrhdo_test index6-2.2 { 15466518ca7Sdrh execsql { 15566518ca7Sdrh EXPLAIN QUERY PLAN 15666518ca7Sdrh SELECT * FROM t2 WHERE a=5; 15766518ca7Sdrh } 15866518ca7Sdrh} {/.* TABLE t2 USING INDEX t2a1 .*/} 1598ad169abSdanifcapable stat4||stat3 { 1607de2a1faSdan execsql ANALYZE 1613d407598Sdan do_test index6-2.3stat4 { 16266518ca7Sdrh execsql { 16366518ca7Sdrh EXPLAIN QUERY PLAN 16466518ca7Sdrh SELECT * FROM t2 WHERE a IS NOT NULL; 16566518ca7Sdrh } 16666518ca7Sdrh } {/.* TABLE t2 USING INDEX t2a1 .*/} 1679fe809c5Sdrh} else { 1683d407598Sdan do_test index6-2.3stat4 { 1699fe809c5Sdrh execsql { 1709fe809c5Sdrh EXPLAIN QUERY PLAN 1719fe809c5Sdrh SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; 1729fe809c5Sdrh } 1739fe809c5Sdrh } {/.* TABLE t2 USING INDEX t2a1 .*/} 1749fe809c5Sdrh} 17566518ca7Sdrhdo_test index6-2.4 { 17666518ca7Sdrh execsql { 17766518ca7Sdrh EXPLAIN QUERY PLAN 17866518ca7Sdrh SELECT * FROM t2 WHERE a IS NULL; 17966518ca7Sdrh } 18066518ca7Sdrh} {~/.*INDEX t2a1.*/} 18166518ca7Sdrh 18266518ca7Sdrhdo_execsql_test index6-2.101 { 18366518ca7Sdrh DROP INDEX t2a1; 18466518ca7Sdrh UPDATE t2 SET a=b, b=b+10000; 18566518ca7Sdrh SELECT b FROM t2 WHERE a=15; 18666518ca7Sdrh} {10015} 18766518ca7Sdrhdo_execsql_test index6-2.102 { 18866518ca7Sdrh CREATE INDEX t2a2 ON t2(a) WHERE a<100 OR a>200; 18966518ca7Sdrh SELECT b FROM t2 WHERE a=15; 19066518ca7Sdrh PRAGMA integrity_check; 19166518ca7Sdrh} {10015 ok} 19266518ca7Sdrhdo_execsql_test index6-2.102eqp { 19366518ca7Sdrh EXPLAIN QUERY PLAN 19466518ca7Sdrh SELECT b FROM t2 WHERE a=15; 19566518ca7Sdrh} {~/.*INDEX t2a2.*/} 19666518ca7Sdrhdo_execsql_test index6-2.103 { 19766518ca7Sdrh SELECT b FROM t2 WHERE a=15 AND a<100; 19866518ca7Sdrh} {10015} 19966518ca7Sdrhdo_execsql_test index6-2.103eqp { 20066518ca7Sdrh EXPLAIN QUERY PLAN 20166518ca7Sdrh SELECT b FROM t2 WHERE a=15 AND a<100; 20266518ca7Sdrh} {/.*INDEX t2a2.*/} 20366518ca7Sdrhdo_execsql_test index6-2.104 { 20466518ca7Sdrh SELECT b FROM t2 WHERE a=515 AND a>200; 20566518ca7Sdrh} {10515} 20666518ca7Sdrhdo_execsql_test index6-2.104eqp { 20766518ca7Sdrh EXPLAIN QUERY PLAN 20866518ca7Sdrh SELECT b FROM t2 WHERE a=515 AND a>200; 20966518ca7Sdrh} {/.*INDEX t2a2.*/} 21066518ca7Sdrh 21166518ca7Sdrh# Partial UNIQUE indices 21266518ca7Sdrh# 21366518ca7Sdrhdo_execsql_test index6-3.1 { 21466518ca7Sdrh CREATE TABLE t3(a,b); 21566518ca7Sdrh INSERT INTO t3 SELECT value, value FROM nums WHERE value<200; 21666518ca7Sdrh UPDATE t3 SET a=999 WHERE b%5!=0; 21766518ca7Sdrh CREATE UNIQUE INDEX t3a ON t3(a) WHERE a<>999; 21866518ca7Sdrh} {} 21966518ca7Sdrhdo_test index6-3.2 { 22066518ca7Sdrh # unable to insert a duplicate row a-value that is not 999. 22166518ca7Sdrh catchsql { 22266518ca7Sdrh INSERT INTO t3(a,b) VALUES(150, 'test1'); 22366518ca7Sdrh } 224f9c8ce3cSdrh} {1 {UNIQUE constraint failed: t3.a}} 22566518ca7Sdrhdo_test index6-3.3 { 22666518ca7Sdrh # can insert multiple rows with a==999 because such rows are not 22766518ca7Sdrh # part of the unique index. 22866518ca7Sdrh catchsql { 22966518ca7Sdrh INSERT INTO t3(a,b) VALUES(999, 'test1'), (999, 'test2'); 23066518ca7Sdrh } 23166518ca7Sdrh} {0 {}} 23266518ca7Sdrhdo_execsql_test index6-3.4 { 23366518ca7Sdrh SELECT count(*) FROM t3 WHERE a=999; 23466518ca7Sdrh} {162} 23566518ca7Sdrhintegrity_check index6-3.5 23666518ca7Sdrh 2373bf0ac17Sdrhdo_execsql_test index6-4.0 { 2383bf0ac17Sdrh VACUUM; 2393bf0ac17Sdrh PRAGMA integrity_check; 2403bf0ac17Sdrh} {ok} 2413bf0ac17Sdrh 2421e7d43c9Sdrh# Silently ignore database name qualifiers in partial indices. 2431e7d43c9Sdrh# 2441e7d43c9Sdrhdo_execsql_test index6-5.0 { 2451e7d43c9Sdrh CREATE INDEX t3b ON t3(b) WHERE xyzzy.t3.b BETWEEN 5 AND 10; 2461e7d43c9Sdrh /* ^^^^^-- ignored */ 2471e7d43c9Sdrh ANALYZE; 2481e7d43c9Sdrh SELECT count(*) FROM t3 WHERE t3.b BETWEEN 5 AND 10; 2491e7d43c9Sdrh SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b'; 2501e7d43c9Sdrh} {6 6} 2511e7d43c9Sdrh 25287744513Sdrh# Test case for ticket [2ea3e9fe6379fc3f6ce7e090ce483c1a3a80d6c9] from 25387744513Sdrh# 2014-04-13: Partial index causes assertion fault on UPDATE OR REPLACE. 25487744513Sdrh# 25587744513Sdrhdo_execsql_test index6-6.0 { 25687744513Sdrh CREATE TABLE t6(a,b); 25787744513Sdrh CREATE UNIQUE INDEX t6ab ON t1(a,b); 25887744513Sdrh CREATE INDEX t6b ON t6(b) WHERE b=1; 25987744513Sdrh INSERT INTO t6(a,b) VALUES(123,456); 26087744513Sdrh SELECT * FROM t6; 26187744513Sdrh} {123 456} 26287744513Sdrhdo_execsql_test index6-6.1 { 26387744513Sdrh UPDATE OR REPLACE t6 SET b=789; 26487744513Sdrh SELECT * FROM t6; 26587744513Sdrh} {123 789} 26687744513Sdrhdo_execsql_test index6-6.2 { 26787744513Sdrh PRAGMA integrity_check; 26887744513Sdrh} {ok} 26987744513Sdrh 270e006a866Sdrh# Test case for ticket [2326c258d02ead33d69faa63de8f4686b9b1b9d9] on 271e006a866Sdrh# 2015-02-24. Any use of a partial index qualifying constraint inside 272e006a866Sdrh# the ON clause of a LEFT JOIN was causing incorrect results for all 273e006a866Sdrh# versions of SQLite 3.8.0 through 3.8.8. 274e006a866Sdrh# 275e006a866Sdrhdo_execsql_test index6-7.0 { 276e006a866Sdrh CREATE TABLE t7a(x); 277e006a866Sdrh CREATE TABLE t7b(y); 278e006a866Sdrh INSERT INTO t7a(x) VALUES(1); 279e006a866Sdrh CREATE INDEX t7ax ON t7a(x) WHERE x=99; 280e006a866Sdrh PRAGMA automatic_index=OFF; 281e006a866Sdrh SELECT * FROM t7a LEFT JOIN t7b ON (x=99) ORDER BY x; 282e006a866Sdrh} {1 {}} 283e006a866Sdrhdo_execsql_test index6-7.1 { 284e006a866Sdrh INSERT INTO t7b(y) VALUES(2); 285e006a866Sdrh SELECT * FROM t7a JOIN t7b ON (x=99) ORDER BY x; 286e006a866Sdrh} {} 287e006a866Sdrhdo_execsql_test index6-7.2 { 288e006a866Sdrh INSERT INTO t7a(x) VALUES(99); 289e006a866Sdrh SELECT * FROM t7a LEFT JOIN t7b ON (x=99) ORDER BY x; 290e006a866Sdrh} {1 {} 99 2} 291e006a866Sdrhdo_execsql_test index6-7.3 { 292e006a866Sdrh SELECT * FROM t7a JOIN t7b ON (x=99) ORDER BY x; 293e006a866Sdrh} {99 2} 294e006a866Sdrhdo_execsql_test index6-7.4 { 295e006a866Sdrh EXPLAIN QUERY PLAN 296e006a866Sdrh SELECT * FROM t7a JOIN t7b ON (x=99) ORDER BY x; 297e006a866Sdrh} {/USING COVERING INDEX t7ax/} 29887744513Sdrh 2992a45cb5cSdan 3002a45cb5cSdando_execsql_test index6-8.0 { 3012a45cb5cSdan CREATE TABLE t8a(a,b); 3022a45cb5cSdan CREATE TABLE t8b(x,y); 3032a45cb5cSdan CREATE INDEX i8c ON t8b(y) WHERE x = 'value'; 3042a45cb5cSdan 3052a45cb5cSdan INSERT INTO t8a VALUES(1, 'one'); 3062a45cb5cSdan INSERT INTO t8a VALUES(2, 'two'); 3072a45cb5cSdan INSERT INTO t8a VALUES(3, 'three'); 3082a45cb5cSdan 3092a45cb5cSdan INSERT INTO t8b VALUES('value', 1); 3102a45cb5cSdan INSERT INTO t8b VALUES('dummy', 2); 3112a45cb5cSdan INSERT INTO t8b VALUES('value', 3); 3122a45cb5cSdan INSERT INTO t8b VALUES('dummy', 4); 3132a45cb5cSdan} {} 3142a45cb5cSdan 3152a45cb5cSdando_eqp_test index6-8.1 { 3162a45cb5cSdan SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) 3172a45cb5cSdan} { 3182a45cb5cSdan 0 0 0 {SCAN TABLE t8a} 3192a45cb5cSdan 0 1 1 {SEARCH TABLE t8b USING INDEX i8c (y=?)} 3202a45cb5cSdan} 3212a45cb5cSdan 3222a45cb5cSdando_execsql_test index6-8.2 { 3232a45cb5cSdan SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) 3242a45cb5cSdan} { 3252a45cb5cSdan 1 one value 1 3262a45cb5cSdan 2 two {} {} 3272a45cb5cSdan 3 three value 3 3282a45cb5cSdan} 3292a45cb5cSdan 33072bc8208Sdrh# 2015-06-11. Assertion fault found by AFL 33172bc8208Sdrh# 33272bc8208Sdrhdo_execsql_test index6-9.1 { 33372bc8208Sdrh CREATE TABLE t9(a int, b int, c int); 33472bc8208Sdrh CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20); 33572bc8208Sdrh INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5),(NULL,7,3); 33672bc8208Sdrh UPDATE t9 SET b=c WHERE a in (10,12,20); 33772bc8208Sdrh SELECT a,b,c,'|' FROM t9 ORDER BY a; 33872bc8208Sdrh} {{} 7 3 | 1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |} 33972bc8208Sdrhdo_execsql_test index6-9.2 { 34072bc8208Sdrh DROP TABLE t9; 34172bc8208Sdrh CREATE TABLE t9(a int, b int, c int, PRIMARY KEY(a)) WITHOUT ROWID; 34272bc8208Sdrh CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20); 34372bc8208Sdrh INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5); 34472bc8208Sdrh UPDATE t9 SET b=c WHERE a in (10,12,20); 34572bc8208Sdrh SELECT a,b,c,'|' FROM t9 ORDER BY a; 34672bc8208Sdrh} {1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |} 34772bc8208Sdrh 348*cf599b6aSdrh# AND-connected terms in the WHERE clause of a partial index 349*cf599b6aSdrh# 350*cf599b6aSdrhdo_execsql_test index6-10.1 { 351*cf599b6aSdrh CREATE TABLE t10(a,b,c,d,e INTEGER PRIMARY KEY); 352*cf599b6aSdrh INSERT INTO t10 VALUES 353*cf599b6aSdrh (1,2,3,4,5), 354*cf599b6aSdrh (2,3,4,5,6), 355*cf599b6aSdrh (3,4,5,6,7), 356*cf599b6aSdrh (1,2,3,8,9); 357*cf599b6aSdrh CREATE INDEX t10x ON t10(d) WHERE a=1 AND b=2 AND c=3; 358*cf599b6aSdrh SELECT e FROM t10 WHERE a=1 AND b=2 AND c=3 ORDER BY d; 359*cf599b6aSdrh} {5 9} 360*cf599b6aSdrhdo_execsql_test index6-10.1eqp { 361*cf599b6aSdrh EXPLAIN QUERY PLAN 362*cf599b6aSdrh SELECT e FROM t10 WHERE a=1 AND b=2 AND c=3 ORDER BY d; 363*cf599b6aSdrh} {/USING INDEX t10x/} 364*cf599b6aSdrhdo_execsql_test index6-10.2 { 365*cf599b6aSdrh SELECT e FROM t10 WHERE c=3 AND 2=b AND a=1 ORDER BY d DESC; 366*cf599b6aSdrh} {9 5} 367*cf599b6aSdrhdo_execsql_test index6-10.2eqp { 368*cf599b6aSdrh EXPLAIN QUERY PLAN 369*cf599b6aSdrh SELECT e FROM t10 WHERE c=3 AND 2=b AND a=1 ORDER BY d DESC; 370*cf599b6aSdrh} {/USING INDEX t10x/} 371*cf599b6aSdrhdo_execsql_test index6-10.3 { 372*cf599b6aSdrh SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; 373*cf599b6aSdrh} {9 5} 374*cf599b6aSdrhdo_execsql_test index6-10.3eqp { 375*cf599b6aSdrh EXPLAIN QUERY PLAN 376*cf599b6aSdrh SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; 377*cf599b6aSdrh} {~/USING INDEX t10x/} 37872bc8208Sdrh 3791fe0537eSdrhfinish_test 380