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.11 2007/11/13 10:30:26 danielk1977 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 get_file_format 279 } {2} 280 do_test alter2-5.2 { 281 execsql { 282 VACUUM; 283 } 284 } {} 285 do_test alter2-5.3 { 286 get_file_format 287 } $default_file_format 288} 289 290#--------------------------------------------------------------------- 291# Test that when a database with file-format 2 is opened, new 292# databases are still created with file-format 1. 293# 294do_test alter2-6.1 { 295 db close 296 set_file_format 2 297 sqlite3 db test.db 298 set ::DB [sqlite3_connection_pointer db] 299 get_file_format 300} {2} 301ifcapable attach { 302 do_test alter2-6.2 { 303 file delete -force test2.db-journal 304 file delete -force test2.db 305 execsql { 306 ATTACH 'test2.db' AS aux; 307 CREATE TABLE aux.t1(a, b); 308 } 309 get_file_format test2.db 310 } $default_file_format 311} 312do_test alter2-6.3 { 313 execsql { 314 CREATE TABLE t1(a, b); 315 } 316 get_file_format 317} {2} 318 319#--------------------------------------------------------------------- 320# Test that types and values for columns added with default values 321# other than NULL work with SELECT statements. 322# 323do_test alter2-7.1 { 324 execsql { 325 DROP TABLE t1; 326 CREATE TABLE t1(a); 327 INSERT INTO t1 VALUES(1); 328 INSERT INTO t1 VALUES(2); 329 INSERT INTO t1 VALUES(3); 330 INSERT INTO t1 VALUES(4); 331 SELECT * FROM t1; 332 } 333} {1 2 3 4} 334do_test alter2-7.2 { 335 set sql {CREATE TABLE t1(a, b DEFAULT '123', c INTEGER DEFAULT '123')} 336 alter_table t1 $sql 3 337 execsql { 338 SELECT * FROM t1 LIMIT 1; 339 } 340} {1 123 123} 341do_test alter2-7.3 { 342 execsql { 343 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 344 } 345} {1 integer 123 text 123 integer} 346do_test alter2-7.4 { 347 execsql { 348 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 349 } 350} {1 integer 123 text 123 integer} 351do_test alter2-7.5 { 352 set sql {CREATE TABLE t1(a, b DEFAULT -123.0, c VARCHAR(10) default 5)} 353 alter_table t1 $sql 3 354 execsql { 355 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 356 } 357} {1 integer -123 integer 5 text} 358 359#----------------------------------------------------------------------- 360# Test that UPDATE trigger tables work with default values, and that when 361# a row is updated the default values are correctly transfered to the 362# new row. 363# 364ifcapable trigger { 365db function set_val {set ::val} 366 do_test alter2-8.1 { 367 execsql { 368 CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN 369 SELECT set_val( 370 old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c)||' '|| 371 new.b||' '||typeof(new.b)||' '||new.c||' '||typeof(new.c) 372 ); 373 END; 374 } 375 list 376 } {} 377} 378do_test alter2-8.2 { 379 execsql { 380 UPDATE t1 SET c = 10 WHERE a = 1; 381 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 382 } 383} {1 integer -123 integer 10 text} 384ifcapable trigger { 385 do_test alter2-8.3 { 386 set ::val 387 } {-123 integer 5 text -123 integer 10 text} 388} 389 390#----------------------------------------------------------------------- 391# Test that DELETE trigger tables work with default values, and that when 392# a row is updated the default values are correctly transfered to the 393# new row. 394# 395ifcapable trigger { 396 do_test alter2-9.1 { 397 execsql { 398 CREATE TRIGGER trig2 BEFORE DELETE ON t1 BEGIN 399 SELECT set_val( 400 old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c) 401 ); 402 END; 403 } 404 list 405 } {} 406 do_test alter2-9.2 { 407 execsql { 408 DELETE FROM t1 WHERE a = 2; 409 } 410 set ::val 411 } {-123 integer 5 text} 412} 413 414#----------------------------------------------------------------------- 415# Test creating an index on a column added with a default value. 416# 417ifcapable bloblit { 418 do_test alter2-10.1 { 419 execsql { 420 CREATE TABLE t2(a); 421 INSERT INTO t2 VALUES('a'); 422 INSERT INTO t2 VALUES('b'); 423 INSERT INTO t2 VALUES('c'); 424 INSERT INTO t2 VALUES('d'); 425 } 426 alter_table t2 {CREATE TABLE t2(a, b DEFAULT X'ABCD', c DEFAULT NULL);} 3 427 catchsql { 428 SELECT * FROM sqlite_master; 429 } 430 execsql { 431 SELECT quote(a), quote(b), quote(c) FROM t2 LIMIT 1; 432 } 433 } {'a' X'ABCD' NULL} 434 do_test alter2-10.2 { 435 execsql { 436 CREATE INDEX i1 ON t2(b); 437 SELECT a FROM t2 WHERE b = X'ABCD'; 438 } 439 } {a b c d} 440 do_test alter2-10.3 { 441 execsql { 442 DELETE FROM t2 WHERE a = 'c'; 443 SELECT a FROM t2 WHERE b = X'ABCD'; 444 } 445 } {a b d} 446 do_test alter2-10.4 { 447 execsql { 448 SELECT count(b) FROM t2 WHERE b = X'ABCD'; 449 } 450 } {3} 451} 452 453finish_test 454