blob: b72c556432d2948cfdf393600a331cb829582eb3 [file] [log] [blame]
drhb24fcbe2000-05-29 23:30:50 +00001# Copyright (c) 1999, 2000 D. Richard Hipp
2#
3# This program is free software; you can redistribute it and/or
4# modify it under the terms of the GNU General Public
5# License as published by the Free Software Foundation; either
6# version 2 of the License, or (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11# General Public License for more details.
12#
13# You should have received a copy of the GNU General Public
14# License along with this library; if not, write to the
15# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16# Boston, MA 02111-1307, USA.
17#
18# Author contact information:
19# drh@hwaci.com
20# http://www.hwaci.com/drh/
21#
22#***********************************************************************
23# This file implements regression tests for SQLite library. The
24# focus of this file is testing the CREATE INDEX statement.
25#
drh353f57e2000-08-02 12:26:28 +000026# $Id: index.test,v 1.6 2000/08/02 12:26:30 drh Exp $
drhb24fcbe2000-05-29 23:30:50 +000027
28set testdir [file dirname $argv0]
29source $testdir/tester.tcl
30
31# Create a basic index and verify it is added to sqlite_master
32#
drh1b6a71f2000-05-29 23:58:11 +000033do_test index-1.1 {
drhb24fcbe2000-05-29 23:30:50 +000034 execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)}
35 execsql {CREATE INDEX index1 ON test1(f1)}
36 execsql {SELECT name FROM sqlite_master ORDER BY name}
37} {index1 test1}
drh1b6a71f2000-05-29 23:58:11 +000038do_test index-1.1b {
drhb24fcbe2000-05-29 23:30:50 +000039 execsql {SELECT name, sql, tbl_name, type FROM sqlite_master
40 WHERE name='index1'}
41} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index}
drh1b6a71f2000-05-29 23:58:11 +000042do_test index-1.1c {
drhb24fcbe2000-05-29 23:30:50 +000043 db close
44 sqlite db testdb
45 execsql {SELECT name, sql, tbl_name, type FROM sqlite_master
46 WHERE name='index1'}
47} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index}
drh1b6a71f2000-05-29 23:58:11 +000048do_test index-1.1d {
drhb24fcbe2000-05-29 23:30:50 +000049 db close
50 sqlite db testdb
51 execsql {SELECT name FROM sqlite_master ORDER BY name}
52} {index1 test1}
53
54# Verify that the index dies with the table
55#
drh1b6a71f2000-05-29 23:58:11 +000056do_test index-1.2 {
drhb24fcbe2000-05-29 23:30:50 +000057 execsql {DROP TABLE test1}
58 execsql {SELECT name FROM sqlite_master ORDER BY name}
59} {}
60
61# Try adding an index to a table that does not exist
62#
drh1b6a71f2000-05-29 23:58:11 +000063do_test index-2.1 {
drhb24fcbe2000-05-29 23:30:50 +000064 set v [catch {execsql {CREATE INDEX index1 ON test1(f1)}} msg]
65 lappend v $msg
66} {1 {no such table: test1}}
67
drh1ccde152000-06-17 13:12:39 +000068# Try adding an index on a column of a table where the table
69# exists but the column does not.
drhb24fcbe2000-05-29 23:30:50 +000070#
drh1b6a71f2000-05-29 23:58:11 +000071do_test index-2.1 {
drhb24fcbe2000-05-29 23:30:50 +000072 execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)}
73 set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg]
74 lappend v $msg
drh1ccde152000-06-17 13:12:39 +000075} {1 {table test1 has no column named f4}}
drhb24fcbe2000-05-29 23:30:50 +000076
drh1ccde152000-06-17 13:12:39 +000077# Try an index with some columns that match and others that do now.
drhb24fcbe2000-05-29 23:30:50 +000078#
drh1b6a71f2000-05-29 23:58:11 +000079do_test index-2.2 {
drhb24fcbe2000-05-29 23:30:50 +000080 set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg]
81 execsql {DROP TABLE test1}
82 lappend v $msg
drh1ccde152000-06-17 13:12:39 +000083} {1 {table test1 has no column named f4}}
drhb24fcbe2000-05-29 23:30:50 +000084
85# Try creating a bunch of indices on the same table
86#
87set r {}
88for {set i 1} {$i<100} {incr i} {
89 lappend r index$i
90}
drh1b6a71f2000-05-29 23:58:11 +000091do_test index-3.1 {
drhb24fcbe2000-05-29 23:30:50 +000092 execsql {CREATE TABLE test1(f1 int, f2 int, f3 int, f4 int, f5 int)}
93 for {set i 1} {$i<100} {incr i} {
94 set sql "CREATE INDEX index$i ON test1(f[expr {($i%5)+1}])"
95 execsql $sql
96 }
97 execsql {SELECT name FROM sqlite_master
98 WHERE type='index' AND tbl_name='test1'
99 ORDER BY name}
100} $r
101
102# Add a single entry to the table. Verify that files are created
103# for every index.
104#
105set r {}
106for {set i 1} {$i<100} {incr i} {
107 lappend r testdb/index$i.tbl
108}
drh1b6a71f2000-05-29 23:58:11 +0000109do_test index-3.2 {
drhb24fcbe2000-05-29 23:30:50 +0000110 execsql {INSERT INTO test1 VALUES(1,2,3,4,5)}
111 lsort -dictionary [glob testdb/index*.tbl]
112} $r
113
114# Verify that all the indices go away when we drop the table.
115#
drh1b6a71f2000-05-29 23:58:11 +0000116do_test index-3.3 {
drhb24fcbe2000-05-29 23:30:50 +0000117 execsql {DROP TABLE test1}
118 execsql {SELECT name FROM sqlite_master
119 WHERE type='index' AND tbl_name='test1'
120 ORDER BY name}
121} {}
drh1b6a71f2000-05-29 23:58:11 +0000122do_test index-3.4 {
drhb24fcbe2000-05-29 23:30:50 +0000123 lsort -dictionary [glob -nocomplain testdb/index*.tbl]
124} {}
125
126# Create a table and insert values into that table. Then create
127# an index on that table. Verify that we can select values
128# from the table correctly using the index.
129#
drh7020f652000-06-03 18:06:52 +0000130# Note that the index names "index9" and "indext" are chosen because
131# they both have the same hash.
132#
drh1b6a71f2000-05-29 23:58:11 +0000133do_test index-4.1 {
drhb24fcbe2000-05-29 23:30:50 +0000134 execsql {CREATE TABLE test1(cnt int, power int)}
135 for {set i 1} {$i<20} {incr i} {
136 execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])"
137 }
drh7020f652000-06-03 18:06:52 +0000138 execsql {CREATE INDEX index9 ON test1(cnt)}
139 execsql {CREATE INDEX indext ON test1(power)}
drhb24fcbe2000-05-29 23:30:50 +0000140 execsql {SELECT name FROM sqlite_master ORDER BY name}
drh7020f652000-06-03 18:06:52 +0000141} {index9 indext test1}
drh1b6a71f2000-05-29 23:58:11 +0000142do_test index-4.2 {
drhb24fcbe2000-05-29 23:30:50 +0000143 execsql {SELECT cnt FROM test1 WHERE power=4}
144} {2}
drh1b6a71f2000-05-29 23:58:11 +0000145do_test index-4.3 {
drhb24fcbe2000-05-29 23:30:50 +0000146 execsql {SELECT cnt FROM test1 WHERE power=1024}
147} {10}
drh1b6a71f2000-05-29 23:58:11 +0000148do_test index-4.4 {
drhb24fcbe2000-05-29 23:30:50 +0000149 execsql {SELECT power FROM test1 WHERE cnt=6}
150} {64}
drh1b6a71f2000-05-29 23:58:11 +0000151do_test index-4.5 {
drh7020f652000-06-03 18:06:52 +0000152 execsql {DROP INDEX indext}
153 execsql {SELECT power FROM test1 WHERE cnt=6}
154} {64}
155do_test index-4.6 {
156 execsql {SELECT cnt FROM test1 WHERE power=1024}
157} {10}
158do_test index-4.7 {
159 execsql {CREATE INDEX indext ON test1(cnt)}
160 execsql {SELECT power FROM test1 WHERE cnt=6}
161} {64}
162do_test index-4.8 {
163 execsql {SELECT cnt FROM test1 WHERE power=1024}
164} {10}
165do_test index-4.9 {
166 execsql {DROP INDEX index9}
167 execsql {SELECT power FROM test1 WHERE cnt=6}
168} {64}
169do_test index-4.10 {
170 execsql {SELECT cnt FROM test1 WHERE power=1024}
171} {10}
172do_test index-4.11 {
173 execsql {DROP INDEX indext}
174 execsql {SELECT power FROM test1 WHERE cnt=6}
175} {64}
176do_test index-4.12 {
177 execsql {SELECT cnt FROM test1 WHERE power=1024}
178} {10}
179do_test index-4.13 {
drhb24fcbe2000-05-29 23:30:50 +0000180 execsql {DROP TABLE test1}
drh7020f652000-06-03 18:06:52 +0000181 execsql {SELECT name FROM sqlite_master ORDER BY name}
drhb24fcbe2000-05-29 23:30:50 +0000182} {}
183
184# Do not allow indices to be added to sqlite_master
185#
drh1b6a71f2000-05-29 23:58:11 +0000186do_test index-5.1 {
drhb24fcbe2000-05-29 23:30:50 +0000187 set v [catch {execsql {CREATE INDEX index1 ON sqlite_master(name)}} msg]
188 lappend v $msg
189} {1 {table sqlite_master may not have new indices added}}
drh1b6a71f2000-05-29 23:58:11 +0000190do_test index-5.2 {
drhb24fcbe2000-05-29 23:30:50 +0000191 execsql {SELECT name FROM sqlite_master}
192} {}
193
194# Do not allow indices with duplicate names to be added
195#
drh1b6a71f2000-05-29 23:58:11 +0000196do_test index-6.1 {
drhb24fcbe2000-05-29 23:30:50 +0000197 execsql {CREATE TABLE test1(f1 int, f2 int)}
198 execsql {CREATE TABLE test2(g1 real, g2 real)}
199 execsql {CREATE INDEX index1 ON test1(f1)}
200 set v [catch {execsql {CREATE INDEX index1 ON test2(g1)}} msg]
201 lappend v $msg
drh1d37e282000-05-30 03:12:21 +0000202} {1 {index index1 already exists}}
drh1b6a71f2000-05-29 23:58:11 +0000203do_test index-6.1b {
drhb24fcbe2000-05-29 23:30:50 +0000204 execsql {SELECT name FROM sqlite_master ORDER BY name}
205} {index1 test1 test2}
drh1b6a71f2000-05-29 23:58:11 +0000206do_test index-6.2 {
drhb24fcbe2000-05-29 23:30:50 +0000207 set v [catch {execsql {CREATE INDEX test1 ON test2(g1)}} msg]
208 lappend v $msg
drh1d37e282000-05-30 03:12:21 +0000209} {1 {there is already a table named test1}}
drh1b6a71f2000-05-29 23:58:11 +0000210do_test index-6.2b {
drhb24fcbe2000-05-29 23:30:50 +0000211 execsql {SELECT name FROM sqlite_master ORDER BY name}
212} {index1 test1 test2}
drh1b6a71f2000-05-29 23:58:11 +0000213do_test index-6.3 {
drhb24fcbe2000-05-29 23:30:50 +0000214 execsql {DROP TABLE test1}
215 execsql {DROP TABLE test2}
216 execsql {SELECT name FROM sqlite_master ORDER BY name}
217} {}
218
219# Create a primary key
220#
drh1b6a71f2000-05-29 23:58:11 +0000221do_test index-7.1 {
drhb24fcbe2000-05-29 23:30:50 +0000222 execsql {CREATE TABLE test1(f1 int, f2 int primary key)}
223 for {set i 1} {$i<20} {incr i} {
224 execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])"
225 }
226 lsort -dictionary [glob testdb/test1*.tbl]
227} {testdb/test1.tbl testdb/test1__primary_key.tbl}
drh1b6a71f2000-05-29 23:58:11 +0000228do_test index-7.2 {
drhb24fcbe2000-05-29 23:30:50 +0000229 execsql {SELECT f1 FROM test1 WHERE f2=65536}
230} {16}
drh1b6a71f2000-05-29 23:58:11 +0000231do_test index-7.3 {
drhb24fcbe2000-05-29 23:30:50 +0000232 set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}]
233 expr {[lsearch $code test1__primary_key]>0}
234} {1}
drh1b6a71f2000-05-29 23:58:11 +0000235do_test index-7.4 {
236 execsql {DROP table test1}
237 execsql {SELECT name FROM sqlite_master}
238} {}
239
drh7020f652000-06-03 18:06:52 +0000240# Make sure we cannot drop a non-existant index.
drh1b6a71f2000-05-29 23:58:11 +0000241#
242do_test index-8.1 {
243 set v [catch {execsql {DROP INDEX index1}} msg]
244 lappend v $msg
drh1d37e282000-05-30 03:12:21 +0000245} {1 {no such index: index1}}
drh1b6a71f2000-05-29 23:58:11 +0000246
drh7020f652000-06-03 18:06:52 +0000247# Make sure we don't actually create an index when the EXPLAIN keyword
248# is used.
249#
250do_test index-9.1 {
251 execsql {CREATE TABLE tab1(a int)}
252 execsql {EXPLAIN CREATE INDEX idx1 ON tab1(a)}
253 execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1'}
254} {tab1}
255do_test index-9.2 {
256 execsql {CREATE INDEX idx1 ON tab1(a)}
257 execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1' ORDER BY name}
258} {idx1 tab1}
drhb24fcbe2000-05-29 23:30:50 +0000259
drhe8409722000-06-08 16:54:40 +0000260# Allow more than one entry with the same key.
261#
262do_test index-10.0 {
263 execsql {
264 CREATE TABLE t1(a int, b int);
265 CREATE INDEX i1 ON t1(a);
266 INSERT INTO t1 VALUES(1,2);
267 INSERT INTO t1 VALUES(2,4);
268 INSERT INTO t1 VALUES(3,8);
269 INSERT INTO t1 VALUES(1,12);
270 SELECT b FROM t1 WHERE a=1 ORDER BY b;
271 }
272} {2 12}
273do_test index-10.1 {
274 execsql {
275 SELECT b FROM t1 WHERE a=2 ORDER BY b;
276 }
277} {4}
278do_test index-10.2 {
279 execsql {
280 DELETE FROM t1 WHERE b=12;
281 SELECT b FROM t1 WHERE a=1 ORDER BY b;
282 }
283} {2}
drh353f57e2000-08-02 12:26:28 +0000284do_test index-10.3 {
drhe8409722000-06-08 16:54:40 +0000285 execsql {
286 DELETE FROM t1 WHERE b=2;
287 SELECT b FROM t1 WHERE a=1 ORDER BY b;
288 }
289} {}
drh353f57e2000-08-02 12:26:28 +0000290do_test index-10.4 {
291 execsql {
292 DELETE FROM t1;
293 INSERT INTO t1 VALUES (1,1);
294 INSERT INTO t1 VALUES (1,2);
295 INSERT INTO t1 VALUES (1,3);
296 INSERT INTO t1 VALUES (1,4);
297 INSERT INTO t1 VALUES (1,5);
298 INSERT INTO t1 VALUES (1,6);
299 INSERT INTO t1 VALUES (1,7);
300 INSERT INTO t1 VALUES (1,8);
301 INSERT INTO t1 VALUES (1,9);
302 INSERT INTO t1 VALUES (2,0);
303 SELECT b FROM t1 WHERE a=1 ORDER BY b;
304 }
305} {1 2 3 4 5 6 7 8 9}
306do_test index-10.5 {
307 execsql {
308 DELETE FROM t1 WHERE b IN (2, 4, 6, 8);
309 SELECT b FROM t1 WHERE a=1 ORDER BY b;
310 }
311} {1 3 5 7 9}
312do_test index-10.6 {
313 execsql {
314 DELETE FROM t1 WHERE b>2;
315 SELECT b FROM t1 WHERE a=1 ORDER BY b;
316 }
317} {1}
318do_test index-10.7 {
319 execsql {
320 DELETE FROM t1 WHERE b=1;
321 SELECT b FROM t1 WHERE a=1 ORDER BY b;
322 }
323} {}
324do_test index-10.8 {
325 execsql {
326 SELECT b FROM t1 ORDER BY b;
327 }
328} {0}
329
drhe8409722000-06-08 16:54:40 +0000330
drhb24fcbe2000-05-29 23:30:50 +0000331finish_test