1f57b3399Sdrh# 2001 October 7 2f57b3399Sdrh# 3f57b3399Sdrh# The author disclaims copyright to this source code. In place of 4f57b3399Sdrh# a legal notice, here is a blessing: 5f57b3399Sdrh# 6f57b3399Sdrh# May you do good and not evil. 7f57b3399Sdrh# May you find forgiveness for yourself and forgive others. 8f57b3399Sdrh# May you share freely, never taking more than you give. 9f57b3399Sdrh# 10f57b3399Sdrh#*********************************************************************** 11f57b3399Sdrh# This file implements regression tests for SQLite library. 12f57b3399Sdrh# 13f57b3399Sdrh# This file implements tests for temporary tables and indices. 14f57b3399Sdrh# 159da742f9Sdrh# $Id: temptable.test,v 1.21 2009/06/16 17:49:36 drh Exp $ 16f57b3399Sdrh 17f57b3399Sdrhset testdir [file dirname $argv0] 18f57b3399Sdrhsource $testdir/tester.tcl 19f57b3399Sdrh 2053c0f748Sdanielk1977ifcapable !tempdb { 2153c0f748Sdanielk1977 finish_test 2253c0f748Sdanielk1977 return 2353c0f748Sdanielk1977} 2453c0f748Sdanielk1977 25f57b3399Sdrh# Create an alternative connection to the database 26f57b3399Sdrh# 27f57b3399Sdrhdo_test temptable-1.0 { 28ef4ac8f9Sdrh sqlite3 db2 ./test.db 29c22bd47dSdrh set dummy {} 30f57b3399Sdrh} {} 31f57b3399Sdrh 32f57b3399Sdrh# Create a permanent table. 33f57b3399Sdrh# 34f57b3399Sdrhdo_test temptable-1.1 { 35f57b3399Sdrh execsql {CREATE TABLE t1(a,b,c);} 36f57b3399Sdrh execsql {INSERT INTO t1 VALUES(1,2,3);} 37f57b3399Sdrh execsql {SELECT * FROM t1} 38f57b3399Sdrh} {1 2 3} 39f57b3399Sdrhdo_test temptable-1.2 { 40f57b3399Sdrh catch {db2 eval {SELECT * FROM sqlite_master}} 41f57b3399Sdrh db2 eval {SELECT * FROM t1} 42f57b3399Sdrh} {1 2 3} 43ad75e987Sdrhdo_test temptable-1.3 { 44f57b3399Sdrh execsql {SELECT name FROM sqlite_master} 45f57b3399Sdrh} {t1} 46ad75e987Sdrhdo_test temptable-1.4 { 47f57b3399Sdrh db2 eval {SELECT name FROM sqlite_master} 48f57b3399Sdrh} {t1} 49f57b3399Sdrh 50f57b3399Sdrh# Create a temporary table. Verify that only one of the two 51f57b3399Sdrh# processes can see it. 52f57b3399Sdrh# 53ad75e987Sdrhdo_test temptable-1.5 { 54f57b3399Sdrh db2 eval { 55f57b3399Sdrh CREATE TEMP TABLE t2(x,y,z); 56f57b3399Sdrh INSERT INTO t2 VALUES(4,5,6); 57f57b3399Sdrh } 58f57b3399Sdrh db2 eval {SELECT * FROM t2} 59f57b3399Sdrh} {4 5 6} 60ad75e987Sdrhdo_test temptable-1.6 { 61f57b3399Sdrh catch {execsql {SELECT * FROM sqlite_master}} 62f57b3399Sdrh catchsql {SELECT * FROM t2} 63f57b3399Sdrh} {1 {no such table: t2}} 64ad75e987Sdrhdo_test temptable-1.7 { 65f57b3399Sdrh catchsql {INSERT INTO t2 VALUES(8,9,0);} 66f57b3399Sdrh} {1 {no such table: t2}} 67ad75e987Sdrhdo_test temptable-1.8 { 68f57b3399Sdrh db2 eval {INSERT INTO t2 VALUES(8,9,0);} 69f57b3399Sdrh db2 eval {SELECT * FROM t2 ORDER BY x} 70f57b3399Sdrh} {4 5 6 8 9 0} 71ad75e987Sdrhdo_test temptable-1.9 { 72f57b3399Sdrh db2 eval {DELETE FROM t2 WHERE x==8} 73f57b3399Sdrh db2 eval {SELECT * FROM t2 ORDER BY x} 74f57b3399Sdrh} {4 5 6} 75ad75e987Sdrhdo_test temptable-1.10 { 76f57b3399Sdrh db2 eval {DELETE FROM t2} 77f57b3399Sdrh db2 eval {SELECT * FROM t2} 78f57b3399Sdrh} {} 79ad75e987Sdrhdo_test temptable-1.11 { 80f57b3399Sdrh db2 eval { 81f57b3399Sdrh INSERT INTO t2 VALUES(7,6,5); 82f57b3399Sdrh INSERT INTO t2 VALUES(4,3,2); 83f57b3399Sdrh SELECT * FROM t2 ORDER BY x; 84f57b3399Sdrh } 85f57b3399Sdrh} {4 3 2 7 6 5} 86ad75e987Sdrhdo_test temptable-1.12 { 87f57b3399Sdrh db2 eval {DROP TABLE t2;} 88f57b3399Sdrh set r [catch {db2 eval {SELECT * FROM t2}} msg] 89f57b3399Sdrh lappend r $msg 90f57b3399Sdrh} {1 {no such table: t2}} 91f57b3399Sdrh 92f57b3399Sdrh# Make sure temporary tables work with transactions 93f57b3399Sdrh# 94ad75e987Sdrhdo_test temptable-2.1 { 95f57b3399Sdrh execsql { 96f57b3399Sdrh BEGIN TRANSACTION; 97f57b3399Sdrh CREATE TEMPORARY TABLE t2(x,y); 98f57b3399Sdrh INSERT INTO t2 VALUES(1,2); 99f57b3399Sdrh SELECT * FROM t2; 100f57b3399Sdrh } 101f57b3399Sdrh} {1 2} 102ad75e987Sdrhdo_test temptable-2.2 { 103f57b3399Sdrh execsql {ROLLBACK} 104f57b3399Sdrh catchsql {SELECT * FROM t2} 105f57b3399Sdrh} {1 {no such table: t2}} 106ad75e987Sdrhdo_test temptable-2.3 { 107f57b3399Sdrh execsql { 108f57b3399Sdrh BEGIN TRANSACTION; 109f57b3399Sdrh CREATE TEMPORARY TABLE t2(x,y); 110f57b3399Sdrh INSERT INTO t2 VALUES(1,2); 111f57b3399Sdrh SELECT * FROM t2; 112f57b3399Sdrh } 113f57b3399Sdrh} {1 2} 114ad75e987Sdrhdo_test temptable-2.4 { 115f57b3399Sdrh execsql {COMMIT} 116f57b3399Sdrh catchsql {SELECT * FROM t2} 117f57b3399Sdrh} {0 {1 2}} 118ad75e987Sdrhdo_test temptable-2.5 { 119f57b3399Sdrh set r [catch {db2 eval {SELECT * FROM t2}} msg] 120f57b3399Sdrh lappend r $msg 121f57b3399Sdrh} {1 {no such table: t2}} 122f57b3399Sdrh 123ad75e987Sdrh# Make sure indices on temporary tables are also temporary. 124ad75e987Sdrh# 125ad75e987Sdrhdo_test temptable-3.1 { 126ad75e987Sdrh execsql { 127ad75e987Sdrh CREATE INDEX i2 ON t2(x); 128ad75e987Sdrh SELECT name FROM sqlite_master WHERE type='index'; 129ad75e987Sdrh } 130ad75e987Sdrh} {} 131ad75e987Sdrhdo_test temptable-3.2 { 132ad75e987Sdrh execsql { 133ad75e987Sdrh SELECT y FROM t2 WHERE x=1; 134ad75e987Sdrh } 135ad75e987Sdrh} {2} 136ad75e987Sdrhdo_test temptable-3.3 { 137ad75e987Sdrh execsql { 138ad75e987Sdrh DROP INDEX i2; 139ad75e987Sdrh SELECT y FROM t2 WHERE x=1; 140ad75e987Sdrh } 141ad75e987Sdrh} {2} 142ad75e987Sdrhdo_test temptable-3.4 { 143ad75e987Sdrh execsql { 144ad75e987Sdrh CREATE INDEX i2 ON t2(x); 145ad75e987Sdrh DROP TABLE t2; 146ad75e987Sdrh } 147ad75e987Sdrh catchsql {DROP INDEX i2} 148ad75e987Sdrh} {1 {no such index: i2}} 149ad75e987Sdrh 150f57b3399Sdrh# Check for correct name collision processing. A name collision can 151f57b3399Sdrh# occur when process A creates a temporary table T then process B 152f57b3399Sdrh# creates a permanent table also named T. The temp table in process A 153*48864df9Smistachkin# hides the existence of the permanent table. 154f57b3399Sdrh# 155ad75e987Sdrhdo_test temptable-4.1 { 156da9e0346Sdrh execsql { 157ad75e987Sdrh CREATE TEMP TABLE t2(x,y); 158ad75e987Sdrh INSERT INTO t2 VALUES(10,20); 159ad75e987Sdrh SELECT * FROM t2; 160da9e0346Sdrh } db2 161ad75e987Sdrh} {10 20} 162ad75e987Sdrhdo_test temptable-4.2 { 163ad75e987Sdrh execsql { 164ad75e987Sdrh CREATE TABLE t2(x,y,z); 165ad75e987Sdrh INSERT INTO t2 VALUES(9,8,7); 166ad75e987Sdrh SELECT * FROM t2; 167ad75e987Sdrh } 168ad75e987Sdrh} {9 8 7} 169ad75e987Sdrhdo_test temptable-4.3 { 170da9e0346Sdrh catchsql { 171da9e0346Sdrh SELECT * FROM t2; 172da9e0346Sdrh } db2 1738bf8dc92Sdrh} {0 {10 20}} 1740be9df07Sdrhdo_test temptable-4.4.1 { 1750be9df07Sdrh catchsql { 1760be9df07Sdrh SELECT * FROM temp.t2; 1770be9df07Sdrh } db2 1780be9df07Sdrh} {0 {10 20}} 1790be9df07Sdrhdo_test temptable-4.4.2 { 1800be9df07Sdrh catchsql { 1810be9df07Sdrh SELECT * FROM main.t2; 1820be9df07Sdrh } db2 1839da742f9Sdrh} {0 {9 8 7}} 184a1f9b5eeSdrh#do_test temptable-4.4.3 { 185a1f9b5eeSdrh# catchsql { 186a1f9b5eeSdrh# SELECT name FROM main.sqlite_master WHERE type='table'; 187a1f9b5eeSdrh# } db2 188a1f9b5eeSdrh#} {1 {database schema has changed}} 1898bf8dc92Sdrhdo_test temptable-4.4.4 { 1908bf8dc92Sdrh catchsql { 1918bf8dc92Sdrh SELECT name FROM main.sqlite_master WHERE type='table'; 1928bf8dc92Sdrh } db2 1938bf8dc92Sdrh} {0 {t1 t2}} 1948bf8dc92Sdrhdo_test temptable-4.4.5 { 1958bf8dc92Sdrh catchsql { 1968bf8dc92Sdrh SELECT * FROM main.t2; 1978bf8dc92Sdrh } db2 1988bf8dc92Sdrh} {0 {9 8 7}} 1998bf8dc92Sdrhdo_test temptable-4.4.6 { 2000be9df07Sdrh # TEMP takes precedence over MAIN 201da9e0346Sdrh catchsql { 202da9e0346Sdrh SELECT * FROM t2; 203da9e0346Sdrh } db2 204ad75e987Sdrh} {0 {10 20}} 205ad75e987Sdrhdo_test temptable-4.5 { 206da9e0346Sdrh catchsql { 2070be9df07Sdrh DROP TABLE t2; -- should drop TEMP 2080be9df07Sdrh SELECT * FROM t2; -- data should be from MAIN 209da9e0346Sdrh } db2 2100be9df07Sdrh} {0 {9 8 7}} 211ad75e987Sdrhdo_test temptable-4.6 { 212ad75e987Sdrh db2 close 213ef4ac8f9Sdrh sqlite3 db2 ./test.db 214da9e0346Sdrh catchsql { 215da9e0346Sdrh SELECT * FROM t2; 216da9e0346Sdrh } db2 217ad75e987Sdrh} {0 {9 8 7}} 218da9e0346Sdrhdo_test temptable-4.7 { 219da9e0346Sdrh catchsql { 220da9e0346Sdrh DROP TABLE t2; 221da9e0346Sdrh SELECT * FROM t2; 222da9e0346Sdrh } 223da9e0346Sdrh} {1 {no such table: t2}} 224da9e0346Sdrhdo_test temptable-4.8 { 225da9e0346Sdrh db2 close 226ef4ac8f9Sdrh sqlite3 db2 ./test.db 227da9e0346Sdrh execsql { 228da9e0346Sdrh CREATE TEMP TABLE t2(x unique,y); 229da9e0346Sdrh INSERT INTO t2 VALUES(1,2); 230da9e0346Sdrh SELECT * FROM t2; 231da9e0346Sdrh } db2 232da9e0346Sdrh} {1 2} 233da9e0346Sdrhdo_test temptable-4.9 { 234da9e0346Sdrh execsql { 235da9e0346Sdrh CREATE TABLE t2(x unique, y); 236da9e0346Sdrh INSERT INTO t2 VALUES(3,4); 237da9e0346Sdrh SELECT * FROM t2; 238da9e0346Sdrh } 239da9e0346Sdrh} {3 4} 2408bf8dc92Sdrhdo_test temptable-4.10.1 { 241da9e0346Sdrh catchsql { 242da9e0346Sdrh SELECT * FROM t2; 243da9e0346Sdrh } db2 2448bf8dc92Sdrh} {0 {1 2}} 245f9d19a6bSdanielk1977# Update: The schema is reloaded in test temptable-4.10.1. And tclsqlite.c 246f9d19a6bSdanielk1977# handles it and retries the query anyway. 247f9d19a6bSdanielk1977# do_test temptable-4.10.2 { 248f9d19a6bSdanielk1977# catchsql { 249f9d19a6bSdanielk1977# SELECT name FROM sqlite_master WHERE type='table' 250f9d19a6bSdanielk1977# } db2 251f9d19a6bSdanielk1977# } {1 {database schema has changed}} 2528bf8dc92Sdrhdo_test temptable-4.10.3 { 2538bf8dc92Sdrh catchsql { 2548bf8dc92Sdrh SELECT name FROM sqlite_master WHERE type='table' 2558bf8dc92Sdrh } db2 2568bf8dc92Sdrh} {0 {t1 t2}} 257da9e0346Sdrhdo_test temptable-4.11 { 258da9e0346Sdrh execsql { 259da9e0346Sdrh SELECT * FROM t2; 260da9e0346Sdrh } db2 261da9e0346Sdrh} {1 2} 262da9e0346Sdrhdo_test temptable-4.12 { 263da9e0346Sdrh execsql { 264da9e0346Sdrh SELECT * FROM t2; 265da9e0346Sdrh } 266da9e0346Sdrh} {3 4} 267da9e0346Sdrhdo_test temptable-4.13 { 268da9e0346Sdrh catchsql { 2690be9df07Sdrh DROP TABLE t2; -- drops TEMP.T2 2700be9df07Sdrh SELECT * FROM t2; -- uses MAIN.T2 271da9e0346Sdrh } db2 2720be9df07Sdrh} {0 {3 4}} 273da9e0346Sdrhdo_test temptable-4.14 { 274da9e0346Sdrh execsql { 275da9e0346Sdrh SELECT * FROM t2; 276da9e0346Sdrh } 277da9e0346Sdrh} {3 4} 278da9e0346Sdrhdo_test temptable-4.15 { 279da9e0346Sdrh db2 close 280ef4ac8f9Sdrh sqlite3 db2 ./test.db 281da9e0346Sdrh execsql { 282da9e0346Sdrh SELECT * FROM t2; 283da9e0346Sdrh } db2 284da9e0346Sdrh} {3 4} 285ad75e987Sdrh 286ad75e987Sdrh# Now create a temporary table in db2 and a permanent index in db. The 287ad75e987Sdrh# temporary table in db2 should mask the name of the permanent index, 288ad75e987Sdrh# but the permanent index should still be accessible and should still 289da9e0346Sdrh# be updated when its corresponding table changes. 290ad75e987Sdrh# 291ad75e987Sdrhdo_test temptable-5.1 { 292da9e0346Sdrh execsql { 293da9e0346Sdrh CREATE TEMP TABLE mask(a,b,c) 294da9e0346Sdrh } db2 295c431fd55Sdan if {[permutation]=="prepare"} { db2 cache flush } 296ad75e987Sdrh execsql { 297ad75e987Sdrh CREATE INDEX mask ON t2(x); 298ad75e987Sdrh SELECT * FROM t2; 299ad75e987Sdrh } 300da9e0346Sdrh} {3 4} 301a1f9b5eeSdrh#do_test temptable-5.2 { 302a1f9b5eeSdrh# catchsql { 303a1f9b5eeSdrh# SELECT * FROM t2; 304a1f9b5eeSdrh# } db2 305a1f9b5eeSdrh#} {1 {database schema has changed}} 306ad75e987Sdrhdo_test temptable-5.3 { 307da9e0346Sdrh catchsql { 308da9e0346Sdrh SELECT * FROM t2; 309da9e0346Sdrh } db2 310da9e0346Sdrh} {0 {3 4}} 311ad75e987Sdrhdo_test temptable-5.4 { 312da9e0346Sdrh execsql { 313da9e0346Sdrh SELECT y FROM t2 WHERE x=3 314ad75e987Sdrh } 315da9e0346Sdrh} {4} 316da9e0346Sdrhdo_test temptable-5.5 { 317da9e0346Sdrh execsql { 318da9e0346Sdrh SELECT y FROM t2 WHERE x=3 319da9e0346Sdrh } db2 320da9e0346Sdrh} {4} 321da9e0346Sdrhdo_test temptable-5.6 { 322da9e0346Sdrh execsql { 323da9e0346Sdrh INSERT INTO t2 VALUES(1,2); 324da9e0346Sdrh SELECT y FROM t2 WHERE x=1; 325da9e0346Sdrh } db2 326ad75e987Sdrh} {2} 327ad75e987Sdrhdo_test temptable-5.7 { 328da9e0346Sdrh execsql { 329da9e0346Sdrh SELECT y FROM t2 WHERE x=3 330da9e0346Sdrh } db2 331da9e0346Sdrh} {4} 332ad75e987Sdrhdo_test temptable-5.8 { 333ad75e987Sdrh execsql { 334ad75e987Sdrh SELECT y FROM t2 WHERE x=1; 335ad75e987Sdrh } 336ad75e987Sdrh} {2} 337ad75e987Sdrhdo_test temptable-5.9 { 338da9e0346Sdrh execsql { 339da9e0346Sdrh SELECT y FROM t2 WHERE x=3 340da9e0346Sdrh } 341da9e0346Sdrh} {4} 342f57b3399Sdrh 343ff0839c0Sdrhdb2 close 344ff0839c0Sdrh 3455df72a5aSdrh# Test for correct operation of read-only databases 3465df72a5aSdrh# 3475df72a5aSdrhdo_test temptable-6.1 { 3485df72a5aSdrh execsql { 3495df72a5aSdrh CREATE TABLE t8(x); 3505df72a5aSdrh INSERT INTO t8 VALUES('xyzzy'); 3515df72a5aSdrh SELECT * FROM t8; 3525df72a5aSdrh } 3535df72a5aSdrh} {xyzzy} 3545df72a5aSdrhdo_test temptable-6.2 { 3555df72a5aSdrh db close 3565df72a5aSdrh catch {file attributes test.db -permissions 0444} 3575df72a5aSdrh catch {file attributes test.db -readonly 1} 358ef4ac8f9Sdrh sqlite3 db test.db 3590e1cfb85Sdrh if {[file writable test.db]} { 3600e1cfb85Sdrh error "Unable to make the database file test.db readonly - rerun this test as an unprivileged user" 3610e1cfb85Sdrh } 3625df72a5aSdrh execsql { 3635df72a5aSdrh SELECT * FROM t8; 3645df72a5aSdrh } 3655df72a5aSdrh} {xyzzy} 3665df72a5aSdrhdo_test temptable-6.3 { 3670e1cfb85Sdrh if {[file writable test.db]} { 3680e1cfb85Sdrh error "Unable to make the database file test.db readonly - rerun this test as an unprivileged user" 3690e1cfb85Sdrh } 3705df72a5aSdrh catchsql { 3715df72a5aSdrh CREATE TABLE t9(x,y); 3725df72a5aSdrh } 3735df72a5aSdrh} {1 {attempt to write a readonly database}} 3745df72a5aSdrhdo_test temptable-6.4 { 3755df72a5aSdrh catchsql { 3765df72a5aSdrh CREATE TEMP TABLE t9(x,y); 3775df72a5aSdrh } 3785df72a5aSdrh} {0 {}} 3795df72a5aSdrhdo_test temptable-6.5 { 3805df72a5aSdrh catchsql { 3815df72a5aSdrh INSERT INTO t9 VALUES(1,2); 3825df72a5aSdrh SELECT * FROM t9; 3835df72a5aSdrh } 3845df72a5aSdrh} {0 {1 2}} 3855df72a5aSdrhdo_test temptable-6.6 { 3860e1cfb85Sdrh if {[file writable test.db]} { 3870e1cfb85Sdrh error "Unable to make the database file test.db readonly - rerun this test as an unprivileged user" 3880e1cfb85Sdrh } 3895df72a5aSdrh catchsql { 3905df72a5aSdrh INSERT INTO t8 VALUES('hello'); 3915df72a5aSdrh SELECT * FROM t8; 3925df72a5aSdrh } 3935df72a5aSdrh} {1 {attempt to write a readonly database}} 3945df72a5aSdrhdo_test temptable-6.7 { 3955df72a5aSdrh catchsql { 3965df72a5aSdrh SELECT * FROM t8,t9; 3975df72a5aSdrh } 3985df72a5aSdrh} {0 {xyzzy 1 2}} 3995df72a5aSdrhdo_test temptable-6.8 { 4005df72a5aSdrh db close 401ef4ac8f9Sdrh sqlite3 db test.db 4025df72a5aSdrh catchsql { 4035df72a5aSdrh SELECT * FROM t8,t9; 4045df72a5aSdrh } 4055df72a5aSdrh} {1 {no such table: t9}} 4065df72a5aSdrh 407fda06befSmistachkinforcedelete test2.db test2.db-journal 4085a8f9374Sdanielk1977ifcapable attach { 40985c23c61Sdrh do_test temptable-7.1 { 41085c23c61Sdrh catchsql { 41185c23c61Sdrh ATTACH 'test2.db' AS two; 41285c23c61Sdrh CREATE TEMP TABLE two.abc(x,y); 41385c23c61Sdrh } 41485c23c61Sdrh } {1 {temporary table name must be unqualified}} 4155a8f9374Sdanielk1977} 41685c23c61Sdrh 417382e28faSdanielk1977# Need to do the following for tcl 8.5 on mac. On that configuration, the 418fda06befSmistachkin# -readonly flag is taken so seriously that a subsequent [forcedelete] 419382e28faSdanielk1977# (required before the next test file can be executed) will fail. 420382e28faSdanielk1977# 421382e28faSdanielk1977catch {file attributes test.db -readonly 0} 422382e28faSdanielk1977 423cd503d6aSdanielk1977do_test temptable-8.0 { 424cd503d6aSdanielk1977 db close 425fda06befSmistachkin catch {forcedelete test.db} 426cd503d6aSdanielk1977 sqlite3 db test.db 427cd503d6aSdanielk1977} {} 428cd503d6aSdanielk1977do_test temptable-8.1 { 429cd503d6aSdanielk1977 execsql { CREATE TEMP TABLE tbl2(a, b); } 430cd503d6aSdanielk1977 execsql { 431cd503d6aSdanielk1977 CREATE TABLE tbl(a, b); 432cd503d6aSdanielk1977 INSERT INTO tbl VALUES(1, 2); 433cd503d6aSdanielk1977 } 434cd503d6aSdanielk1977 execsql {SELECT * FROM tbl} 435cd503d6aSdanielk1977} {1 2} 436cd503d6aSdanielk1977do_test temptable-8.2 { 437cd503d6aSdanielk1977 execsql { CREATE TEMP TABLE tbl(a, b); } 438cd503d6aSdanielk1977 execsql {SELECT * FROM tbl} 439cd503d6aSdanielk1977} {} 440cd503d6aSdanielk1977 441f57b3399Sdrhfinish_test 442