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.7 2007/04/02 12:29:01 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 dbat eval { 72 PRAGMA writable_schema = 1; 73 UPDATE sqlite_master SET sql = $sql WHERE name = $tbl AND type = 'table'; 74 PRAGMA writable_schema = 0; 75 } 76 dbat close 77 set_file_format 2 78} 79 80#----------------------------------------------------------------------- 81# Some basic tests to make sure short rows are handled. 82# 83do_test alter2-1.1 { 84 execsql { 85 CREATE TABLE abc(a, b); 86 INSERT INTO abc VALUES(1, 2); 87 INSERT INTO abc VALUES(3, 4); 88 INSERT INTO abc VALUES(5, 6); 89 } 90} {} 91do_test alter2-1.2 { 92 # ALTER TABLE abc ADD COLUMN c; 93 alter_table abc {CREATE TABLE abc(a, b, c);} 94} {} 95do_test alter2-1.3 { 96 execsql { 97 SELECT * FROM abc; 98 } 99} {1 2 {} 3 4 {} 5 6 {}} 100do_test alter2-1.4 { 101 execsql { 102 UPDATE abc SET c = 10 WHERE a = 1; 103 SELECT * FROM abc; 104 } 105} {1 2 10 3 4 {} 5 6 {}} 106do_test alter2-1.5 { 107 execsql { 108 CREATE INDEX abc_i ON abc(c); 109 } 110} {} 111do_test alter2-1.6 { 112 execsql { 113 SELECT c FROM abc ORDER BY c; 114 } 115} {{} {} 10} 116do_test alter2-1.7 { 117 execsql { 118 SELECT * FROM abc WHERE c = 10; 119 } 120} {1 2 10} 121do_test alter2-1.8 { 122 execsql { 123 SELECT sum(a), c FROM abc GROUP BY c; 124 } 125} {8 {} 1 10} 126do_test alter2-1.9 { 127 # ALTER TABLE abc ADD COLUMN d; 128 alter_table abc {CREATE TABLE abc(a, b, c, d);} 129 execsql { SELECT * FROM abc; } 130 execsql { 131 UPDATE abc SET d = 11 WHERE c IS NULL AND a<4; 132 SELECT * FROM abc; 133 } 134} {1 2 10 {} 3 4 {} 11 5 6 {} {}} 135do_test alter2-1.10 { 136 execsql { 137 SELECT typeof(d) FROM abc; 138 } 139} {null integer null} 140do_test alter2-1.99 { 141 execsql { 142 DROP TABLE abc; 143 } 144} {} 145 146#----------------------------------------------------------------------- 147# Test that views work when the underlying table structure is changed. 148# 149ifcapable view { 150 do_test alter2-2.1 { 151 execsql { 152 CREATE TABLE abc2(a, b, c); 153 INSERT INTO abc2 VALUES(1, 2, 10); 154 INSERT INTO abc2 VALUES(3, 4, NULL); 155 INSERT INTO abc2 VALUES(5, 6, NULL); 156 CREATE VIEW abc2_v AS SELECT * FROM abc2; 157 SELECT * FROM abc2_v; 158 } 159 } {1 2 10 3 4 {} 5 6 {}} 160 do_test alter2-2.2 { 161 # ALTER TABLE abc ADD COLUMN d; 162 alter_table abc2 {CREATE TABLE abc2(a, b, c, d);} 163 execsql { 164 SELECT * FROM abc2_v; 165 } 166 } {1 2 10 {} 3 4 {} {} 5 6 {} {}} 167 do_test alter2-2.3 { 168 execsql { 169 DROP TABLE abc2; 170 DROP VIEW abc2_v; 171 } 172 } {} 173} 174 175#----------------------------------------------------------------------- 176# Test that triggers work when a short row is copied to the old.* 177# trigger pseudo-table. 178# 179ifcapable trigger { 180 do_test alter2-3.1 { 181 execsql { 182 CREATE TABLE abc3(a, b); 183 CREATE TABLE blog(o, n); 184 CREATE TRIGGER abc3_t AFTER UPDATE OF b ON abc3 BEGIN 185 INSERT INTO blog VALUES(old.b, new.b); 186 END; 187 } 188 } {} 189 do_test alter2-3.2 { 190 execsql { 191 INSERT INTO abc3 VALUES(1, 4); 192 UPDATE abc3 SET b = 2 WHERE b = 4; 193 SELECT * FROM blog; 194 } 195 } {4 2} 196 do_test alter2-3.3 { 197 execsql { 198 INSERT INTO abc3 VALUES(3, 4); 199 INSERT INTO abc3 VALUES(5, 6); 200 } 201 alter_table abc3 {CREATE TABLE abc3(a, b, c);} 202 execsql { 203 SELECT * FROM abc3; 204 } 205 } {1 2 {} 3 4 {} 5 6 {}} 206 do_test alter2-3.4 { 207 execsql { 208 UPDATE abc3 SET b = b*2 WHERE a<4; 209 SELECT * FROM abc3; 210 } 211 } {1 4 {} 3 8 {} 5 6 {}} 212 do_test alter2-3.5 { 213 execsql { 214 SELECT * FROM blog; 215 } 216 } {4 2 2 4 4 8} 217 218 do_test alter2-3.6 { 219 execsql { 220 CREATE TABLE clog(o, n); 221 CREATE TRIGGER abc3_t2 AFTER UPDATE OF c ON abc3 BEGIN 222 INSERT INTO clog VALUES(old.c, new.c); 223 END; 224 UPDATE abc3 SET c = a*2; 225 SELECT * FROM clog; 226 } 227 } {{} 2 {} 6 {} 10} 228} 229 230#--------------------------------------------------------------------- 231# Check that an error occurs if the database is upgraded to a file 232# format that SQLite does not support (in this case 5). Note: The 233# file format is checked each time the schema is read, so changing the 234# file format requires incrementing the schema cookie. 235# 236do_test alter2-4.1 { 237 set_file_format 5 238} {} 239do_test alter2-4.2 { 240 catchsql { 241 SELECT * FROM sqlite_master; 242 } 243} {1 {unsupported file format}} 244do_test alter2-4.3 { 245 sqlite3_errcode $::DB 246} {SQLITE_ERROR} 247do_test alter2-4.4 { 248 set ::DB [sqlite3_connection_pointer db] 249 catchsql { 250 SELECT * FROM sqlite_master; 251 } 252} {1 {unsupported file format}} 253do_test alter2-4.5 { 254 sqlite3_errcode $::DB 255} {SQLITE_ERROR} 256 257#--------------------------------------------------------------------- 258# Check that executing VACUUM on a file with file-format version 2 259# resets the file format to 1. 260# 261set default_file_format [expr $sqlite_default_file_format==4 ? 4 : 1] 262do_test alter2-5.1 { 263 set_file_format 2 264 get_file_format 265} {2} 266do_test alter2-5.2 { 267 execsql { 268 VACUUM; 269 } 270} {} 271do_test alter2-5.3 { 272 get_file_format 273} $default_file_format 274 275#--------------------------------------------------------------------- 276# Test that when a database with file-format 2 is opened, new 277# databases are still created with file-format 1. 278# 279do_test alter2-6.1 { 280 db close 281 set_file_format 2 282 sqlite3 db test.db 283 set ::DB [sqlite3_connection_pointer db] 284 get_file_format 285} {2} 286do_test alter2-6.2 { 287 file delete -force test2.db-journal 288 file delete -force test2.db 289 execsql { 290 ATTACH 'test2.db' AS aux; 291 CREATE TABLE aux.t1(a, b); 292 } 293 get_file_format test2.db 294} $default_file_format 295do_test alter2-6.3 { 296 execsql { 297 CREATE TABLE t1(a, b); 298 } 299 get_file_format 300} {2} 301 302#--------------------------------------------------------------------- 303# Test that types and values for columns added with default values 304# other than NULL work with SELECT statements. 305# 306do_test alter2-7.1 { 307 execsql { 308 DROP TABLE t1; 309 CREATE TABLE t1(a); 310 INSERT INTO t1 VALUES(1); 311 INSERT INTO t1 VALUES(2); 312 INSERT INTO t1 VALUES(3); 313 INSERT INTO t1 VALUES(4); 314 SELECT * FROM t1; 315 } 316} {1 2 3 4} 317do_test alter2-7.2 { 318 set sql {CREATE TABLE t1(a, b DEFAULT '123', c INTEGER DEFAULT '123')} 319 alter_table t1 $sql 3 320 execsql { 321 SELECT * FROM t1 LIMIT 1; 322 } 323} {1 123 123} 324do_test alter2-7.3 { 325 execsql { 326 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 327 } 328} {1 integer 123 text 123 integer} 329do_test alter2-7.4 { 330 execsql { 331 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 332 } 333} {1 integer 123 text 123 integer} 334do_test alter2-7.5 { 335 set sql {CREATE TABLE t1(a, b DEFAULT -123.0, c VARCHAR(10) default 5)} 336 alter_table t1 $sql 3 337 execsql { 338 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 339 } 340} {1 integer -123 integer 5 text} 341 342#----------------------------------------------------------------------- 343# Test that UPDATE trigger tables work with default values, and that when 344# a row is updated the default values are correctly transfered to the 345# new row. 346# 347ifcapable trigger { 348db function set_val {set ::val} 349 do_test alter2-8.1 { 350 execsql { 351 CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN 352 SELECT set_val( 353 old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c)||' '|| 354 new.b||' '||typeof(new.b)||' '||new.c||' '||typeof(new.c) 355 ); 356 END; 357 } 358 list 359 } {} 360} 361do_test alter2-8.2 { 362 execsql { 363 UPDATE t1 SET c = 10 WHERE a = 1; 364 SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1; 365 } 366} {1 integer -123 integer 10 text} 367ifcapable trigger { 368 do_test alter2-8.3 { 369 set ::val 370 } {-123 integer 5 text -123 integer 10 text} 371} 372 373#----------------------------------------------------------------------- 374# Test that DELETE trigger tables work with default values, and that when 375# a row is updated the default values are correctly transfered to the 376# new row. 377# 378ifcapable trigger { 379 do_test alter2-9.1 { 380 execsql { 381 CREATE TRIGGER trig2 BEFORE DELETE ON t1 BEGIN 382 SELECT set_val( 383 old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c) 384 ); 385 END; 386 } 387 list 388 } {} 389 do_test alter2-9.2 { 390 execsql { 391 DELETE FROM t1 WHERE a = 2; 392 } 393 set ::val 394 } {-123 integer 5 text} 395} 396 397#----------------------------------------------------------------------- 398# Test creating an index on a column added with a default value. 399# 400do_test alter2-10.1 { 401 execsql { 402 CREATE TABLE t2(a); 403 INSERT INTO t2 VALUES('a'); 404 INSERT INTO t2 VALUES('b'); 405 INSERT INTO t2 VALUES('c'); 406 INSERT INTO t2 VALUES('d'); 407 } 408 alter_table t2 {CREATE TABLE t2(a, b DEFAULT X'ABCD', c DEFAULT NULL);} 3 409 catchsql { 410 SELECT * FROM sqlite_master; 411 } 412 execsql { 413 SELECT quote(a), quote(b), quote(c) FROM t2 LIMIT 1; 414 } 415} {'a' X'ABCD' NULL} 416do_test alter2-10.2 { 417 execsql { 418 CREATE INDEX i1 ON t2(b); 419 SELECT a FROM t2 WHERE b = X'ABCD'; 420 } 421} {a b c d} 422do_test alter2-10.3 { 423 execsql { 424 DELETE FROM t2 WHERE a = 'c'; 425 SELECT a FROM t2 WHERE b = X'ABCD'; 426 } 427} {a b d} 428do_test alter2-10.4 { 429 execsql { 430 SELECT count(b) FROM t2 WHERE b = X'ABCD'; 431 } 432} {3} 433 434finish_test 435