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