1# 2# 2001 September 15 3# 4# The author disclaims copyright to this source code. In place of 5# a legal notice, here is a blessing: 6# 7# May you do good and not evil. 8# May you find forgiveness for yourself and forgive others. 9# May you share freely, never taking more than you give. 10# 11#*********************************************************************** 12# This file implements regression tests for SQLite library. 13# 14# This file implements tests for the special processing associated 15# with INTEGER PRIMARY KEY columns. 16# 17# $Id: intpkey.test,v 1.14 2003/06/15 23:42:25 drh Exp $ 18 19set testdir [file dirname $argv0] 20source $testdir/tester.tcl 21 22# Create a table with a primary key and a datatype other than 23# integer 24# 25do_test intpkey-1.0 { 26 execsql { 27 CREATE TABLE t1(a TEXT PRIMARY KEY, b, c); 28 } 29} {} 30 31# There should be an index associated with the primary key 32# 33do_test intpkey-1.1 { 34 execsql { 35 SELECT name FROM sqlite_master 36 WHERE type='index' AND tbl_name='t1'; 37 } 38} {{(t1 autoindex 1)}} 39 40# Now create a table with an integer primary key and verify that 41# there is no associated index. 42# 43do_test intpkey-1.2 { 44 execsql { 45 DROP TABLE t1; 46 CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); 47 SELECT name FROM sqlite_master 48 WHERE type='index' AND tbl_name='t1'; 49 } 50} {} 51 52# Insert some records into the new table. Specify the primary key 53# and verify that the key is used as the record number. 54# 55do_test intpkey-1.3 { 56 execsql { 57 INSERT INTO t1 VALUES(5,'hello','world'); 58 } 59 db last_insert_rowid 60} {5} 61do_test intpkey-1.4 { 62 execsql { 63 SELECT * FROM t1; 64 } 65} {5 hello world} 66do_test intpkey-1.5 { 67 execsql { 68 SELECT rowid, * FROM t1; 69 } 70} {5 5 hello world} 71 72# Attempting to insert a duplicate primary key should give a constraint 73# failure. 74# 75do_test intpkey-1.6 { 76 set r [catch {execsql { 77 INSERT INTO t1 VALUES(5,'second','entry'); 78 }} msg] 79 lappend r $msg 80} {1 {PRIMARY KEY must be unique}} 81do_test intpkey-1.7 { 82 execsql { 83 SELECT rowid, * FROM t1; 84 } 85} {5 5 hello world} 86do_test intpkey-1.8 { 87 set r [catch {execsql { 88 INSERT INTO t1 VALUES(6,'second','entry'); 89 }} msg] 90 lappend r $msg 91} {0 {}} 92do_test intpkey-1.8.1 { 93 db last_insert_rowid 94} {6} 95do_test intpkey-1.9 { 96 execsql { 97 SELECT rowid, * FROM t1; 98 } 99} {5 5 hello world 6 6 second entry} 100 101# A ROWID is automatically generated for new records that do not specify 102# the integer primary key. 103# 104do_test intpkey-1.10 { 105 execsql { 106 INSERT INTO t1(b,c) VALUES('one','two'); 107 SELECT b FROM t1 ORDER BY b; 108 } 109} {hello one second} 110 111# Try to change the ROWID for the new entry. 112# 113do_test intpkey-1.11 { 114 execsql { 115 UPDATE t1 SET a=4 WHERE b='one'; 116 SELECT * FROM t1; 117 } 118} {4 one two 5 hello world 6 second entry} 119 120# Make sure SELECT statements are able to use the primary key column 121# as an index. 122# 123do_test intpkey-1.12 { 124 execsql { 125 SELECT * FROM t1 WHERE a==4; 126 } 127} {4 one two} 128 129# Try to insert a non-integer value into the primary key field. This 130# should result in a data type mismatch. 131# 132do_test intpkey-1.13.1 { 133 set r [catch {execsql { 134 INSERT INTO t1 VALUES('x','y','z'); 135 }} msg] 136 lappend r $msg 137} {1 {datatype mismatch}} 138do_test intpkey-1.13.2 { 139 set r [catch {execsql { 140 INSERT INTO t1 VALUES('','y','z'); 141 }} msg] 142 lappend r $msg 143} {1 {datatype mismatch}} 144do_test intpkey-1.14 { 145 set r [catch {execsql { 146 INSERT INTO t1 VALUES(3.4,'y','z'); 147 }} msg] 148 lappend r $msg 149} {1 {datatype mismatch}} 150do_test intpkey-1.15 { 151 set r [catch {execsql { 152 INSERT INTO t1 VALUES(-3,'y','z'); 153 }} msg] 154 lappend r $msg 155} {0 {}} 156do_test intpkey-1.16 { 157 execsql {SELECT * FROM t1} 158} {-3 y z 4 one two 5 hello world 6 second entry} 159 160#### INDICES 161# Check to make sure indices work correctly with integer primary keys 162# 163do_test intpkey-2.1 { 164 execsql { 165 CREATE INDEX i1 ON t1(b); 166 SELECT * FROM t1 WHERE b=='y' 167 } 168} {-3 y z} 169do_test intpkey-2.1.1 { 170 execsql { 171 SELECT * FROM t1 WHERE b=='y' AND rowid<0 172 } 173} {-3 y z} 174do_test intpkey-2.1.2 { 175 execsql { 176 SELECT * FROM t1 WHERE b=='y' AND rowid<0 AND rowid>=-20 177 } 178} {-3 y z} 179do_test intpkey-2.1.3 { 180 execsql { 181 SELECT * FROM t1 WHERE b>='y' 182 } 183} {-3 y z} 184do_test intpkey-2.1.4 { 185 execsql { 186 SELECT * FROM t1 WHERE b>='y' AND rowid<10 187 } 188} {-3 y z} 189 190do_test intpkey-2.2 { 191 execsql { 192 UPDATE t1 SET a=8 WHERE b=='y'; 193 SELECT * FROM t1 WHERE b=='y'; 194 } 195} {8 y z} 196do_test intpkey-2.3 { 197 execsql { 198 SELECT rowid, * FROM t1; 199 } 200} {4 4 one two 5 5 hello world 6 6 second entry 8 8 y z} 201do_test intpkey-2.4 { 202 execsql { 203 SELECT rowid, * FROM t1 WHERE b<'second' 204 } 205} {5 5 hello world 4 4 one two} 206do_test intpkey-2.4.1 { 207 execsql { 208 SELECT rowid, * FROM t1 WHERE 'second'>b 209 } 210} {5 5 hello world 4 4 one two} 211do_test intpkey-2.4.2 { 212 execsql { 213 SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b 214 } 215} {4 4 one two 5 5 hello world} 216do_test intpkey-2.4.3 { 217 execsql { 218 SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b AND 0<rowid 219 } 220} {4 4 one two 5 5 hello world} 221do_test intpkey-2.5 { 222 execsql { 223 SELECT rowid, * FROM t1 WHERE b>'a' 224 } 225} {5 5 hello world 4 4 one two 6 6 second entry 8 8 y z} 226do_test intpkey-2.6 { 227 execsql { 228 DELETE FROM t1 WHERE rowid=4; 229 SELECT * FROM t1 WHERE b>'a'; 230 } 231} {5 hello world 6 second entry 8 y z} 232do_test intpkey-2.7 { 233 execsql { 234 UPDATE t1 SET a=-4 WHERE rowid=8; 235 SELECT * FROM t1 WHERE b>'a'; 236 } 237} {5 hello world 6 second entry -4 y z} 238do_test intpkey-2.7 { 239 execsql { 240 SELECT * FROM t1 241 } 242} {-4 y z 5 hello world 6 second entry} 243 244# Do an SQL statement. Append the search count to the end of the result. 245# 246proc count sql { 247 set ::sqlite_search_count 0 248 return [concat [execsql $sql] $::sqlite_search_count] 249} 250 251# Create indices that include the integer primary key as one of their 252# columns. 253# 254do_test intpkey-3.1 { 255 execsql { 256 CREATE INDEX i2 ON t1(a); 257 } 258} {} 259do_test intpkey-3.2 { 260 count { 261 SELECT * FROM t1 WHERE a=5; 262 } 263} {5 hello world 0} 264do_test intpkey-3.3 { 265 count { 266 SELECT * FROM t1 WHERE a>4 AND a<6; 267 } 268} {5 hello world 2} 269do_test intpkey-3.4 { 270 count { 271 SELECT * FROM t1 WHERE b>='hello' AND b<'hello2'; 272 } 273} {5 hello world 3} 274do_test intpkey-3.5 { 275 execsql { 276 CREATE INDEX i3 ON t1(c,a); 277 } 278} {} 279do_test intpkey-3.6 { 280 count { 281 SELECT * FROM t1 WHERE c=='world'; 282 } 283} {5 hello world 3} 284do_test intpkey-3.7 { 285 execsql {INSERT INTO t1 VALUES(11,'hello','world')} 286 count { 287 SELECT * FROM t1 WHERE c=='world'; 288 } 289} {5 hello world 11 hello world 5} 290do_test intpkey-3.8 { 291 count { 292 SELECT * FROM t1 WHERE c=='world' AND a>7; 293 } 294} {11 hello world 5} 295do_test intpkey-3.9 { 296 count { 297 SELECT * FROM t1 WHERE 7<a; 298 } 299} {11 hello world 1} 300 301# Test inequality constraints on integer primary keys and rowids 302# 303do_test intpkey-4.1 { 304 count { 305 SELECT * FROM t1 WHERE 11=rowid 306 } 307} {11 hello world 0} 308do_test intpkey-4.2 { 309 count { 310 SELECT * FROM t1 WHERE 11=rowid AND b=='hello' 311 } 312} {11 hello world 0} 313do_test intpkey-4.3 { 314 count { 315 SELECT * FROM t1 WHERE 11=rowid AND b=='hello' AND c IS NOT NULL; 316 } 317} {11 hello world 0} 318do_test intpkey-4.4 { 319 count { 320 SELECT * FROM t1 WHERE rowid==11 321 } 322} {11 hello world 0} 323do_test intpkey-4.5 { 324 count { 325 SELECT * FROM t1 WHERE oid==11 AND b=='hello' 326 } 327} {11 hello world 0} 328do_test intpkey-4.6 { 329 count { 330 SELECT * FROM t1 WHERE a==11 AND b=='hello' AND c IS NOT NULL; 331 } 332} {11 hello world 0} 333 334do_test intpkey-4.7 { 335 count { 336 SELECT * FROM t1 WHERE 8<rowid; 337 } 338} {11 hello world 1} 339do_test intpkey-4.8 { 340 count { 341 SELECT * FROM t1 WHERE 8<rowid AND 11>=oid; 342 } 343} {11 hello world 1} 344do_test intpkey-4.9 { 345 count { 346 SELECT * FROM t1 WHERE 11<=_rowid_ AND 12>=a; 347 } 348} {11 hello world 1} 349do_test intpkey-4.10 { 350 count { 351 SELECT * FROM t1 WHERE 0>=_rowid_; 352 } 353} {-4 y z 1} 354do_test intpkey-4.11 { 355 count { 356 SELECT * FROM t1 WHERE a<0; 357 } 358} {-4 y z 1} 359do_test intpkey-4.12 { 360 count { 361 SELECT * FROM t1 WHERE a<0 AND a>10; 362 } 363} {1} 364 365# Make sure it is OK to insert a rowid of 0 366# 367do_test intpkey-5.1 { 368 execsql { 369 INSERT INTO t1 VALUES(0,'zero','entry'); 370 } 371 count { 372 SELECT * FROM t1 WHERE a=0; 373 } 374} {0 zero entry 0} 375do_test intpkey=5.2 { 376 execsql { 377 SELECT rowid, a FROM t1 378 } 379} {-4 -4 0 0 5 5 6 6 11 11} 380 381# Test the ability of the COPY command to put data into a 382# table that contains an integer primary key. 383# 384do_test intpkey-6.1 { 385 set f [open ./data1.txt w] 386 puts $f "20\tb-20\tc-20" 387 puts $f "21\tb-21\tc-21" 388 puts $f "22\tb-22\tc-22" 389 close $f 390 execsql { 391 COPY t1 FROM 'data1.txt'; 392 SELECT * FROM t1 WHERE a>=20; 393 } 394} {20 b-20 c-20 21 b-21 c-21 22 b-22 c-22} 395do_test intpkey-6.2 { 396 execsql { 397 SELECT * FROM t1 WHERE b=='hello' 398 } 399} {5 hello world 11 hello world} 400do_test intpkey-6.3 { 401 execsql { 402 DELETE FROM t1 WHERE b='b-21'; 403 SELECT * FROM t1 WHERE b=='b-21'; 404 } 405} {} 406do_test intpkey-6.4 { 407 execsql { 408 SELECT * FROM t1 WHERE a>=20 409 } 410} {20 b-20 c-20 22 b-22 c-22} 411 412# Do an insert of values with the columns specified out of order. 413# 414do_test intpkey-7.1 { 415 execsql { 416 INSERT INTO t1(c,b,a) VALUES('row','new',30); 417 SELECT * FROM t1 WHERE rowid>=30; 418 } 419} {30 new row} 420do_test intpkey-7.2 { 421 execsql { 422 SELECT * FROM t1 WHERE rowid>20; 423 } 424} {22 b-22 c-22 30 new row} 425 426# Do an insert from a select statement. 427# 428do_test intpkey-8.1 { 429 execsql { 430 CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z); 431 INSERT INTO t2 SELECT * FROM t1; 432 SELECT rowid FROM t2; 433 } 434} {-4 0 5 6 11 20 22 30} 435do_test intpkey-8.2 { 436 execsql { 437 SELECT x FROM t2; 438 } 439} {-4 0 5 6 11 20 22 30} 440 441do_test intpkey-9.1 { 442 execsql { 443 UPDATE t1 SET c='www' WHERE c='world'; 444 SELECT rowid, a, c FROM t1 WHERE c=='www'; 445 } 446} {5 5 www 11 11 www} 447 448 449# Check insert of NULL for primary key 450# 451do_test intpkey-10.1 { 452 execsql { 453 DROP TABLE t2; 454 CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z); 455 INSERT INTO t2 VALUES(NULL, 1, 2); 456 SELECT * from t2; 457 } 458} {1 1 2} 459do_test intpkey-10.2 { 460 execsql { 461 INSERT INTO t2 VALUES(NULL, 2, 3); 462 SELECT * from t2 WHERE x=2; 463 } 464} {2 2 3} 465do_test intpkey-10.3 { 466 execsql { 467 INSERT INTO t2 SELECT NULL, z, y FROM t2; 468 SELECT * FROM t2; 469 } 470} {1 1 2 2 2 3 3 2 1 4 3 2} 471 472# This tests checks to see if a floating point number can be used 473# to reference an integer primary key. 474# 475do_test intpkey-11.1 { 476 execsql { 477 SELECT b FROM t1 WHERE a=2.0+3.0; 478 } 479} {hello} 480do_test intpkey-11.1 { 481 execsql { 482 SELECT b FROM t1 WHERE a=2.0+3.5; 483 } 484} {} 485 486integrity_check intpkey-12.1 487 488finish_test 489