1# 2005 February 18 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. The 12# focus of this script is testing that SQLite can handle a subtle 13# file format change that may be used in the future to implement 14# "ALTER TABLE ... ADD COLUMN". 15# 16# $Id: alter2.test,v 1.12 2007/11/28 13:43:17 drh Exp $ 17# 18 19set testdir [file dirname $argv0] 20source $testdir/tester.tcl 21 22# We have to have pragmas in order to do this test 23ifcapable {!pragma} return 24 25# These tests do not work if there is a codec. The 26# btree_open command does not know how to handle codecs. 27# 28#if {[catch {sqlite3 -has_codec} r] || $r} return 29 30# The file format change affects the way row-records stored in tables (but 31# not indices) are interpreted. Before version 3.1.3, a row-record for a 32# table with N columns was guaranteed to contain exactly N fields. As 33# of version 3.1.3, the record may contain up to N fields. In this case 34# the M fields that are present are the values for the left-most M 35# columns. The (N-M) rightmost columns contain NULL. 36# 37# If any records in the database contain less fields than their table 38# has columns, then the file-format meta value should be set to (at least) 2. 39# 40 41# This procedure sets the value of the file-format in file 'test.db' 42# to $newval. Also, the schema cookie is incremented. 43# 44proc set_file_format {newval} { 45 set bt [btree_open test.db 10 0] 46 btree_begin_transaction $bt 47 set meta [btree_get_meta $bt] 48 lset meta 2 $newval ;# File format 49 lset meta 1 [expr [lindex $meta 1]+1] ;# Schema cookie 50 eval "btree_update_meta $bt $meta" 51 btree_commit $bt 52 btree_close $bt 53} 54 55# This procedure returns the value of the file-format in file 'test.db'. 56# 57proc get_file_format {{fname test.db}} { 58 set bt [btree_open $fname 10 0] 59 set meta [btree_get_meta $bt] 60 btree_close $bt 61 lindex $meta 2 62} 63 64# This procedure sets the SQL statement stored for table $tbl in the 65# sqlite_master table of file 'test.db' to $sql. Also set the file format 66# to the supplied value. This is 2 if the added column has a default that is 67# NULL, or 3 otherwise. 68# 69proc alter_table {tbl sql {file_format 2}} { 70 sqlite3 dbat test.db 71 set s [string map {' ''} $sql] 72 set t [string map {' ''} $tbl] 73 dbat eval [subst { 74 PRAGMA writable_schema = 1; 75 UPDATE sqlite_master SET sql = '$s' WHERE name = '$t' AND type = 'table'; 76 PRAGMA writable_schema = 0; 77 }] 78 dbat close 79 set_file_format 2 80} 81 82#----------------------------------------------------------------------- 83# Some basic tests to make sure short rows are handled. 84# 85do_test alter2-1.1 { 86 execsql { 87 CREATE TABLE abc(a, b); 88 INSERT INTO abc VALUES(1, 2); 89 INSERT INTO abc VALUES(3, 4); 90 INSERT INTO abc VALUES(5, 6); 91 } 92} {} 93do_test alter2-1.2 { 94 # ALTER TABLE abc ADD COLUMN c; 95 alter_table abc {CREATE TABLE abc(a, b, c);} 96} {} 97do_test alter2-1.3 { 98 execsql { 99 SELECT * FROM abc; 100 } 101} {1 2 {} 3 4 {} 5 6 {}} 102do_test alter2-1.4 { 103 execsql { 104 UPDATE abc SET c = 10 WHERE a = 1; 105 SELECT * FROM abc; 106 } 107} {1 2 10 3 4 {} 5 6 {}} 108do_test alter2-1.5 { 109 execsql { 110 CREATE INDEX abc_i ON abc(c); 111 } 112} {} 113do_test alter2-1.6 { 114 execsql { 115 SELECT c FROM abc ORDER BY c; 116 } 117} {{} {} 10} 118do_test alter2-1.7 { 119 execsql { 120 SELECT * FROM abc WHERE c = 10; 121 } 122} {1 2 10} 123do_test alter2-1.8 { 124 execsql { 125 SELECT sum(a), c FROM abc GROUP BY c; 126 } 127} {8 {} 1 10} 128do_test alter2-1.9 { 129 # ALTER TABLE abc ADD COLUMN d; 130 alter_table abc {CREATE TABLE abc(a, b, c, d);} 131 execsql { SELECT * FROM abc; } 132 execsql { 133 UPDATE abc SET d = 11 WHERE c IS NULL AND a<4; 134 SELECT * FROM abc; 135 } 136} {1 2 10 {} 3 4 {} 11 5 6 {} {}} 137do_test alter2-1.10 { 138 execsql { 139 SELECT typeof(d) FROM abc; 140 } 141} {null integer null} 142do_test alter2-1.99 { 143 execsql { 144 DROP TABLE abc; 145 } 146} {} 147 148#----------------------------------------------------------------------- 149# Test that views work when the underlying table structure is changed. 150# 151ifcapable view { 152 do_test alter2-2.1 { 153 execsql { 154 CREATE TABLE abc2(a, b, c); 155 INSERT INTO abc2 VALUES(1, 2, 10); 156 INSERT INTO abc2 VALUES(3, 4, NULL); 157 INSERT INTO abc2 VALUES(5, 6, NULL); 158 CREATE VIEW abc2_v AS SELECT * FROM abc2; 159 SELECT * FROM abc2_v; 160 } 161 } {1 2 10 3 4 {} 5 6 {}} 162 do_test alter2-2.2 { 163 # ALTER TABLE abc ADD COLUMN d; 164 alter_table abc2 {CREATE TABLE abc2(a, b, c, d);} 165 execsql { 166 SELECT * FROM abc2_v; 167 } 168 } {1 2 10 {} 3 4 {} {} 5 6 {} {}} 169 do_test alter2-2.3 { 170 execsql { 171 DROP TABLE abc2; 172 DROP VIEW abc2_v; 173 } 174 } {} 175} 176 177#----------------------------------------------------------------------- 178# Test that triggers work when a short row is copied to the old.* 179# trigger pseudo-table. 180# 181ifcapable trigger { 182 do_test alter2-3.1 { 183 execsql { 184 CREATE TABLE abc3(a, b); 185 CREATE TABLE blog(o, n); 186 CREATE TRIGGER abc3_t AFTER UPDATE OF b ON abc3 BEGIN 187 INSERT INTO blog VALUES(old.b, new.b); 188 END; 189 } 190 } {} 191 do_test alter2-3.2 { 192 execsql { 193 INSERT INTO abc3 VALUES(1, 4); 194 UPDATE abc3 SET b = 2 WHERE b = 4; 195 SELECT * FROM blog; 196 } 197 } {4 2} 198 do_test alter2-3.3 { 199 execsql { 200 INSERT INTO abc3 VALUES(3, 4); 201 INSERT INTO abc3 VALUES(5, 6); 202 } 203 alter_table abc3 {CREATE TABLE abc3(a, b, c);} 204 execsql { 205 SELECT * FROM abc3; 206 } 207 } {1 2 {} 3 4 {} 5 6 {}} 208 do_test alter2-3.4 { 209 execsql { 210 UPDATE abc3 SET b = b*2 WHERE a<4; 211 SELECT * FROM abc3; 212 } 213 } {1 4 {} 3 8 {} 5 6 {}} 214 do_test alter2-3.5 { 215 execsql { 216 SELECT * FROM blog; 217 } 218 } {4 2 2 4 4 8} 219 220 do_test alter2-3.6 { 221 execsql { 222 CREATE TABLE clog(o, n); 223 CREATE TRIGGER abc3_t2 AFTER UPDATE OF c ON abc3 BEGIN 224 INSERT INTO clog VALUES(old.c, new.c); 225 END; 226 UPDATE abc3 SET c = a*2; 227 SELECT * FROM clog; 228 } 229 } {{} 2 {} 6 {} 10} 230} 231 232#--------------------------------------------------------------------- 233# Check that an error occurs if the database is upgraded to a file 234# format that SQLite does not support (in this case 5). Note: The 235# file format is checked each time the schema is read, so changing the 236# file format requires incrementing the schema cookie. 237# 238do_test alter2-4.1 { 239 set_file_format 5 240} {} 241do_test alter2-4.2 { 242 # We have to run two queries here because the Tcl interface uses 243 # sqlite3_prepare_v2(). In this case, the first query encounters an 244 # SQLITE_SCHEMA error. Then, when trying to recompile the statement, the 245 # "unsupported file format" error is encountered. So the error code 246 # returned is SQLITE_SCHEMA, not SQLITE_ERROR as required by the following 247 # test case. 248 # 249 # When the query is attempted a second time, the same error message is 250 # returned but the error code is SQLITE_ERROR, because the unsupported 251 # file format was detected during a call to sqlite3_prepare(), not 252 # sqlite3_step(). 253 # 254 catchsql { SELECT * FROM sqlite_master; } 255 catchsql { SELECT * FROM sqlite_master; } 256} {1 {unsupported file format}} 257do_test alter2-4.3 { 258 sqlite3_errcode $::DB 259} {SQLITE_ERROR} 260do_test alter2-4.4 { 261 set ::DB [sqlite3_connection_pointer db] 262 catchsql { 263 SELECT * FROM sqlite_master; 264 } 265} {1 {unsupported file format}} 266do_test alter2-4.5 { 267 sqlite3_errcode $::DB 268} {SQLITE_ERROR} 269 270#--------------------------------------------------------------------- 271# Check that executing VACUUM on a file with file-format version 2 272# resets the file format to 1. 273# 274set default_file_format [expr $SQLITE_DEFAULT_FILE_FORMAT==4 ? 4 : 1] 275ifcapable vacuum { 276 do_test alter2-5.1 { 277 set_file_format 2 278 execsql {SELECT 1 FROM sqlite_master LIMIT 1;} 279 get_file_format 280 } {2} 281 do_test alter2-5.2 { 282 execsql { 283 VACUUM; 284 } 285 } {} 286 do_test alter2-5.3 { 287 get_file_format 288 } $default_file_format 289} 290 291#--------------------------------------------------------------------- 292# Test that when a database with file-format 2 is opened, new 293# databases are still created with file-format 1. 294# 295do_test alter2-6.1 { 296 db close 297 set_file_format 2 298 sqlite3 db test.db 299 set ::DB [sqlite3_connection_pointer db] 300 get_file_format 301} {2} 302ifcapable attach { 303 do_test alter2-6.2 { 304 file delete -force test2.db-journal 305 file delete -force test2.db 306 execsql { 307 ATTACH 'test2.db' AS aux; 308 CREATE TABLE aux.t1(a, b); 309 } 310 get_file_format test2.db 311 } $default_file_format 312} 313do_test alter2-6.3 { 314 execsql { 315 CREATE TABLE t1(a, b); 316 } 317 get_file_format 318} {2} 319 320#--------------------------------------------------------------------- 321# Test that types and values for columns added with default values 322# other than NULL work with SELECT statements. 323# 324do_test alter2-7.1 { 325 execsql { 326 DROP TABLE t1; 327 CREATE TABLE t1(a); 328 INSERT INTO t1 VALUES(1); 329 INSERT INTO t1 VALUES(2); 330 INSERT INTO t1 VALUES(3); 331 INSERT INTO t1 VALUES(4); 332 SELECT * FROM t1; 333 } 334} {1 2 3 4} 335do_test alter2-7.2 { 336 set sql {CREATE TABLE t1(a, b DEFAULT '123', c INTEGER DEFAULT '123')} 337 alter_table t1 $sql 3 338 execsql { 339 SELECT * FROM t1 LIMIT 1; 340 } 341} {1 123 123} 342do_test alter2-7.3 { 343 execsql { 344 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 345 } 346} {1 integer 123 text 123 integer} 347do_test alter2-7.4 { 348 execsql { 349 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 350 } 351} {1 integer 123 text 123 integer} 352do_test alter2-7.5 { 353 set sql {CREATE TABLE t1(a, b DEFAULT -123.0, c VARCHAR(10) default 5)} 354 alter_table t1 $sql 3 355 execsql { 356 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 357 } 358} {1 integer -123 integer 5 text} 359 360#----------------------------------------------------------------------- 361# Test that UPDATE trigger tables work with default values, and that when 362# a row is updated the default values are correctly transfered to the 363# new row. 364# 365ifcapable trigger { 366db function set_val {set ::val} 367 do_test alter2-8.1 { 368 execsql { 369 CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN 370 SELECT set_val( 371 old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c)||' '|| 372 new.b||' '||typeof(new.b)||' '||new.c||' '||typeof(new.c) 373 ); 374 END; 375 } 376 list 377 } {} 378} 379do_test alter2-8.2 { 380 execsql { 381 UPDATE t1 SET c = 10 WHERE a = 1; 382 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 383 } 384} {1 integer -123 integer 10 text} 385ifcapable trigger { 386 do_test alter2-8.3 { 387 set ::val 388 } {-123 integer 5 text -123 integer 10 text} 389} 390 391#----------------------------------------------------------------------- 392# Test that DELETE trigger tables work with default values, and that when 393# a row is updated the default values are correctly transfered to the 394# new row. 395# 396ifcapable trigger { 397 do_test alter2-9.1 { 398 execsql { 399 CREATE TRIGGER trig2 BEFORE DELETE ON t1 BEGIN 400 SELECT set_val( 401 old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c) 402 ); 403 END; 404 } 405 list 406 } {} 407 do_test alter2-9.2 { 408 execsql { 409 DELETE FROM t1 WHERE a = 2; 410 } 411 set ::val 412 } {-123 integer 5 text} 413} 414 415#----------------------------------------------------------------------- 416# Test creating an index on a column added with a default value. 417# 418ifcapable bloblit { 419 do_test alter2-10.1 { 420 execsql { 421 CREATE TABLE t2(a); 422 INSERT INTO t2 VALUES('a'); 423 INSERT INTO t2 VALUES('b'); 424 INSERT INTO t2 VALUES('c'); 425 INSERT INTO t2 VALUES('d'); 426 } 427 alter_table t2 {CREATE TABLE t2(a, b DEFAULT X'ABCD', c DEFAULT NULL);} 3 428 catchsql { 429 SELECT * FROM sqlite_master; 430 } 431 execsql { 432 SELECT quote(a), quote(b), quote(c) FROM t2 LIMIT 1; 433 } 434 } {'a' X'ABCD' NULL} 435 do_test alter2-10.2 { 436 execsql { 437 CREATE INDEX i1 ON t2(b); 438 SELECT a FROM t2 WHERE b = X'ABCD'; 439 } 440 } {a b c d} 441 do_test alter2-10.3 { 442 execsql { 443 DELETE FROM t2 WHERE a = 'c'; 444 SELECT a FROM t2 WHERE b = X'ABCD'; 445 } 446 } {a b d} 447 do_test alter2-10.4 { 448 execsql { 449 SELECT count(b) FROM t2 WHERE b = X'ABCD'; 450 } 451 } {3} 452} 453 454finish_test 455