| 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  |  | 
|   17 # Create a schema with some indexes. |  | 
|   18 # |  | 
|   19 do_test indexedby-1.1 { |  | 
|   20   execsql { |  | 
|   21     CREATE TABLE t1(a, b); |  | 
|   22     CREATE INDEX i1 ON t1(a); |  | 
|   23     CREATE INDEX i2 ON t1(b); |  | 
|   24  |  | 
|   25     CREATE TABLE t2(c, d); |  | 
|   26     CREATE INDEX i3 ON t2(c); |  | 
|   27     CREATE INDEX i4 ON t2(d); |  | 
|   28  |  | 
|   29     CREATE TABLE t3(e PRIMARY KEY, f); |  | 
|   30  |  | 
|   31     CREATE VIEW v1 AS SELECT * FROM t1; |  | 
|   32   } |  | 
|   33 } {} |  | 
|   34  |  | 
|   35 # Explain Query Plan |  | 
|   36 # |  | 
|   37 proc EQP {sql} { |  | 
|   38   uplevel "execsql {EXPLAIN QUERY PLAN $sql}" |  | 
|   39 } |  | 
|   40  |  | 
|   41 # These tests are to check that "EXPLAIN QUERY PLAN" is working as expected. |  | 
|   42 # |  | 
|   43 do_test indexedby-1.2 { |  | 
|   44   EQP { select * from t1 WHERE a = 10; } |  | 
|   45 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|   46 do_test indexedby-1.3 { |  | 
|   47   EQP { select * from t1 ; } |  | 
|   48 } {0 0 {TABLE t1}} |  | 
|   49 do_test indexedby-1.4 { |  | 
|   50   EQP { select * from t1, t2 WHERE c = 10; } |  | 
|   51 } {0 1 {TABLE t2 WITH INDEX i3} 1 0 {TABLE t1}} |  | 
|   52  |  | 
|   53 # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be  |  | 
|   54 # attached to a table in the FROM clause, but not to a sub-select or |  | 
|   55 # SQL view. Also test that specifying an index that does not exist or |  | 
|   56 # is attached to a different table is detected as an error. |  | 
|   57 #  |  | 
|   58 do_test indexedby-2.1 { |  | 
|   59   execsql { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'} |  | 
|   60 } {} |  | 
|   61 do_test indexedby-2.2 { |  | 
|   62   execsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'} |  | 
|   63 } {} |  | 
|   64 do_test indexedby-2.3 { |  | 
|   65   execsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'} |  | 
|   66 } {} |  | 
|   67  |  | 
|   68 do_test indexedby-2.4 { |  | 
|   69   catchsql { SELECT * FROM t1 INDEXED BY i3 WHERE a = 'one' AND b = 'two'} |  | 
|   70 } {1 {no such index: i3}} |  | 
|   71 do_test indexedby-2.5 { |  | 
|   72   catchsql { SELECT * FROM t1 INDEXED BY i5 WHERE a = 'one' AND b = 'two'} |  | 
|   73 } {1 {no such index: i5}} |  | 
|   74 do_test indexedby-2.6 { |  | 
|   75   catchsql { SELECT * FROM t1 INDEXED BY WHERE a = 'one' AND b = 'two'} |  | 
|   76 } {1 {near "WHERE": syntax error}} |  | 
|   77 do_test indexedby-2.7 { |  | 
|   78   catchsql { SELECT * FROM v1 INDEXED BY i1 WHERE a = 'one' } |  | 
|   79 } {1 {no such index: i1}} |  | 
|   80  |  | 
|   81 # Tests for single table cases. |  | 
|   82 # |  | 
|   83 do_test indexedby-3.1 { |  | 
|   84   EQP { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'} |  | 
|   85 } {0 0 {TABLE t1}} |  | 
|   86 do_test indexedby-3.2 { |  | 
|   87   EQP { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'} |  | 
|   88 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|   89 do_test indexedby-3.3 { |  | 
|   90   EQP { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'} |  | 
|   91 } {0 0 {TABLE t1 WITH INDEX i2}} |  | 
|   92 do_test indexedby-3.4 { |  | 
|   93   catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } |  | 
|   94 } {1 {cannot use index: i2}} |  | 
|   95 do_test indexedby-3.5 { |  | 
|   96   catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a } |  | 
|   97 } {1 {cannot use index: i2}} |  | 
|   98 do_test indexedby-3.6 { |  | 
|   99   catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' } |  | 
|  100 } {0 {}} |  | 
|  101 do_test indexedby-3.7 { |  | 
|  102   catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a } |  | 
|  103 } {0 {}} |  | 
|  104  |  | 
|  105 do_test indexedby-3.8 { |  | 
|  106   EQP { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e } |  | 
|  107 } {0 0 {TABLE t3 WITH INDEX sqlite_autoindex_t3_1 ORDER BY}} |  | 
|  108 do_test indexedby-3.9 { |  | 
|  109   EQP { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 } |  | 
|  110 } {0 0 {TABLE t3 WITH INDEX sqlite_autoindex_t3_1}} |  | 
|  111 do_test indexedby-3.10 { |  | 
|  112   catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } |  | 
|  113 } {1 {cannot use index: sqlite_autoindex_t3_1}} |  | 
|  114 do_test indexedby-3.11 { |  | 
|  115   catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 } |  | 
|  116 } {1 {no such index: sqlite_autoindex_t3_2}} |  | 
|  117  |  | 
|  118 # Tests for multiple table cases. |  | 
|  119 # |  | 
|  120 do_test indexedby-4.1 { |  | 
|  121   EQP { SELECT * FROM t1, t2 WHERE a = c } |  | 
|  122 } {0 0 {TABLE t1} 1 1 {TABLE t2 WITH INDEX i3}} |  | 
|  123 do_test indexedby-4.2 { |  | 
|  124   EQP { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } |  | 
|  125 } {0 1 {TABLE t2} 1 0 {TABLE t1 WITH INDEX i1}} |  | 
|  126  |  | 
|  127 # Test embedding an INDEXED BY in a CREATE VIEW statement. This block |  | 
|  128 # also tests that nothing bad happens if an index refered to by |  | 
|  129 # a CREATE VIEW statement is dropped and recreated. |  | 
|  130 # |  | 
|  131 do_test indexedby-5.1 { |  | 
|  132   execsql { |  | 
|  133     CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; |  | 
|  134   } |  | 
|  135   EQP { SELECT * FROM v2 } |  | 
|  136 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  137 do_test indexedby-5.2 { |  | 
|  138   EQP { SELECT * FROM v2 WHERE b = 10 } |  | 
|  139 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  140 do_test indexedby-5.3 { |  | 
|  141   execsql { DROP INDEX i1 } |  | 
|  142   catchsql { SELECT * FROM v2 } |  | 
|  143 } {1 {no such index: i1}} |  | 
|  144 do_test indexedby-5.4 { |  | 
|  145   # Recreate index i1 in such a way as it cannot be used by the view query. |  | 
|  146   execsql { CREATE INDEX i1 ON t1(b) } |  | 
|  147   catchsql { SELECT * FROM v2 } |  | 
|  148 } {1 {cannot use index: i1}} |  | 
|  149 do_test indexedby-5.5 { |  | 
|  150   # Drop and recreate index i1 again. This time, create it so that it can |  | 
|  151   # be used by the query. |  | 
|  152   execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) } |  | 
|  153   catchsql { SELECT * FROM v2 } |  | 
|  154 } {0 {}} |  | 
|  155  |  | 
|  156 # Test that "NOT INDEXED" may use the rowid index, but not others. |  | 
|  157 #  |  | 
|  158 do_test indexedby-6.1 { |  | 
|  159   EQP { SELECT * FROM t1 WHERE b = 10 ORDER BY rowid } |  | 
|  160 } {0 0 {TABLE t1 WITH INDEX i2 ORDER BY}} |  | 
|  161 do_test indexedby-6.2 { |  | 
|  162   EQP { SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid } |  | 
|  163 } {0 0 {TABLE t1 USING PRIMARY KEY ORDER BY}} |  | 
|  164  |  | 
|  165 # Test that "INDEXED BY" can be used in a DELETE statement. |  | 
|  166 #  |  | 
|  167 do_test indexedby-7.1 { |  | 
|  168   EQP { DELETE FROM t1 WHERE a = 5 } |  | 
|  169 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  170 do_test indexedby-7.2 { |  | 
|  171   EQP { DELETE FROM t1 NOT INDEXED WHERE a = 5 } |  | 
|  172 } {0 0 {TABLE t1}} |  | 
|  173 do_test indexedby-7.3 { |  | 
|  174   EQP { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 } |  | 
|  175 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  176 do_test indexedby-7.4 { |  | 
|  177   EQP { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10} |  | 
|  178 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  179 do_test indexedby-7.5 { |  | 
|  180   EQP { DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10} |  | 
|  181 } {0 0 {TABLE t1 WITH INDEX i2}} |  | 
|  182 do_test indexedby-7.6 { |  | 
|  183   catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} |  | 
|  184 } {1 {cannot use index: i2}} |  | 
|  185  |  | 
|  186 # Test that "INDEXED BY" can be used in an UPDATE statement. |  | 
|  187 #  |  | 
|  188 do_test indexedby-8.1 { |  | 
|  189   EQP { UPDATE t1 SET rowid=rowid+1 WHERE a = 5 } |  | 
|  190 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  191 do_test indexedby-8.2 { |  | 
|  192   EQP { UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 } |  | 
|  193 } {0 0 {TABLE t1}} |  | 
|  194 do_test indexedby-8.3 { |  | 
|  195   EQP { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 } |  | 
|  196 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  197 do_test indexedby-8.4 { |  | 
|  198   EQP { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10} |  | 
|  199 } {0 0 {TABLE t1 WITH INDEX i1}} |  | 
|  200 do_test indexedby-8.5 { |  | 
|  201   EQP { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10} |  | 
|  202 } {0 0 {TABLE t1 WITH INDEX i2}} |  | 
|  203 do_test indexedby-8.6 { |  | 
|  204   catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} |  | 
|  205 } {1 {cannot use index: i2}} |  | 
|  206  |  | 
|  207 # Test that bug #3560 is fixed. |  | 
|  208 # |  | 
|  209 do_test indexedby-9.1 { |  | 
|  210   execsql { |  | 
|  211     CREATE TABLE maintable( id integer); |  | 
|  212     CREATE TABLE joinme(id_int integer, id_text text); |  | 
|  213     CREATE INDEX joinme_id_text_idx on joinme(id_text); |  | 
|  214     CREATE INDEX joinme_id_int_idx on joinme(id_int); |  | 
|  215   } |  | 
|  216 } {} |  | 
|  217 do_test indexedby-9.2 { |  | 
|  218   catchsql { |  | 
|  219     select * from maintable as m inner join |  | 
|  220     joinme as j indexed by joinme_id_text_idx |  | 
|  221     on ( m.id  = j.id_int) |  | 
|  222   } |  | 
|  223 } {1 {cannot use index: joinme_id_text_idx}} |  | 
|  224 do_test indexedby-9.3 { |  | 
|  225   catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx } |  | 
|  226 } {1 {cannot use index: joinme_id_text_idx}} |  | 
|  227  |  | 
|  228 # Make sure we can still create tables, indices, and columns whose name |  | 
|  229 # is "indexed". |  | 
|  230 # |  | 
|  231 do_test indexedby-10.1 { |  | 
|  232   execsql { |  | 
|  233     CREATE TABLE indexed(x,y); |  | 
|  234     INSERT INTO indexed VALUES(1,2); |  | 
|  235     SELECT * FROM indexed; |  | 
|  236   } |  | 
|  237 } {1 2} |  | 
|  238 do_test indexedby-10.2 { |  | 
|  239   execsql { |  | 
|  240     CREATE INDEX i10 ON indexed(x); |  | 
|  241     SELECT * FROM indexed indexed by i10 where x>0; |  | 
|  242   } |  | 
|  243 } {1 2} |  | 
|  244 do_test indexedby-10.3 { |  | 
|  245   execsql { |  | 
|  246     DROP TABLE indexed; |  | 
|  247     CREATE TABLE t10(indexed INTEGER); |  | 
|  248     INSERT INTO t10 VALUES(1); |  | 
|  249     CREATE INDEX indexed ON t10(indexed); |  | 
|  250     SELECT * FROM t10 indexed by indexed WHERE indexed>0 |  | 
|  251   } |  | 
|  252 } {1} |  | 
|  253  |  | 
|  254 finish_test |  | 
| OLD | NEW |