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 40*5f33f375Sdrh# Make sure the count(*) optimization works correctly with 41*5f33f375Sdrh# partial indices. Ticket [a5c8ed66cae16243be6] 2013-10-03. 42*5f33f375Sdrh# 43*5f33f375Sdrhdo_execsql_test index6-1.1.1 { 44*5f33f375Sdrh SELECT count(*) FROM t1; 45*5f33f375Sdrh} {20} 46*5f33f375Sdrh 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; 14866518ca7Sdrh UPDATE t2 SET a=NULL WHERE b%5==0; 14966518ca7Sdrh CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL; 15066518ca7Sdrh SELECT count(*) FROM t2 WHERE a IS NOT NULL; 15166518ca7Sdrh } 15266518ca7Sdrh} {800} 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 { 1603d407598Sdan do_test index6-2.3stat4 { 16166518ca7Sdrh execsql { 16266518ca7Sdrh EXPLAIN QUERY PLAN 16366518ca7Sdrh SELECT * FROM t2 WHERE a IS NOT NULL; 16466518ca7Sdrh } 16566518ca7Sdrh } {/.* TABLE t2 USING INDEX t2a1 .*/} 1669fe809c5Sdrh} else { 1673d407598Sdan do_test index6-2.3stat4 { 1689fe809c5Sdrh execsql { 1699fe809c5Sdrh EXPLAIN QUERY PLAN 1709fe809c5Sdrh SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; 1719fe809c5Sdrh } 1729fe809c5Sdrh } {/.* TABLE t2 USING INDEX t2a1 .*/} 1739fe809c5Sdrh} 17466518ca7Sdrhdo_test index6-2.4 { 17566518ca7Sdrh execsql { 17666518ca7Sdrh EXPLAIN QUERY PLAN 17766518ca7Sdrh SELECT * FROM t2 WHERE a IS NULL; 17866518ca7Sdrh } 17966518ca7Sdrh} {~/.*INDEX t2a1.*/} 18066518ca7Sdrh 18166518ca7Sdrhdo_execsql_test index6-2.101 { 18266518ca7Sdrh DROP INDEX t2a1; 18366518ca7Sdrh UPDATE t2 SET a=b, b=b+10000; 18466518ca7Sdrh SELECT b FROM t2 WHERE a=15; 18566518ca7Sdrh} {10015} 18666518ca7Sdrhdo_execsql_test index6-2.102 { 18766518ca7Sdrh CREATE INDEX t2a2 ON t2(a) WHERE a<100 OR a>200; 18866518ca7Sdrh SELECT b FROM t2 WHERE a=15; 18966518ca7Sdrh PRAGMA integrity_check; 19066518ca7Sdrh} {10015 ok} 19166518ca7Sdrhdo_execsql_test index6-2.102eqp { 19266518ca7Sdrh EXPLAIN QUERY PLAN 19366518ca7Sdrh SELECT b FROM t2 WHERE a=15; 19466518ca7Sdrh} {~/.*INDEX t2a2.*/} 19566518ca7Sdrhdo_execsql_test index6-2.103 { 19666518ca7Sdrh SELECT b FROM t2 WHERE a=15 AND a<100; 19766518ca7Sdrh} {10015} 19866518ca7Sdrhdo_execsql_test index6-2.103eqp { 19966518ca7Sdrh EXPLAIN QUERY PLAN 20066518ca7Sdrh SELECT b FROM t2 WHERE a=15 AND a<100; 20166518ca7Sdrh} {/.*INDEX t2a2.*/} 20266518ca7Sdrhdo_execsql_test index6-2.104 { 20366518ca7Sdrh SELECT b FROM t2 WHERE a=515 AND a>200; 20466518ca7Sdrh} {10515} 20566518ca7Sdrhdo_execsql_test index6-2.104eqp { 20666518ca7Sdrh EXPLAIN QUERY PLAN 20766518ca7Sdrh SELECT b FROM t2 WHERE a=515 AND a>200; 20866518ca7Sdrh} {/.*INDEX t2a2.*/} 20966518ca7Sdrh 21066518ca7Sdrh# Partial UNIQUE indices 21166518ca7Sdrh# 21266518ca7Sdrhdo_execsql_test index6-3.1 { 21366518ca7Sdrh CREATE TABLE t3(a,b); 21466518ca7Sdrh INSERT INTO t3 SELECT value, value FROM nums WHERE value<200; 21566518ca7Sdrh UPDATE t3 SET a=999 WHERE b%5!=0; 21666518ca7Sdrh CREATE UNIQUE INDEX t3a ON t3(a) WHERE a<>999; 21766518ca7Sdrh} {} 21866518ca7Sdrhdo_test index6-3.2 { 21966518ca7Sdrh # unable to insert a duplicate row a-value that is not 999. 22066518ca7Sdrh catchsql { 22166518ca7Sdrh INSERT INTO t3(a,b) VALUES(150, 'test1'); 22266518ca7Sdrh } 22366518ca7Sdrh} {1 {column a is not unique}} 22466518ca7Sdrhdo_test index6-3.3 { 22566518ca7Sdrh # can insert multiple rows with a==999 because such rows are not 22666518ca7Sdrh # part of the unique index. 22766518ca7Sdrh catchsql { 22866518ca7Sdrh INSERT INTO t3(a,b) VALUES(999, 'test1'), (999, 'test2'); 22966518ca7Sdrh } 23066518ca7Sdrh} {0 {}} 23166518ca7Sdrhdo_execsql_test index6-3.4 { 23266518ca7Sdrh SELECT count(*) FROM t3 WHERE a=999; 23366518ca7Sdrh} {162} 23466518ca7Sdrhintegrity_check index6-3.5 23566518ca7Sdrh 2363bf0ac17Sdrhdo_execsql_test index6-4.0 { 2373bf0ac17Sdrh VACUUM; 2383bf0ac17Sdrh PRAGMA integrity_check; 2393bf0ac17Sdrh} {ok} 2403bf0ac17Sdrh 2411e7d43c9Sdrh# Silently ignore database name qualifiers in partial indices. 2421e7d43c9Sdrh# 2431e7d43c9Sdrhdo_execsql_test index6-5.0 { 2441e7d43c9Sdrh CREATE INDEX t3b ON t3(b) WHERE xyzzy.t3.b BETWEEN 5 AND 10; 2451e7d43c9Sdrh /* ^^^^^-- ignored */ 2461e7d43c9Sdrh ANALYZE; 2471e7d43c9Sdrh SELECT count(*) FROM t3 WHERE t3.b BETWEEN 5 AND 10; 2481e7d43c9Sdrh SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b'; 2491e7d43c9Sdrh} {6 6} 2501e7d43c9Sdrh 2511fe0537eSdrhfinish_test 252