drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 1 | # 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 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 26 | # $Id: index.test,v 1.1 2000/05/29 23:58:12 drh Exp $ |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 27 | |
| 28 | set testdir [file dirname $argv0] |
| 29 | source $testdir/tester.tcl |
| 30 | |
| 31 | # Create a basic index and verify it is added to sqlite_master |
| 32 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 33 | do_test index-1.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 34 | 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} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 38 | do_test index-1.1b { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 39 | execsql {SELECT name, sql, tbl_name, type FROM sqlite_master |
| 40 | WHERE name='index1'} |
| 41 | } {index1 {CREATE INDEX index1 ON test1(f1)} test1 index} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 42 | do_test index-1.1c { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 43 | 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} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 48 | do_test index-1.1d { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 49 | 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 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 56 | do_test index-1.2 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 57 | 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 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 63 | do_test index-2.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 64 | set v [catch {execsql {CREATE INDEX index1 ON test1(f1)}} msg] |
| 65 | lappend v $msg |
| 66 | } {1 {no such table: test1}} |
| 67 | |
| 68 | # Try adding an index on a field of a table where the table |
| 69 | # exists but the field does not. |
| 70 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 71 | do_test index-2.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 72 | 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 |
| 75 | } {1 {table test1 has no field named f4}} |
| 76 | |
| 77 | # Try an index with some fields that match and others that do now. |
| 78 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 79 | do_test index-2.2 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 80 | set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg] |
| 81 | execsql {DROP TABLE test1} |
| 82 | lappend v $msg |
| 83 | } {1 {table test1 has no field named f4}} |
| 84 | |
| 85 | # Try creating a bunch of indices on the same table |
| 86 | # |
| 87 | set r {} |
| 88 | for {set i 1} {$i<100} {incr i} { |
| 89 | lappend r index$i |
| 90 | } |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 91 | do_test index-3.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 92 | 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 | # |
| 105 | set r {} |
| 106 | for {set i 1} {$i<100} {incr i} { |
| 107 | lappend r testdb/index$i.tbl |
| 108 | } |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 109 | do_test index-3.2 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 110 | 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 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 116 | do_test index-3.3 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 117 | execsql {DROP TABLE test1} |
| 118 | execsql {SELECT name FROM sqlite_master |
| 119 | WHERE type='index' AND tbl_name='test1' |
| 120 | ORDER BY name} |
| 121 | } {} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 122 | do_test index-3.4 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 123 | 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 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 130 | do_test index-4.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 131 | execsql {CREATE TABLE test1(cnt int, power int)} |
| 132 | for {set i 1} {$i<20} {incr i} { |
| 133 | execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])" |
| 134 | } |
| 135 | execsql {CREATE INDEX index1 ON test1(cnt)} |
| 136 | execsql {CREATE INDEX index2 ON test1(cnt)} |
| 137 | execsql {SELECT name FROM sqlite_master ORDER BY name} |
| 138 | } {index1 index2 test1} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 139 | do_test index-4.2 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 140 | execsql {SELECT cnt FROM test1 WHERE power=4} |
| 141 | } {2} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 142 | do_test index-4.3 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 143 | execsql {SELECT cnt FROM test1 WHERE power=1024} |
| 144 | } {10} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 145 | do_test index-4.4 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 146 | execsql {SELECT power FROM test1 WHERE cnt=6} |
| 147 | } {64} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 148 | do_test index-4.5 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 149 | execsql {DROP TABLE test1} |
| 150 | } {} |
| 151 | |
| 152 | # Do not allow indices to be added to sqlite_master |
| 153 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 154 | do_test index-5.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 155 | set v [catch {execsql {CREATE INDEX index1 ON sqlite_master(name)}} msg] |
| 156 | lappend v $msg |
| 157 | } {1 {table sqlite_master may not have new indices added}} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 158 | do_test index-5.2 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 159 | execsql {SELECT name FROM sqlite_master} |
| 160 | } {} |
| 161 | |
| 162 | # Do not allow indices with duplicate names to be added |
| 163 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 164 | do_test index-6.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 165 | execsql {CREATE TABLE test1(f1 int, f2 int)} |
| 166 | execsql {CREATE TABLE test2(g1 real, g2 real)} |
| 167 | execsql {CREATE INDEX index1 ON test1(f1)} |
| 168 | set v [catch {execsql {CREATE INDEX index1 ON test2(g1)}} msg] |
| 169 | lappend v $msg |
| 170 | } {1 {index "index1" already exists}} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 171 | do_test index-6.1b { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 172 | execsql {SELECT name FROM sqlite_master ORDER BY name} |
| 173 | } {index1 test1 test2} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 174 | do_test index-6.2 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 175 | set v [catch {execsql {CREATE INDEX test1 ON test2(g1)}} msg] |
| 176 | lappend v $msg |
| 177 | } {1 {there is already a table named "test1"}} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 178 | do_test index-6.2b { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 179 | execsql {SELECT name FROM sqlite_master ORDER BY name} |
| 180 | } {index1 test1 test2} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 181 | do_test index-6.3 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 182 | execsql {DROP TABLE test1} |
| 183 | execsql {DROP TABLE test2} |
| 184 | execsql {SELECT name FROM sqlite_master ORDER BY name} |
| 185 | } {} |
| 186 | |
| 187 | # Create a primary key |
| 188 | # |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 189 | do_test index-7.1 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 190 | execsql {CREATE TABLE test1(f1 int, f2 int primary key)} |
| 191 | for {set i 1} {$i<20} {incr i} { |
| 192 | execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])" |
| 193 | } |
| 194 | lsort -dictionary [glob testdb/test1*.tbl] |
| 195 | } {testdb/test1.tbl testdb/test1__primary_key.tbl} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 196 | do_test index-7.2 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 197 | execsql {SELECT f1 FROM test1 WHERE f2=65536} |
| 198 | } {16} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 199 | do_test index-7.3 { |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 200 | set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}] |
| 201 | expr {[lsearch $code test1__primary_key]>0} |
| 202 | } {1} |
drh | 1b6a71f | 2000-05-29 23:58:11 +0000 | [diff] [blame^] | 203 | do_test index-7.4 { |
| 204 | execsql {DROP table test1} |
| 205 | execsql {SELECT name FROM sqlite_master} |
| 206 | } {} |
| 207 | |
| 208 | # Make sure we cannot drop a non-existant table. |
| 209 | # |
| 210 | do_test index-8.1 { |
| 211 | set v [catch {execsql {DROP INDEX index1}} msg] |
| 212 | lappend v $msg |
| 213 | } {1 {no such index: "index1"}} |
| 214 | |
| 215 | |
drh | b24fcbe | 2000-05-29 23:30:50 +0000 | [diff] [blame] | 216 | |
| 217 | finish_test |