blob: d4ca515e00ab77174b6746344ad6de8132ea9c52 [file] [log] [blame]
drhb19a2bc2001-09-16 00:13:26 +00001# 2001 September 15
drhb24fcbe2000-05-29 23:30:50 +00002#
drhb19a2bc2001-09-16 00:13:26 +00003# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
drhb24fcbe2000-05-29 23:30:50 +00005#
drhb19a2bc2001-09-16 00:13:26 +00006# 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.
drhb24fcbe2000-05-29 23:30:50 +00009#
10#***********************************************************************
11# This file implements regression tests for SQLite library. The
12# focus of this file is testing the CREATE INDEX statement.
13#
drh485b39b2002-07-13 03:11:52 +000014# $Id: index.test,v 1.18 2002/07/13 03:11:54 drh Exp $
drhb24fcbe2000-05-29 23:30:50 +000015
16set testdir [file dirname $argv0]
17source $testdir/tester.tcl
18
19# Create a basic index and verify it is added to sqlite_master
20#
drh1b6a71f2000-05-29 23:58:11 +000021do_test index-1.1 {
drhb24fcbe2000-05-29 23:30:50 +000022 execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)}
23 execsql {CREATE INDEX index1 ON test1(f1)}
drh28037572000-08-02 13:47:41 +000024 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +000025} {index1 test1}
drh1b6a71f2000-05-29 23:58:11 +000026do_test index-1.1b {
drhb24fcbe2000-05-29 23:30:50 +000027 execsql {SELECT name, sql, tbl_name, type FROM sqlite_master
28 WHERE name='index1'}
29} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index}
drh1b6a71f2000-05-29 23:58:11 +000030do_test index-1.1c {
drhb24fcbe2000-05-29 23:30:50 +000031 db close
drh5edc3122001-09-13 21:53:09 +000032 sqlite db test.db
drhb24fcbe2000-05-29 23:30:50 +000033 execsql {SELECT name, sql, tbl_name, type FROM sqlite_master
34 WHERE name='index1'}
35} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index}
drh1b6a71f2000-05-29 23:58:11 +000036do_test index-1.1d {
drhb24fcbe2000-05-29 23:30:50 +000037 db close
drh5edc3122001-09-13 21:53:09 +000038 sqlite db test.db
drh28037572000-08-02 13:47:41 +000039 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +000040} {index1 test1}
41
42# Verify that the index dies with the table
43#
drh1b6a71f2000-05-29 23:58:11 +000044do_test index-1.2 {
drhb24fcbe2000-05-29 23:30:50 +000045 execsql {DROP TABLE test1}
drh28037572000-08-02 13:47:41 +000046 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +000047} {}
48
49# Try adding an index to a table that does not exist
50#
drh1b6a71f2000-05-29 23:58:11 +000051do_test index-2.1 {
drhb24fcbe2000-05-29 23:30:50 +000052 set v [catch {execsql {CREATE INDEX index1 ON test1(f1)}} msg]
53 lappend v $msg
54} {1 {no such table: test1}}
55
drh1ccde152000-06-17 13:12:39 +000056# Try adding an index on a column of a table where the table
57# exists but the column does not.
drhb24fcbe2000-05-29 23:30:50 +000058#
drh1b6a71f2000-05-29 23:58:11 +000059do_test index-2.1 {
drhb24fcbe2000-05-29 23:30:50 +000060 execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)}
61 set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg]
62 lappend v $msg
drh1ccde152000-06-17 13:12:39 +000063} {1 {table test1 has no column named f4}}
drhb24fcbe2000-05-29 23:30:50 +000064
drh1ccde152000-06-17 13:12:39 +000065# Try an index with some columns that match and others that do now.
drhb24fcbe2000-05-29 23:30:50 +000066#
drh1b6a71f2000-05-29 23:58:11 +000067do_test index-2.2 {
drhb24fcbe2000-05-29 23:30:50 +000068 set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg]
69 execsql {DROP TABLE test1}
70 lappend v $msg
drh1ccde152000-06-17 13:12:39 +000071} {1 {table test1 has no column named f4}}
drhb24fcbe2000-05-29 23:30:50 +000072
73# Try creating a bunch of indices on the same table
74#
75set r {}
76for {set i 1} {$i<100} {incr i} {
77 lappend r index$i
78}
drh1b6a71f2000-05-29 23:58:11 +000079do_test index-3.1 {
drhb24fcbe2000-05-29 23:30:50 +000080 execsql {CREATE TABLE test1(f1 int, f2 int, f3 int, f4 int, f5 int)}
81 for {set i 1} {$i<100} {incr i} {
82 set sql "CREATE INDEX index$i ON test1(f[expr {($i%5)+1}])"
83 execsql $sql
84 }
85 execsql {SELECT name FROM sqlite_master
86 WHERE type='index' AND tbl_name='test1'
87 ORDER BY name}
88} $r
89
drhb24fcbe2000-05-29 23:30:50 +000090
91# Verify that all the indices go away when we drop the table.
92#
drh1b6a71f2000-05-29 23:58:11 +000093do_test index-3.3 {
drhb24fcbe2000-05-29 23:30:50 +000094 execsql {DROP TABLE test1}
95 execsql {SELECT name FROM sqlite_master
96 WHERE type='index' AND tbl_name='test1'
97 ORDER BY name}
98} {}
drhb24fcbe2000-05-29 23:30:50 +000099
100# Create a table and insert values into that table. Then create
101# an index on that table. Verify that we can select values
102# from the table correctly using the index.
103#
drh7020f652000-06-03 18:06:52 +0000104# Note that the index names "index9" and "indext" are chosen because
105# they both have the same hash.
106#
drh1b6a71f2000-05-29 23:58:11 +0000107do_test index-4.1 {
drhb24fcbe2000-05-29 23:30:50 +0000108 execsql {CREATE TABLE test1(cnt int, power int)}
109 for {set i 1} {$i<20} {incr i} {
110 execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])"
111 }
drh7020f652000-06-03 18:06:52 +0000112 execsql {CREATE INDEX index9 ON test1(cnt)}
113 execsql {CREATE INDEX indext ON test1(power)}
drh28037572000-08-02 13:47:41 +0000114 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drh7020f652000-06-03 18:06:52 +0000115} {index9 indext test1}
drh1b6a71f2000-05-29 23:58:11 +0000116do_test index-4.2 {
drhb24fcbe2000-05-29 23:30:50 +0000117 execsql {SELECT cnt FROM test1 WHERE power=4}
118} {2}
drh1b6a71f2000-05-29 23:58:11 +0000119do_test index-4.3 {
drhb24fcbe2000-05-29 23:30:50 +0000120 execsql {SELECT cnt FROM test1 WHERE power=1024}
121} {10}
drh1b6a71f2000-05-29 23:58:11 +0000122do_test index-4.4 {
drhb24fcbe2000-05-29 23:30:50 +0000123 execsql {SELECT power FROM test1 WHERE cnt=6}
124} {64}
drh1b6a71f2000-05-29 23:58:11 +0000125do_test index-4.5 {
drh7020f652000-06-03 18:06:52 +0000126 execsql {DROP INDEX indext}
127 execsql {SELECT power FROM test1 WHERE cnt=6}
128} {64}
129do_test index-4.6 {
130 execsql {SELECT cnt FROM test1 WHERE power=1024}
131} {10}
132do_test index-4.7 {
133 execsql {CREATE INDEX indext ON test1(cnt)}
134 execsql {SELECT power FROM test1 WHERE cnt=6}
135} {64}
136do_test index-4.8 {
137 execsql {SELECT cnt FROM test1 WHERE power=1024}
138} {10}
139do_test index-4.9 {
140 execsql {DROP INDEX index9}
141 execsql {SELECT power FROM test1 WHERE cnt=6}
142} {64}
143do_test index-4.10 {
144 execsql {SELECT cnt FROM test1 WHERE power=1024}
145} {10}
146do_test index-4.11 {
147 execsql {DROP INDEX indext}
148 execsql {SELECT power FROM test1 WHERE cnt=6}
149} {64}
150do_test index-4.12 {
151 execsql {SELECT cnt FROM test1 WHERE power=1024}
152} {10}
153do_test index-4.13 {
drhb24fcbe2000-05-29 23:30:50 +0000154 execsql {DROP TABLE test1}
drh28037572000-08-02 13:47:41 +0000155 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +0000156} {}
157
158# Do not allow indices to be added to sqlite_master
159#
drh1b6a71f2000-05-29 23:58:11 +0000160do_test index-5.1 {
drhb24fcbe2000-05-29 23:30:50 +0000161 set v [catch {execsql {CREATE INDEX index1 ON sqlite_master(name)}} msg]
162 lappend v $msg
163} {1 {table sqlite_master may not have new indices added}}
drh1b6a71f2000-05-29 23:58:11 +0000164do_test index-5.2 {
drh28037572000-08-02 13:47:41 +0000165 execsql {SELECT name FROM sqlite_master WHERE type!='meta'}
drhb24fcbe2000-05-29 23:30:50 +0000166} {}
167
168# Do not allow indices with duplicate names to be added
169#
drh1b6a71f2000-05-29 23:58:11 +0000170do_test index-6.1 {
drhb24fcbe2000-05-29 23:30:50 +0000171 execsql {CREATE TABLE test1(f1 int, f2 int)}
172 execsql {CREATE TABLE test2(g1 real, g2 real)}
173 execsql {CREATE INDEX index1 ON test1(f1)}
174 set v [catch {execsql {CREATE INDEX index1 ON test2(g1)}} msg]
175 lappend v $msg
drh1d37e282000-05-30 03:12:21 +0000176} {1 {index index1 already exists}}
drh1b6a71f2000-05-29 23:58:11 +0000177do_test index-6.1b {
drh28037572000-08-02 13:47:41 +0000178 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +0000179} {index1 test1 test2}
drh1b6a71f2000-05-29 23:58:11 +0000180do_test index-6.2 {
drhb24fcbe2000-05-29 23:30:50 +0000181 set v [catch {execsql {CREATE INDEX test1 ON test2(g1)}} msg]
182 lappend v $msg
drh1d37e282000-05-30 03:12:21 +0000183} {1 {there is already a table named test1}}
drh1b6a71f2000-05-29 23:58:11 +0000184do_test index-6.2b {
drh28037572000-08-02 13:47:41 +0000185 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +0000186} {index1 test1 test2}
drh1b6a71f2000-05-29 23:58:11 +0000187do_test index-6.3 {
drhb24fcbe2000-05-29 23:30:50 +0000188 execsql {DROP TABLE test1}
189 execsql {DROP TABLE test2}
drh28037572000-08-02 13:47:41 +0000190 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +0000191} {}
drhf5bf0a72001-11-23 00:24:12 +0000192do_test index-6.4 {
193 execsql {
194 CREATE TABLE test1(a,b);
195 CREATE INDEX index1 ON test1(a);
196 CREATE INDEX index2 ON test1(b);
197 CREATE INDEX index3 ON test1(a,b);
198 DROP TABLE test1;
199 SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name;
200 }
201} {}
drhb24fcbe2000-05-29 23:30:50 +0000202
203# Create a primary key
204#
drh1b6a71f2000-05-29 23:58:11 +0000205do_test index-7.1 {
drhb24fcbe2000-05-29 23:30:50 +0000206 execsql {CREATE TABLE test1(f1 int, f2 int primary key)}
207 for {set i 1} {$i<20} {incr i} {
208 execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])"
209 }
drh767c2002000-10-19 14:10:08 +0000210 execsql {SELECT count(*) FROM test1}
211} {19}
drh1b6a71f2000-05-29 23:58:11 +0000212do_test index-7.2 {
drhb24fcbe2000-05-29 23:30:50 +0000213 execsql {SELECT f1 FROM test1 WHERE f2=65536}
214} {16}
drh1b6a71f2000-05-29 23:58:11 +0000215do_test index-7.3 {
drhadbca9c2001-09-27 15:11:53 +0000216 execsql {
217 SELECT name FROM sqlite_master
218 WHERE type='index' AND tbl_name='test1'
219 }
220} {{(test1 autoindex 1)}}
drh1b6a71f2000-05-29 23:58:11 +0000221do_test index-7.4 {
222 execsql {DROP table test1}
drh28037572000-08-02 13:47:41 +0000223 execsql {SELECT name FROM sqlite_master WHERE type!='meta'}
drh1b6a71f2000-05-29 23:58:11 +0000224} {}
225
drh7020f652000-06-03 18:06:52 +0000226# Make sure we cannot drop a non-existant index.
drh1b6a71f2000-05-29 23:58:11 +0000227#
228do_test index-8.1 {
229 set v [catch {execsql {DROP INDEX index1}} msg]
230 lappend v $msg
drh1d37e282000-05-30 03:12:21 +0000231} {1 {no such index: index1}}
drh1b6a71f2000-05-29 23:58:11 +0000232
drh7020f652000-06-03 18:06:52 +0000233# Make sure we don't actually create an index when the EXPLAIN keyword
234# is used.
235#
236do_test index-9.1 {
237 execsql {CREATE TABLE tab1(a int)}
238 execsql {EXPLAIN CREATE INDEX idx1 ON tab1(a)}
239 execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1'}
240} {tab1}
241do_test index-9.2 {
242 execsql {CREATE INDEX idx1 ON tab1(a)}
243 execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1' ORDER BY name}
244} {idx1 tab1}
drhb24fcbe2000-05-29 23:30:50 +0000245
drhe8409722000-06-08 16:54:40 +0000246# Allow more than one entry with the same key.
247#
248do_test index-10.0 {
249 execsql {
250 CREATE TABLE t1(a int, b int);
251 CREATE INDEX i1 ON t1(a);
252 INSERT INTO t1 VALUES(1,2);
253 INSERT INTO t1 VALUES(2,4);
254 INSERT INTO t1 VALUES(3,8);
255 INSERT INTO t1 VALUES(1,12);
256 SELECT b FROM t1 WHERE a=1 ORDER BY b;
257 }
258} {2 12}
259do_test index-10.1 {
260 execsql {
261 SELECT b FROM t1 WHERE a=2 ORDER BY b;
262 }
263} {4}
264do_test index-10.2 {
265 execsql {
266 DELETE FROM t1 WHERE b=12;
267 SELECT b FROM t1 WHERE a=1 ORDER BY b;
268 }
269} {2}
drh353f57e2000-08-02 12:26:28 +0000270do_test index-10.3 {
drhe8409722000-06-08 16:54:40 +0000271 execsql {
272 DELETE FROM t1 WHERE b=2;
273 SELECT b FROM t1 WHERE a=1 ORDER BY b;
274 }
275} {}
drh353f57e2000-08-02 12:26:28 +0000276do_test index-10.4 {
277 execsql {
278 DELETE FROM t1;
279 INSERT INTO t1 VALUES (1,1);
280 INSERT INTO t1 VALUES (1,2);
281 INSERT INTO t1 VALUES (1,3);
282 INSERT INTO t1 VALUES (1,4);
283 INSERT INTO t1 VALUES (1,5);
284 INSERT INTO t1 VALUES (1,6);
285 INSERT INTO t1 VALUES (1,7);
286 INSERT INTO t1 VALUES (1,8);
287 INSERT INTO t1 VALUES (1,9);
288 INSERT INTO t1 VALUES (2,0);
289 SELECT b FROM t1 WHERE a=1 ORDER BY b;
290 }
291} {1 2 3 4 5 6 7 8 9}
292do_test index-10.5 {
293 execsql {
294 DELETE FROM t1 WHERE b IN (2, 4, 6, 8);
295 SELECT b FROM t1 WHERE a=1 ORDER BY b;
296 }
297} {1 3 5 7 9}
298do_test index-10.6 {
299 execsql {
300 DELETE FROM t1 WHERE b>2;
301 SELECT b FROM t1 WHERE a=1 ORDER BY b;
302 }
303} {1}
304do_test index-10.7 {
305 execsql {
306 DELETE FROM t1 WHERE b=1;
307 SELECT b FROM t1 WHERE a=1 ORDER BY b;
308 }
309} {}
310do_test index-10.8 {
311 execsql {
312 SELECT b FROM t1 ORDER BY b;
313 }
314} {0}
315
drhc4a3c772001-04-04 11:48:57 +0000316# Automatically create an index when we specify a primary key.
317#
318do_test index-11.1 {
319 execsql {
320 CREATE TABLE t3(
321 a text,
322 b int,
323 c float,
324 PRIMARY KEY(b)
325 );
326 }
327 for {set i 1} {$i<=50} {incr i} {
328 execsql "INSERT INTO t3 VALUES('x${i}x',$i,0.$i)"
329 }
drh487ab3c2001-11-08 00:45:21 +0000330 set sqlite_search_count 0
331 concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
332} {0.10 3}
drhe8409722000-06-08 16:54:40 +0000333
drh7a7c7392001-11-24 00:31:46 +0000334# Numeric strings should compare as if they were numbers. So even if the
335# strings are not character-by-character the same, if they represent the
336# same number they should compare equal to one another. Verify that this
337# is true in indices.
338#
339do_test index-12.1 {
340 execsql {
341 CREATE TABLE t4(a,b);
342 INSERT INTO t4 VALUES('0.0',1);
343 INSERT INTO t4 VALUES('0.00',2);
344 INSERT INTO t4 VALUES('abc',3);
345 INSERT INTO t4 VALUES('-1.0',4);
346 INSERT INTO t4 VALUES('+1.0',5);
347 INSERT INTO t4 VALUES('0',6);
348 INSERT INTO t4 VALUES('00000',7);
349 SELECT a FROM t4 ORDER BY b;
350 }
351} {0.0 0.00 abc -1.0 +1.0 0 00000}
352do_test index-12.2 {
353 execsql {
354 SELECT a FROM t4 WHERE a==0 ORDER BY b
355 }
356} {0.0 0.00 0 00000}
357do_test index-12.3 {
358 execsql {
359 SELECT a FROM t4 WHERE a<0.5 ORDER BY b
360 }
361} {0.0 0.00 -1.0 0 00000}
362do_test index-12.4 {
363 execsql {
364 SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
365 }
366} {0.0 0.00 abc +1.0 0 00000}
367do_test index-12.5 {
368 execsql {
369 CREATE INDEX t4i1 ON t4(a);
370 SELECT a FROM t4 WHERE a==0 ORDER BY b
371 }
372} {0.0 0.00 0 00000}
373do_test index-12.6 {
374 execsql {
375 SELECT a FROM t4 WHERE a<0.5 ORDER BY b
376 }
377} {0.0 0.00 -1.0 0 00000}
378do_test index-12.7 {
379 execsql {
380 SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
381 }
382} {0.0 0.00 abc +1.0 0 00000}
383
drh485b39b2002-07-13 03:11:52 +0000384# Make sure we cannot drop an automatically created index.
385#
386do_test index-13.1 {
387 execsql {
388 CREATE TABLE t5(
389 a int UNIQUE,
390 b float PRIMARY KEY,
391 c varchar(10),
392 UNIQUE(a,c)
393 );
394 INSERT INTO t5 VALUES(1,2,3);
395 SELECT * FROM t5;
396 }
397} {1 2 3}
398do_test index-13.2 {
399 set ::idxlist [execsql {
400 SELECT name FROM sqlite_master WHERE type="index" AND tbl_name="t5";
401 }]
402 llength $::idxlist
403} {3}
404for {set i 0} {$i<[llength $::idxlist]} {incr i} {
405 do_test index-13.3.$i {
406 catchsql "
407 DROP INDEX '[lindex $::idxlist $i]';
408 "
409 } {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}}
410}
411do_test index-13.4 {
412 execsql {
413 INSERT INTO t5 VALUES('a','b','c');
414 SELECT * FROM t5;
415 }
416} {1 2 3 a b c}
417
drhb24fcbe2000-05-29 23:30:50 +0000418finish_test