Home | History | Annotate | Download | only in test
      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