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