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 17set testdir [file dirname $argv0] 18source $testdir/tester.tcl 19 20ifcapable !tempdb { 21 finish_test 22 return 23} 24 25# Create an alternative connection to the database 26# 27do_test temptable-1.0 { 28 sqlite3 db2 ./test.db 29 set dummy {} 30} {} 31 32# Create a permanent table. 33# 34do_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} 39do_test temptable-1.2 { 40 catch {db2 eval {SELECT * FROM sqlite_master}} 41 db2 eval {SELECT * FROM t1} 42} {1 2 3} 43do_test temptable-1.3 { 44 execsql {SELECT name FROM sqlite_master} 45} {t1} 46do_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# 53do_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} 60do_test temptable-1.6 { 61 catch {execsql {SELECT * FROM sqlite_master}} 62 catchsql {SELECT * FROM t2} 63} {1 {no such table: t2}} 64do_test temptable-1.7 { 65 catchsql {INSERT INTO t2 VALUES(8,9,0);} 66} {1 {no such table: t2}} 67do_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} 71do_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} 75do_test temptable-1.10 { 76 db2 eval {DELETE FROM t2} 77 db2 eval {SELECT * FROM t2} 78} {} 79do_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} 86do_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# 94do_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} 102do_test temptable-2.2 { 103 execsql {ROLLBACK} 104 catchsql {SELECT * FROM t2} 105} {1 {no such table: t2}} 106do_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} 114do_test temptable-2.4 { 115 execsql {COMMIT} 116 catchsql {SELECT * FROM t2} 117} {0 {1 2}} 118do_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# 125do_test temptable-3.1 { 126 execsql { 127 CREATE INDEX i2 ON t2(x); 128 SELECT name FROM sqlite_master WHERE type='index'; 129 } 130} {} 131do_test temptable-3.2 { 132 execsql { 133 SELECT y FROM t2 WHERE x=1; 134 } 135} {2} 136do_test temptable-3.3 { 137 execsql { 138 DROP INDEX i2; 139 SELECT y FROM t2 WHERE x=1; 140 } 141} {2} 142do_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# 155do_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} 162do_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} 169do_test temptable-4.3 { 170 catchsql { 171 SELECT * FROM t2; 172 } db2 173} {0 {10 20}} 174do_test temptable-4.4.1 { 175 catchsql { 176 SELECT * FROM temp.t2; 177 } db2 178} {0 {10 20}} 179do_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}} 189do_test temptable-4.4.4 { 190 catchsql { 191 SELECT name FROM main.sqlite_master WHERE type='table'; 192 } db2 193} {0 {t1 t2}} 194do_test temptable-4.4.5 { 195 catchsql { 196 SELECT * FROM main.t2; 197 } db2 198} {0 {9 8 7}} 199do_test temptable-4.4.6 { 200 # TEMP takes precedence over MAIN 201 catchsql { 202 SELECT * FROM t2; 203 } db2 204} {0 {10 20}} 205do_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}} 211do_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}} 218do_test temptable-4.7 { 219 catchsql { 220 DROP TABLE t2; 221 SELECT * FROM t2; 222 } 223} {1 {no such table: t2}} 224do_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} 233do_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} 240do_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}} 252do_test temptable-4.10.3 { 253 catchsql { 254 SELECT name FROM sqlite_master WHERE type='table' 255 } db2 256} {0 {t1 t2}} 257do_test temptable-4.11 { 258 execsql { 259 SELECT * FROM t2; 260 } db2 261} {1 2} 262do_test temptable-4.12 { 263 execsql { 264 SELECT * FROM t2; 265 } 266} {3 4} 267do_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}} 273do_test temptable-4.14 { 274 execsql { 275 SELECT * FROM t2; 276 } 277} {3 4} 278do_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# 291do_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}} 305do_test temptable-5.3 { 306 catchsql { 307 SELECT * FROM t2; 308 } db2 309} {0 {3 4}} 310do_test temptable-5.4 { 311 execsql { 312 SELECT y FROM t2 WHERE x=3 313 } 314} {4} 315do_test temptable-5.5 { 316 execsql { 317 SELECT y FROM t2 WHERE x=3 318 } db2 319} {4} 320do_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} 326do_test temptable-5.7 { 327 execsql { 328 SELECT y FROM t2 WHERE x=3 329 } db2 330} {4} 331do_test temptable-5.8 { 332 execsql { 333 SELECT y FROM t2 WHERE x=1; 334 } 335} {2} 336do_test temptable-5.9 { 337 execsql { 338 SELECT y FROM t2 WHERE x=3 339 } 340} {4} 341 342db2 close 343 344# Test for correct operation of read-only databases 345# 346do_test temptable-6.1 { 347 execsql { 348 CREATE TABLE t8(x); 349 INSERT INTO t8 VALUES('xyzzy'); 350 SELECT * FROM t8; 351 } 352} {xyzzy} 353do_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} 365do_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}} 373do_test temptable-6.4 { 374 catchsql { 375 CREATE TEMP TABLE t9(x,y); 376 } 377} {0 {}} 378do_test temptable-6.5 { 379 catchsql { 380 INSERT INTO t9 VALUES(1,2); 381 SELECT * FROM t9; 382 } 383} {0 {1 2}} 384do_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}} 393do_test temptable-6.7 { 394 catchsql { 395 SELECT * FROM t8,t9; 396 } 397} {0 {xyzzy 1 2}} 398do_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 406file delete -force test2.db test2.db-journal 407ifcapable 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# 420catch {file attributes test.db -readonly 0} 421 422do_test temptable-8.0 { 423 db close 424 catch {file delete -force test.db} 425 sqlite3 db test.db 426} {} 427do_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} 435do_test temptable-8.2 { 436 execsql { CREATE TEMP TABLE tbl(a, b); } 437 execsql {SELECT * FROM tbl} 438} {} 439 440finish_test 441