| OLD | NEW |
| (Empty) |
| 1 # 2008 October 4 | |
| 2 # | |
| 3 # The author disclaims copyright to this source code. In place of | |
| 4 # a legal notice, here is a blessing: | |
| 5 # | |
| 6 # May you do good and not evil. | |
| 7 # May you find forgiveness for yourself and forgive others. | |
| 8 # May you share freely, never taking more than you give. | |
| 9 # | |
| 10 #*********************************************************************** | |
| 11 # | |
| 12 # $Id: indexedby.test,v 1.5 2009/03/22 20:36:19 drh Exp $ | |
| 13 | |
| 14 set testdir [file dirname $argv0] | |
| 15 source $testdir/tester.tcl | |
| 16 set ::testprefix indexedby | |
| 17 | |
| 18 # Create a schema with some indexes. | |
| 19 # | |
| 20 do_test indexedby-1.1 { | |
| 21 execsql { | |
| 22 CREATE TABLE t1(a, b); | |
| 23 CREATE INDEX i1 ON t1(a); | |
| 24 CREATE INDEX i2 ON t1(b); | |
| 25 | |
| 26 CREATE TABLE t2(c, d); | |
| 27 CREATE INDEX i3 ON t2(c); | |
| 28 CREATE INDEX i4 ON t2(d); | |
| 29 | |
| 30 CREATE TABLE t3(e PRIMARY KEY, f); | |
| 31 | |
| 32 CREATE VIEW v1 AS SELECT * FROM t1; | |
| 33 } | |
| 34 } {} | |
| 35 | |
| 36 # Explain Query Plan | |
| 37 # | |
| 38 proc EQP {sql} { | |
| 39 uplevel "execsql {EXPLAIN QUERY PLAN $sql}" | |
| 40 } | |
| 41 | |
| 42 # These tests are to check that "EXPLAIN QUERY PLAN" is working as expected. | |
| 43 # | |
| 44 do_execsql_test indexedby-1.2 { | |
| 45 EXPLAIN QUERY PLAN select * from t1 WHERE a = 10; | |
| 46 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} | |
| 47 do_execsql_test indexedby-1.3 { | |
| 48 EXPLAIN QUERY PLAN select * from t1 ; | |
| 49 } {0 0 0 {SCAN TABLE t1}} | |
| 50 do_execsql_test indexedby-1.4 { | |
| 51 EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10; | |
| 52 } { | |
| 53 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} | |
| 54 0 1 0 {SCAN TABLE t1} | |
| 55 } | |
| 56 | |
| 57 # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be | |
| 58 # attached to a table in the FROM clause, but not to a sub-select or | |
| 59 # SQL view. Also test that specifying an index that does not exist or | |
| 60 # is attached to a different table is detected as an error. | |
| 61 # | |
| 62 do_test indexedby-2.1 { | |
| 63 execsql { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'} | |
| 64 } {} | |
| 65 do_test indexedby-2.2 { | |
| 66 execsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'} | |
| 67 } {} | |
| 68 do_test indexedby-2.3 { | |
| 69 execsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'} | |
| 70 } {} | |
| 71 | |
| 72 do_test indexedby-2.4 { | |
| 73 catchsql { SELECT * FROM t1 INDEXED BY i3 WHERE a = 'one' AND b = 'two'} | |
| 74 } {1 {no such index: i3}} | |
| 75 do_test indexedby-2.5 { | |
| 76 catchsql { SELECT * FROM t1 INDEXED BY i5 WHERE a = 'one' AND b = 'two'} | |
| 77 } {1 {no such index: i5}} | |
| 78 do_test indexedby-2.6 { | |
| 79 catchsql { SELECT * FROM t1 INDEXED BY WHERE a = 'one' AND b = 'two'} | |
| 80 } {1 {near "WHERE": syntax error}} | |
| 81 do_test indexedby-2.7 { | |
| 82 catchsql { SELECT * FROM v1 INDEXED BY i1 WHERE a = 'one' } | |
| 83 } {1 {no such index: i1}} | |
| 84 | |
| 85 # Tests for single table cases. | |
| 86 # | |
| 87 do_execsql_test indexedby-3.1 { | |
| 88 EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' | |
| 89 } {0 0 0 {SCAN TABLE t1}} | |
| 90 do_execsql_test indexedby-3.2 { | |
| 91 EXPLAIN QUERY PLAN | |
| 92 SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' | |
| 93 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} | |
| 94 do_execsql_test indexedby-3.3 { | |
| 95 EXPLAIN QUERY PLAN | |
| 96 SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' | |
| 97 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} | |
| 98 do_test indexedby-3.4 { | |
| 99 catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } | |
| 100 } {1 {no query solution}} | |
| 101 do_test indexedby-3.5 { | |
| 102 catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a } | |
| 103 } {1 {no query solution}} | |
| 104 do_test indexedby-3.6 { | |
| 105 catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' } | |
| 106 } {0 {}} | |
| 107 do_test indexedby-3.7 { | |
| 108 catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a } | |
| 109 } {0 {}} | |
| 110 | |
| 111 do_execsql_test indexedby-3.8 { | |
| 112 EXPLAIN QUERY PLAN | |
| 113 SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e | |
| 114 } {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}} | |
| 115 do_execsql_test indexedby-3.9 { | |
| 116 EXPLAIN QUERY PLAN | |
| 117 SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 | |
| 118 } {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}} | |
| 119 do_test indexedby-3.10 { | |
| 120 catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } | |
| 121 } {1 {no query solution}} | |
| 122 do_test indexedby-3.11 { | |
| 123 catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 } | |
| 124 } {1 {no such index: sqlite_autoindex_t3_2}} | |
| 125 | |
| 126 # Tests for multiple table cases. | |
| 127 # | |
| 128 do_execsql_test indexedby-4.1 { | |
| 129 EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c | |
| 130 } { | |
| 131 0 0 0 {SCAN TABLE t1} | |
| 132 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} | |
| 133 } | |
| 134 do_execsql_test indexedby-4.2 { | |
| 135 EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c | |
| 136 } { | |
| 137 0 0 1 {SCAN TABLE t2} | |
| 138 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} | |
| 139 } | |
| 140 do_test indexedby-4.3 { | |
| 141 catchsql { | |
| 142 SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c | |
| 143 } | |
| 144 } {1 {no query solution}} | |
| 145 do_test indexedby-4.4 { | |
| 146 catchsql { | |
| 147 SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c | |
| 148 } | |
| 149 } {1 {no query solution}} | |
| 150 | |
| 151 # Test embedding an INDEXED BY in a CREATE VIEW statement. This block | |
| 152 # also tests that nothing bad happens if an index refered to by | |
| 153 # a CREATE VIEW statement is dropped and recreated. | |
| 154 # | |
| 155 do_execsql_test indexedby-5.1 { | |
| 156 CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; | |
| 157 EXPLAIN QUERY PLAN SELECT * FROM v2 | |
| 158 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} | |
| 159 do_execsql_test indexedby-5.2 { | |
| 160 EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 | |
| 161 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} | |
| 162 do_test indexedby-5.3 { | |
| 163 execsql { DROP INDEX i1 } | |
| 164 catchsql { SELECT * FROM v2 } | |
| 165 } {1 {no such index: i1}} | |
| 166 do_test indexedby-5.4 { | |
| 167 # Recreate index i1 in such a way as it cannot be used by the view query. | |
| 168 execsql { CREATE INDEX i1 ON t1(b) } | |
| 169 catchsql { SELECT * FROM v2 } | |
| 170 } {1 {no query solution}} | |
| 171 do_test indexedby-5.5 { | |
| 172 # Drop and recreate index i1 again. This time, create it so that it can | |
| 173 # be used by the query. | |
| 174 execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) } | |
| 175 catchsql { SELECT * FROM v2 } | |
| 176 } {0 {}} | |
| 177 | |
| 178 # Test that "NOT INDEXED" may use the rowid index, but not others. | |
| 179 # | |
| 180 do_execsql_test indexedby-6.1 { | |
| 181 EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid | |
| 182 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} | |
| 183 do_execsql_test indexedby-6.2 { | |
| 184 EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid | |
| 185 } {0 0 0 {SCAN TABLE t1}} | |
| 186 | |
| 187 # Test that "INDEXED BY" can be used in a DELETE statement. | |
| 188 # | |
| 189 do_execsql_test indexedby-7.1 { | |
| 190 EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5 | |
| 191 } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} | |
| 192 do_execsql_test indexedby-7.2 { | |
| 193 EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5 | |
| 194 } {0 0 0 {SCAN TABLE t1}} | |
| 195 do_execsql_test indexedby-7.3 { | |
| 196 EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 | |
| 197 } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} | |
| 198 do_execsql_test indexedby-7.4 { | |
| 199 EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 | |
| 200 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} | |
| 201 do_execsql_test indexedby-7.5 { | |
| 202 EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 | |
| 203 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} | |
| 204 do_test indexedby-7.6 { | |
| 205 catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} | |
| 206 } {1 {no query solution}} | |
| 207 | |
| 208 # Test that "INDEXED BY" can be used in an UPDATE statement. | |
| 209 # | |
| 210 do_execsql_test indexedby-8.1 { | |
| 211 EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5 | |
| 212 } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} | |
| 213 do_execsql_test indexedby-8.2 { | |
| 214 EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 | |
| 215 } {0 0 0 {SCAN TABLE t1}} | |
| 216 do_execsql_test indexedby-8.3 { | |
| 217 EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 | |
| 218 } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} | |
| 219 do_execsql_test indexedby-8.4 { | |
| 220 EXPLAIN QUERY PLAN | |
| 221 UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10 | |
| 222 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} | |
| 223 do_execsql_test indexedby-8.5 { | |
| 224 EXPLAIN QUERY PLAN | |
| 225 UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10 | |
| 226 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} | |
| 227 do_test indexedby-8.6 { | |
| 228 catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} | |
| 229 } {1 {no query solution}} | |
| 230 | |
| 231 # Test that bug #3560 is fixed. | |
| 232 # | |
| 233 do_test indexedby-9.1 { | |
| 234 execsql { | |
| 235 CREATE TABLE maintable( id integer); | |
| 236 CREATE TABLE joinme(id_int integer, id_text text); | |
| 237 CREATE INDEX joinme_id_text_idx on joinme(id_text); | |
| 238 CREATE INDEX joinme_id_int_idx on joinme(id_int); | |
| 239 } | |
| 240 } {} | |
| 241 do_test indexedby-9.2 { | |
| 242 catchsql { | |
| 243 select * from maintable as m inner join | |
| 244 joinme as j indexed by joinme_id_text_idx | |
| 245 on ( m.id = j.id_int) | |
| 246 } | |
| 247 } {1 {no query solution}} | |
| 248 do_test indexedby-9.3 { | |
| 249 catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx } | |
| 250 } {1 {no query solution}} | |
| 251 | |
| 252 # Make sure we can still create tables, indices, and columns whose name | |
| 253 # is "indexed". | |
| 254 # | |
| 255 do_test indexedby-10.1 { | |
| 256 execsql { | |
| 257 CREATE TABLE indexed(x,y); | |
| 258 INSERT INTO indexed VALUES(1,2); | |
| 259 SELECT * FROM indexed; | |
| 260 } | |
| 261 } {1 2} | |
| 262 do_test indexedby-10.2 { | |
| 263 execsql { | |
| 264 CREATE INDEX i10 ON indexed(x); | |
| 265 SELECT * FROM indexed indexed by i10 where x>0; | |
| 266 } | |
| 267 } {1 2} | |
| 268 do_test indexedby-10.3 { | |
| 269 execsql { | |
| 270 DROP TABLE indexed; | |
| 271 CREATE TABLE t10(indexed INTEGER); | |
| 272 INSERT INTO t10 VALUES(1); | |
| 273 CREATE INDEX indexed ON t10(indexed); | |
| 274 SELECT * FROM t10 indexed by indexed WHERE indexed>0 | |
| 275 } | |
| 276 } {1} | |
| 277 | |
| 278 #------------------------------------------------------------------------- | |
| 279 # Ensure that the rowid at the end of each index entry may be used | |
| 280 # for equality constraints in the same way as other indexed fields. | |
| 281 # | |
| 282 do_execsql_test 11.1 { | |
| 283 CREATE TABLE x1(a, b TEXT); | |
| 284 CREATE INDEX x1i ON x1(a, b); | |
| 285 INSERT INTO x1 VALUES(1, 1); | |
| 286 INSERT INTO x1 VALUES(1, 1); | |
| 287 INSERT INTO x1 VALUES(1, 1); | |
| 288 INSERT INTO x1 VALUES(1, 1); | |
| 289 } | |
| 290 do_execsql_test 11.2 { | |
| 291 SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid=3; | |
| 292 } {1 1 3} | |
| 293 do_execsql_test 11.3 { | |
| 294 SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3'; | |
| 295 } {1 1 3} | |
| 296 do_execsql_test 11.4 { | |
| 297 SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; | |
| 298 } {1 1 3} | |
| 299 do_eqp_test 11.5 { | |
| 300 SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; | |
| 301 } {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}} | |
| 302 | |
| 303 do_execsql_test 11.6 { | |
| 304 CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT); | |
| 305 CREATE INDEX x2i ON x2(a, b); | |
| 306 INSERT INTO x2 VALUES(1, 1, 1); | |
| 307 INSERT INTO x2 VALUES(2, 1, 1); | |
| 308 INSERT INTO x2 VALUES(3, 1, 1); | |
| 309 INSERT INTO x2 VALUES(4, 1, 1); | |
| 310 } | |
| 311 do_execsql_test 11.7 { | |
| 312 SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c=3; | |
| 313 } {1 1 3} | |
| 314 do_execsql_test 11.8 { | |
| 315 SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3'; | |
| 316 } {1 1 3} | |
| 317 do_execsql_test 11.9 { | |
| 318 SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; | |
| 319 } {1 1 3} | |
| 320 do_eqp_test 11.10 { | |
| 321 SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; | |
| 322 } {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}} | |
| 323 | |
| 324 finish_test | |
| OLD | NEW |