1# 2001 September 15 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# This file implements regression tests for SQLite library. The 12# focus of this file is testing the CREATE INDEX statement. 13# 14# $Id: index.test,v 1.27 2004/05/28 12:33:32 danielk1977 Exp $ 15 16set testdir [file dirname $argv0] 17source $testdir/tester.tcl 18 19# Create a basic index and verify it is added to sqlite_master 20# 21do_test index-1.1 { 22 execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)} 23 execsql {CREATE INDEX index1 ON test1(f1)} 24 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 25} {index1 test1} 26do_test index-1.1b { 27 execsql {SELECT name, sql, tbl_name, type FROM sqlite_master 28 WHERE name='index1'} 29} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index} 30do_test index-1.1c { 31 db close 32 sqlite db test.db 33 execsql {SELECT name, sql, tbl_name, type FROM sqlite_master 34 WHERE name='index1'} 35} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index} 36do_test index-1.1d { 37 db close 38 sqlite db test.db 39 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 40} {index1 test1} 41 42# Verify that the index dies with the table 43# 44do_test index-1.2 { 45 execsql {DROP TABLE test1} 46 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 47} {} 48 49# Try adding an index to a table that does not exist 50# 51do_test index-2.1 { 52 set v [catch {execsql {CREATE INDEX index1 ON test1(f1)}} msg] 53 lappend v $msg 54} {1 {no such table: main.test1}} 55 56# Try adding an index on a column of a table where the table 57# exists but the column does not. 58# 59do_test index-2.1 { 60 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 63} {1 {table test1 has no column named f4}} 64 65# Try an index with some columns that match and others that do now. 66# 67do_test index-2.2 { 68 set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg] 69 execsql {DROP TABLE test1} 70 lappend v $msg 71} {1 {table test1 has no column named f4}} 72 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 [format index%02d $i] 78} 79do_test index-3.1 { 80 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 [format index%02d $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 90 91# Verify that all the indices go away when we drop the table. 92# 93do_test index-3.3 { 94 execsql {DROP TABLE test1} 95 execsql {SELECT name FROM sqlite_master 96 WHERE type='index' AND tbl_name='test1' 97 ORDER BY name} 98} {} 99 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# 104# Note that the index names "index9" and "indext" are chosen because 105# they both have the same hash. 106# 107do_test index-4.1 { 108 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 } 112 execsql {CREATE INDEX index9 ON test1(cnt)} 113 execsql {CREATE INDEX indext ON test1(power)} 114 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 115} {index9 indext test1} 116do_test index-4.2 { 117 execsql {SELECT cnt FROM test1 WHERE power=4} 118} {2} 119do_test index-4.3 { 120 execsql {SELECT cnt FROM test1 WHERE power=1024} 121} {10} 122do_test index-4.4 { 123 execsql {SELECT power FROM test1 WHERE cnt=6} 124} {64} 125do_test index-4.5 { 126 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 { 154 execsql {DROP TABLE test1} 155 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 156} {} 157integrity_check index-4.14 158 159# Do not allow indices to be added to sqlite_master 160# 161do_test index-5.1 { 162 set v [catch {execsql {CREATE INDEX index1 ON sqlite_master(name)}} msg] 163 lappend v $msg 164} {1 {table sqlite_master may not be indexed}} 165do_test index-5.2 { 166 execsql {SELECT name FROM sqlite_master WHERE type!='meta'} 167} {} 168 169# Do not allow indices with duplicate names to be added 170# 171do_test index-6.1 { 172 execsql {CREATE TABLE test1(f1 int, f2 int)} 173 execsql {CREATE TABLE test2(g1 real, g2 real)} 174 execsql {CREATE INDEX index1 ON test1(f1)} 175 set v [catch {execsql {CREATE INDEX index1 ON test2(g1)}} msg] 176 lappend v $msg 177} {1 {index index1 already exists}} 178do_test index-6.1b { 179 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 180} {index1 test1 test2} 181do_test index-6.2 { 182 set v [catch {execsql {CREATE INDEX test1 ON test2(g1)}} msg] 183 lappend v $msg 184} {1 {there is already a table named test1}} 185do_test index-6.2b { 186 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 187} {index1 test1 test2} 188do_test index-6.3 { 189 execsql {DROP TABLE test1} 190 execsql {DROP TABLE test2} 191 execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} 192} {} 193do_test index-6.4 { 194 execsql { 195 CREATE TABLE test1(a,b); 196 CREATE INDEX index1 ON test1(a); 197 CREATE INDEX index2 ON test1(b); 198 CREATE INDEX index3 ON test1(a,b); 199 DROP TABLE test1; 200 SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name; 201 } 202} {} 203integrity_check index-6.5 204 205 206# Create a primary key 207# 208do_test index-7.1 { 209 execsql {CREATE TABLE test1(f1 int, f2 int primary key)} 210 for {set i 1} {$i<20} {incr i} { 211 execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])" 212 } 213 execsql {SELECT count(*) FROM test1} 214} {19} 215do_test index-7.2 { 216 execsql {SELECT f1 FROM test1 WHERE f2=65536} 217} {16} 218do_test index-7.3 { 219 execsql { 220 SELECT name FROM sqlite_master 221 WHERE type='index' AND tbl_name='test1' 222 } 223} {{(test1 autoindex 1)}} 224do_test index-7.4 { 225 execsql {DROP table test1} 226 execsql {SELECT name FROM sqlite_master WHERE type!='meta'} 227} {} 228integrity_check index-7.5 229 230# Make sure we cannot drop a non-existant index. 231# 232do_test index-8.1 { 233 set v [catch {execsql {DROP INDEX index1}} msg] 234 lappend v $msg 235} {1 {no such index: index1}} 236 237# Make sure we don't actually create an index when the EXPLAIN keyword 238# is used. 239# 240do_test index-9.1 { 241 execsql {CREATE TABLE tab1(a int)} 242 execsql {EXPLAIN CREATE INDEX idx1 ON tab1(a)} 243 execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1'} 244} {tab1} 245do_test index-9.2 { 246 execsql {CREATE INDEX idx1 ON tab1(a)} 247 execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1' ORDER BY name} 248} {idx1 tab1} 249integrity_check index-9.3 250 251# Allow more than one entry with the same key. 252# 253do_test index-10.0 { 254 execsql { 255 CREATE TABLE t1(a int, b int); 256 CREATE INDEX i1 ON t1(a); 257 INSERT INTO t1 VALUES(1,2); 258 INSERT INTO t1 VALUES(2,4); 259 INSERT INTO t1 VALUES(3,8); 260 INSERT INTO t1 VALUES(1,12); 261 SELECT b FROM t1 WHERE a=1 ORDER BY b; 262 } 263} {2 12} 264do_test index-10.1 { 265 execsql { 266 SELECT b FROM t1 WHERE a=2 ORDER BY b; 267 } 268} {4} 269do_test index-10.2 { 270 execsql { 271 DELETE FROM t1 WHERE b=12; 272 SELECT b FROM t1 WHERE a=1 ORDER BY b; 273 } 274} {2} 275do_test index-10.3 { 276 execsql { 277 DELETE FROM t1 WHERE b=2; 278 SELECT b FROM t1 WHERE a=1 ORDER BY b; 279 } 280} {} 281do_test index-10.4 { 282 execsql { 283 DELETE FROM t1; 284 INSERT INTO t1 VALUES (1,1); 285 INSERT INTO t1 VALUES (1,2); 286 INSERT INTO t1 VALUES (1,3); 287 INSERT INTO t1 VALUES (1,4); 288 INSERT INTO t1 VALUES (1,5); 289 INSERT INTO t1 VALUES (1,6); 290 INSERT INTO t1 VALUES (1,7); 291 INSERT INTO t1 VALUES (1,8); 292 INSERT INTO t1 VALUES (1,9); 293 INSERT INTO t1 VALUES (2,0); 294 SELECT b FROM t1 WHERE a=1 ORDER BY b; 295 } 296} {1 2 3 4 5 6 7 8 9} 297do_test index-10.5 { 298 execsql { 299 DELETE FROM t1 WHERE b IN (2, 4, 6, 8); 300 SELECT b FROM t1 WHERE a=1 ORDER BY b; 301 } 302} {1 3 5 7 9} 303do_test index-10.6 { 304 execsql { 305 DELETE FROM t1 WHERE b>2; 306 SELECT b FROM t1 WHERE a=1 ORDER BY b; 307 } 308} {1} 309do_test index-10.7 { 310 execsql { 311 DELETE FROM t1 WHERE b=1; 312 SELECT b FROM t1 WHERE a=1 ORDER BY b; 313 } 314} {} 315do_test index-10.8 { 316 execsql { 317 SELECT b FROM t1 ORDER BY b; 318 } 319} {0} 320integrity_check index-10.9 321 322# Automatically create an index when we specify a primary key. 323# 324do_test index-11.1 { 325 execsql { 326 CREATE TABLE t3( 327 a text, 328 b int, 329 c float, 330 PRIMARY KEY(b) 331 ); 332 } 333 for {set i 1} {$i<=50} {incr i} { 334 execsql "INSERT INTO t3 VALUES('x${i}x',$i,0.$i)" 335 } 336 set sqlite_search_count 0 337 concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count 338} {0.1 3} 339integrity_check index-11.2 340 341 342# Numeric strings should compare as if they were numbers. So even if the 343# strings are not character-by-character the same, if they represent the 344# same number they should compare equal to one another. Verify that this 345# is true in indices. 346# 347# Updated for sqlite v3: SQLite will now store these values as numbers 348# (because the affinity of column a is NUMERIC) so the quirky 349# representations are not retained. i.e. '+1.0' becomes '1'. 350do_test index-12.1 { 351 execsql { 352 CREATE TABLE t4(a NUM,b); 353 INSERT INTO t4 VALUES('0.0',1); 354 INSERT INTO t4 VALUES('0.00',2); 355 INSERT INTO t4 VALUES('abc',3); 356 INSERT INTO t4 VALUES('-1.0',4); 357 INSERT INTO t4 VALUES('+1.0',5); 358 INSERT INTO t4 VALUES('0',6); 359 INSERT INTO t4 VALUES('00000',7); 360 SELECT a FROM t4 ORDER BY b; 361 } 362} {0 0 abc -1 1 0 0} 363do_test index-12.2 { 364 execsql { 365 SELECT a FROM t4 WHERE a==0 ORDER BY b 366 } 367} {0 0 0 0} 368do_test index-12.3 { 369 execsql { 370 SELECT a FROM t4 WHERE a<0.5 ORDER BY b 371 } 372} {0 0 -1 0 0} 373do_test index-12.4 { 374 execsql { 375 SELECT a FROM t4 WHERE a>-0.5 ORDER BY b 376 } 377} {0 0 abc 1 0 0} 378do_test index-12.5 { 379 execsql { 380 CREATE INDEX t4i1 ON t4(a); 381 SELECT a FROM t4 WHERE a==0 ORDER BY b 382 } 383} {0 0 0 0} 384do_test index-12.6 { 385 execsql { 386 SELECT a FROM t4 WHERE a<0.5 ORDER BY b 387 } 388} {0 0 -1 0 0} 389do_test index-12.7 { 390 execsql { 391 SELECT a FROM t4 WHERE a>-0.5 ORDER BY b 392 } 393} {0 0 abc 1 0 0} 394integrity_check index-12.8 395 396# Make sure we cannot drop an automatically created index. 397# 398do_test index-13.1 { 399 execsql { 400 CREATE TABLE t5( 401 a int UNIQUE, 402 b float PRIMARY KEY, 403 c varchar(10), 404 UNIQUE(a,c) 405 ); 406 INSERT INTO t5 VALUES(1,2,3); 407 SELECT * FROM t5; 408 } 409} {1 2 3} 410do_test index-13.2 { 411 set ::idxlist [execsql { 412 SELECT name FROM sqlite_master WHERE type="index" AND tbl_name="t5"; 413 }] 414 llength $::idxlist 415} {3} 416for {set i 0} {$i<[llength $::idxlist]} {incr i} { 417 do_test index-13.3.$i { 418 catchsql " 419 DROP INDEX '[lindex $::idxlist $i]'; 420 " 421 } {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}} 422} 423do_test index-13.4 { 424 execsql { 425 INSERT INTO t5 VALUES('a','b','c'); 426 SELECT * FROM t5; 427 } 428} {1 2 3 a b c} 429integrity_check index-13.5 430 431# Check the sort order of data in an index. 432# 433do_test index-14.1 { 434 execsql { 435 CREATE TABLE t6(a,b,c); 436 CREATE INDEX t6i1 ON t6(a,b); 437 INSERT INTO t6 VALUES('','',1); 438 INSERT INTO t6 VALUES('',NULL,2); 439 INSERT INTO t6 VALUES(NULL,'',3); 440 INSERT INTO t6 VALUES('abc',123,4); 441 INSERT INTO t6 VALUES(123,'abc',5); 442 SELECT c FROM t6 ORDER BY a,b; 443 } 444} {3 5 2 1 4} 445do_test index-14.2 { 446 execsql { 447 SELECT c FROM t6 WHERE a=''; 448 } 449} {2 1} 450do_test index-14.3 { 451 execsql { 452 SELECT c FROM t6 WHERE b=''; 453 } 454} {1 3} 455do_test index-14.4 { 456 execsql { 457 SELECT c FROM t6 WHERE a>''; 458 } 459} {4} 460do_test index-14.5 { 461 execsql { 462 SELECT c FROM t6 WHERE a>=''; 463 } 464} {2 1 4} 465do_test index-14.6 { 466 execsql { 467 SELECT c FROM t6 WHERE a>123; 468 } 469} {2 1 4} 470do_test index-14.7 { 471 execsql { 472 SELECT c FROM t6 WHERE a>=123; 473 } 474} {5 2 1 4} 475do_test index-14.8 { 476 execsql { 477 SELECT c FROM t6 WHERE a<'abc'; 478 } 479} {5 2 1} 480do_test index-14.9 { 481 execsql { 482 SELECT c FROM t6 WHERE a<='abc'; 483 } 484} {5 2 1 4} 485do_test index-14.10 { 486 execsql { 487 SELECT c FROM t6 WHERE a<=''; 488 } 489} {5 2 1} 490do_test index-14.11 { 491 execsql { 492 SELECT c FROM t6 WHERE a<''; 493 } 494} {5} 495integrity_check index-14.12 496 497do_test index-15.1 { 498 execsql { 499 DELETE FROM t1; 500 SELECT * FROM t1; 501 } 502} {} 503do_test index-15.2 { 504 execsql { 505 INSERT INTO t1 VALUES('1.234e5',1); 506 INSERT INTO t1 VALUES('12.33e04',2); 507 INSERT INTO t1 VALUES('12.35E4',3); 508 INSERT INTO t1 VALUES('12.34e',4); 509 INSERT INTO t1 VALUES('12.32e+4',5); 510 INSERT INTO t1 VALUES('12.36E+04',6); 511 INSERT INTO t1 VALUES('12.36E+',7); 512 INSERT INTO t1 VALUES('+123.10000E+0003',8); 513 INSERT INTO t1 VALUES('+',9); 514 INSERT INTO t1 VALUES('+12347.E+02',10); 515 INSERT INTO t1 VALUES('+12347E+02',11); 516 SELECT b FROM t1 ORDER BY a; 517 } 518} {8 5 2 1 3 6 11 9 10 4 7} 519integrity_check index-15.1 520 521finish_test 522