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