1 # 2001 October 7 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. 12 # 13 # This file implements tests for temporary tables and indices. 14 # 15 # $Id: temptable.test,v 1.21 2009/06/16 17:49:36 drh Exp $ 16 17 set testdir [file dirname $argv0] 18 source $testdir/tester.tcl 19 20 ifcapable !tempdb { 21 finish_test 22 return 23 } 24 25 # Create an alternative connection to the database 26 # 27 do_test temptable-1.0 { 28 sqlite3 db2 ./test.db 29 set dummy {} 30 } {} 31 32 # Create a permanent table. 33 # 34 do_test temptable-1.1 { 35 execsql {CREATE TABLE t1(a,b,c);} 36 execsql {INSERT INTO t1 VALUES(1,2,3);} 37 execsql {SELECT * FROM t1} 38 } {1 2 3} 39 do_test temptable-1.2 { 40 catch {db2 eval {SELECT * FROM sqlite_master}} 41 db2 eval {SELECT * FROM t1} 42 } {1 2 3} 43 do_test temptable-1.3 { 44 execsql {SELECT name FROM sqlite_master} 45 } {t1} 46 do_test temptable-1.4 { 47 db2 eval {SELECT name FROM sqlite_master} 48 } {t1} 49 50 # Create a temporary table. Verify that only one of the two 51 # processes can see it. 52 # 53 do_test temptable-1.5 { 54 db2 eval { 55 CREATE TEMP TABLE t2(x,y,z); 56 INSERT INTO t2 VALUES(4,5,6); 57 } 58 db2 eval {SELECT * FROM t2} 59 } {4 5 6} 60 do_test temptable-1.6 { 61 catch {execsql {SELECT * FROM sqlite_master}} 62 catchsql {SELECT * FROM t2} 63 } {1 {no such table: t2}} 64 do_test temptable-1.7 { 65 catchsql {INSERT INTO t2 VALUES(8,9,0);} 66 } {1 {no such table: t2}} 67 do_test temptable-1.8 { 68 db2 eval {INSERT INTO t2 VALUES(8,9,0);} 69 db2 eval {SELECT * FROM t2 ORDER BY x} 70 } {4 5 6 8 9 0} 71 do_test temptable-1.9 { 72 db2 eval {DELETE FROM t2 WHERE x==8} 73 db2 eval {SELECT * FROM t2 ORDER BY x} 74 } {4 5 6} 75 do_test temptable-1.10 { 76 db2 eval {DELETE FROM t2} 77 db2 eval {SELECT * FROM t2} 78 } {} 79 do_test temptable-1.11 { 80 db2 eval { 81 INSERT INTO t2 VALUES(7,6,5); 82 INSERT INTO t2 VALUES(4,3,2); 83 SELECT * FROM t2 ORDER BY x; 84 } 85 } {4 3 2 7 6 5} 86 do_test temptable-1.12 { 87 db2 eval {DROP TABLE t2;} 88 set r [catch {db2 eval {SELECT * FROM t2}} msg] 89 lappend r $msg 90 } {1 {no such table: t2}} 91 92 # Make sure temporary tables work with transactions 93 # 94 do_test temptable-2.1 { 95 execsql { 96 BEGIN TRANSACTION; 97 CREATE TEMPORARY TABLE t2(x,y); 98 INSERT INTO t2 VALUES(1,2); 99 SELECT * FROM t2; 100 } 101 } {1 2} 102 do_test temptable-2.2 { 103 execsql {ROLLBACK} 104 catchsql {SELECT * FROM t2} 105 } {1 {no such table: t2}} 106 do_test temptable-2.3 { 107 execsql { 108 BEGIN TRANSACTION; 109 CREATE TEMPORARY TABLE t2(x,y); 110 INSERT INTO t2 VALUES(1,2); 111 SELECT * FROM t2; 112 } 113 } {1 2} 114 do_test temptable-2.4 { 115 execsql {COMMIT} 116 catchsql {SELECT * FROM t2} 117 } {0 {1 2}} 118 do_test temptable-2.5 { 119 set r [catch {db2 eval {SELECT * FROM t2}} msg] 120 lappend r $msg 121 } {1 {no such table: t2}} 122 123 # Make sure indices on temporary tables are also temporary. 124 # 125 do_test temptable-3.1 { 126 execsql { 127 CREATE INDEX i2 ON t2(x); 128 SELECT name FROM sqlite_master WHERE type='index'; 129 } 130 } {} 131 do_test temptable-3.2 { 132 execsql { 133 SELECT y FROM t2 WHERE x=1; 134 } 135 } {2} 136 do_test temptable-3.3 { 137 execsql { 138 DROP INDEX i2; 139 SELECT y FROM t2 WHERE x=1; 140 } 141 } {2} 142 do_test temptable-3.4 { 143 execsql { 144 CREATE INDEX i2 ON t2(x); 145 DROP TABLE t2; 146 } 147 catchsql {DROP INDEX i2} 148 } {1 {no such index: i2}} 149 150 # Check for correct name collision processing. A name collision can 151 # occur when process A creates a temporary table T then process B 152 # creates a permanent table also named T. The temp table in process A 153 # hides the existance of the permanent table. 154 # 155 do_test temptable-4.1 { 156 execsql { 157 CREATE TEMP TABLE t2(x,y); 158 INSERT INTO t2 VALUES(10,20); 159 SELECT * FROM t2; 160 } db2 161 } {10 20} 162 do_test temptable-4.2 { 163 execsql { 164 CREATE TABLE t2(x,y,z); 165 INSERT INTO t2 VALUES(9,8,7); 166 SELECT * FROM t2; 167 } 168 } {9 8 7} 169 do_test temptable-4.3 { 170 catchsql { 171 SELECT * FROM t2; 172 } db2 173 } {0 {10 20}} 174 do_test temptable-4.4.1 { 175 catchsql { 176 SELECT * FROM temp.t2; 177 } db2 178 } {0 {10 20}} 179 do_test temptable-4.4.2 { 180 catchsql { 181 SELECT * FROM main.t2; 182 } db2 183 } {0 {9 8 7}} 184 #do_test temptable-4.4.3 { 185 # catchsql { 186 # SELECT name FROM main.sqlite_master WHERE type='table'; 187 # } db2 188 #} {1 {database schema has changed}} 189 do_test temptable-4.4.4 { 190 catchsql { 191 SELECT name FROM main.sqlite_master WHERE type='table'; 192 } db2 193 } {0 {t1 t2}} 194 do_test temptable-4.4.5 { 195 catchsql { 196 SELECT * FROM main.t2; 197 } db2 198 } {0 {9 8 7}} 199 do_test temptable-4.4.6 { 200 # TEMP takes precedence over MAIN 201 catchsql { 202 SELECT * FROM t2; 203 } db2 204 } {0 {10 20}} 205 do_test temptable-4.5 { 206 catchsql { 207 DROP TABLE t2; -- should drop TEMP 208 SELECT * FROM t2; -- data should be from MAIN 209 } db2 210 } {0 {9 8 7}} 211 do_test temptable-4.6 { 212 db2 close 213 sqlite3 db2 ./test.db 214 catchsql { 215 SELECT * FROM t2; 216 } db2 217 } {0 {9 8 7}} 218 do_test temptable-4.7 { 219 catchsql { 220 DROP TABLE t2; 221 SELECT * FROM t2; 222 } 223 } {1 {no such table: t2}} 224 do_test temptable-4.8 { 225 db2 close 226 sqlite3 db2 ./test.db 227 execsql { 228 CREATE TEMP TABLE t2(x unique,y); 229 INSERT INTO t2 VALUES(1,2); 230 SELECT * FROM t2; 231 } db2 232 } {1 2} 233 do_test temptable-4.9 { 234 execsql { 235 CREATE TABLE t2(x unique, y); 236 INSERT INTO t2 VALUES(3,4); 237 SELECT * FROM t2; 238 } 239 } {3 4} 240 do_test temptable-4.10.1 { 241 catchsql { 242 SELECT * FROM t2; 243 } db2 244 } {0 {1 2}} 245 # Update: The schema is reloaded in test temptable-4.10.1. And tclsqlite.c 246 # handles it and retries the query anyway. 247 # do_test temptable-4.10.2 { 248 # catchsql { 249 # SELECT name FROM sqlite_master WHERE type='table' 250 # } db2 251 # } {1 {database schema has changed}} 252 do_test temptable-4.10.3 { 253 catchsql { 254 SELECT name FROM sqlite_master WHERE type='table' 255 } db2 256 } {0 {t1 t2}} 257 do_test temptable-4.11 { 258 execsql { 259 SELECT * FROM t2; 260 } db2 261 } {1 2} 262 do_test temptable-4.12 { 263 execsql { 264 SELECT * FROM t2; 265 } 266 } {3 4} 267 do_test temptable-4.13 { 268 catchsql { 269 DROP TABLE t2; -- drops TEMP.T2 270 SELECT * FROM t2; -- uses MAIN.T2 271 } db2 272 } {0 {3 4}} 273 do_test temptable-4.14 { 274 execsql { 275 SELECT * FROM t2; 276 } 277 } {3 4} 278 do_test temptable-4.15 { 279 db2 close 280 sqlite3 db2 ./test.db 281 execsql { 282 SELECT * FROM t2; 283 } db2 284 } {3 4} 285 286 # Now create a temporary table in db2 and a permanent index in db. The 287 # temporary table in db2 should mask the name of the permanent index, 288 # but the permanent index should still be accessible and should still 289 # be updated when its corresponding table changes. 290 # 291 do_test temptable-5.1 { 292 execsql { 293 CREATE TEMP TABLE mask(a,b,c) 294 } db2 295 execsql { 296 CREATE INDEX mask ON t2(x); 297 SELECT * FROM t2; 298 } 299 } {3 4} 300 #do_test temptable-5.2 { 301 # catchsql { 302 # SELECT * FROM t2; 303 # } db2 304 #} {1 {database schema has changed}} 305 do_test temptable-5.3 { 306 catchsql { 307 SELECT * FROM t2; 308 } db2 309 } {0 {3 4}} 310 do_test temptable-5.4 { 311 execsql { 312 SELECT y FROM t2 WHERE x=3 313 } 314 } {4} 315 do_test temptable-5.5 { 316 execsql { 317 SELECT y FROM t2 WHERE x=3 318 } db2 319 } {4} 320 do_test temptable-5.6 { 321 execsql { 322 INSERT INTO t2 VALUES(1,2); 323 SELECT y FROM t2 WHERE x=1; 324 } db2 325 } {2} 326 do_test temptable-5.7 { 327 execsql { 328 SELECT y FROM t2 WHERE x=3 329 } db2 330 } {4} 331 do_test temptable-5.8 { 332 execsql { 333 SELECT y FROM t2 WHERE x=1; 334 } 335 } {2} 336 do_test temptable-5.9 { 337 execsql { 338 SELECT y FROM t2 WHERE x=3 339 } 340 } {4} 341 342 db2 close 343 344 # Test for correct operation of read-only databases 345 # 346 do_test temptable-6.1 { 347 execsql { 348 CREATE TABLE t8(x); 349 INSERT INTO t8 VALUES('xyzzy'); 350 SELECT * FROM t8; 351 } 352 } {xyzzy} 353 do_test temptable-6.2 { 354 db close 355 catch {file attributes test.db -permissions 0444} 356 catch {file attributes test.db -readonly 1} 357 sqlite3 db test.db 358 if {[file writable test.db]} { 359 error "Unable to make the database file test.db readonly - rerun this test as an unprivileged user" 360 } 361 execsql { 362 SELECT * FROM t8; 363 } 364 } {xyzzy} 365 do_test temptable-6.3 { 366 if {[file writable test.db]} { 367 error "Unable to make the database file test.db readonly - rerun this test as an unprivileged user" 368 } 369 catchsql { 370 CREATE TABLE t9(x,y); 371 } 372 } {1 {attempt to write a readonly database}} 373 do_test temptable-6.4 { 374 catchsql { 375 CREATE TEMP TABLE t9(x,y); 376 } 377 } {0 {}} 378 do_test temptable-6.5 { 379 catchsql { 380 INSERT INTO t9 VALUES(1,2); 381 SELECT * FROM t9; 382 } 383 } {0 {1 2}} 384 do_test temptable-6.6 { 385 if {[file writable test.db]} { 386 error "Unable to make the database file test.db readonly - rerun this test as an unprivileged user" 387 } 388 catchsql { 389 INSERT INTO t8 VALUES('hello'); 390 SELECT * FROM t8; 391 } 392 } {1 {attempt to write a readonly database}} 393 do_test temptable-6.7 { 394 catchsql { 395 SELECT * FROM t8,t9; 396 } 397 } {0 {xyzzy 1 2}} 398 do_test temptable-6.8 { 399 db close 400 sqlite3 db test.db 401 catchsql { 402 SELECT * FROM t8,t9; 403 } 404 } {1 {no such table: t9}} 405 406 file delete -force test2.db test2.db-journal 407 ifcapable attach { 408 do_test temptable-7.1 { 409 catchsql { 410 ATTACH 'test2.db' AS two; 411 CREATE TEMP TABLE two.abc(x,y); 412 } 413 } {1 {temporary table name must be unqualified}} 414 } 415 416 # Need to do the following for tcl 8.5 on mac. On that configuration, the 417 # -readonly flag is taken so seriously that a subsequent [file delete -force] 418 # (required before the next test file can be executed) will fail. 419 # 420 catch {file attributes test.db -readonly 0} 421 422 do_test temptable-8.0 { 423 db close 424 catch {file delete -force test.db} 425 sqlite3 db test.db 426 } {} 427 do_test temptable-8.1 { 428 execsql { CREATE TEMP TABLE tbl2(a, b); } 429 execsql { 430 CREATE TABLE tbl(a, b); 431 INSERT INTO tbl VALUES(1, 2); 432 } 433 execsql {SELECT * FROM tbl} 434 } {1 2} 435 do_test temptable-8.2 { 436 execsql { CREATE TEMP TABLE tbl(a, b); } 437 execsql {SELECT * FROM tbl} 438 } {} 439 440 finish_test 441