1# 2005 November 2 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 file is testing CHECK constraints 13# 14# $Id: check.test,v 1.13 2009/06/05 17:09:12 drh Exp $ 15 16set testdir [file dirname $argv0] 17source $testdir/tester.tcl 18set ::testprefix check 19 20# Only run these tests if the build includes support for CHECK constraints 21ifcapable !check { 22 finish_test 23 return 24} 25 26do_test check-1.1 { 27 execsql { 28 CREATE TABLE t1( 29 x INTEGER CHECK( x<5 ), 30 y REAL CHECK( y>x ) 31 ); 32 } 33} {} 34do_test check-1.2 { 35 execsql { 36 INSERT INTO t1 VALUES(3,4); 37 SELECT * FROM t1; 38 } 39} {3 4.0} 40do_test check-1.3 { 41 catchsql { 42 INSERT INTO t1 VALUES(6,7); 43 } 44} {1 {CHECK constraint failed: t1}} 45do_test check-1.4 { 46 execsql { 47 SELECT * FROM t1; 48 } 49} {3 4.0} 50do_test check-1.5 { 51 catchsql { 52 INSERT INTO t1 VALUES(4,3); 53 } 54} {1 {CHECK constraint failed: t1}} 55do_test check-1.6 { 56 execsql { 57 SELECT * FROM t1; 58 } 59} {3 4.0} 60do_test check-1.7 { 61 catchsql { 62 INSERT INTO t1 VALUES(NULL,6); 63 } 64} {0 {}} 65do_test check-1.8 { 66 execsql { 67 SELECT * FROM t1; 68 } 69} {3 4.0 {} 6.0} 70do_test check-1.9 { 71 catchsql { 72 INSERT INTO t1 VALUES(2,NULL); 73 } 74} {0 {}} 75do_test check-1.10 { 76 execsql { 77 SELECT * FROM t1; 78 } 79} {3 4.0 {} 6.0 2 {}} 80do_test check-1.11 { 81 execsql { 82 DELETE FROM t1 WHERE x IS NULL OR x!=3; 83 UPDATE t1 SET x=2 WHERE x==3; 84 SELECT * FROM t1; 85 } 86} {2 4.0} 87do_test check-1.12 { 88 catchsql { 89 UPDATE t1 SET x=7 WHERE x==2 90 } 91} {1 {CHECK constraint failed: t1}} 92do_test check-1.13 { 93 execsql { 94 SELECT * FROM t1; 95 } 96} {2 4.0} 97do_test check-1.14 { 98 catchsql { 99 UPDATE t1 SET x=5 WHERE x==2 100 } 101} {1 {CHECK constraint failed: t1}} 102do_test check-1.15 { 103 execsql { 104 SELECT * FROM t1; 105 } 106} {2 4.0} 107do_test check-1.16 { 108 catchsql { 109 UPDATE t1 SET x=4, y=11 WHERE x==2 110 } 111} {0 {}} 112do_test check-1.17 { 113 execsql { 114 SELECT * FROM t1; 115 } 116} {4 11.0} 117 118do_test check-2.1 { 119 execsql { 120 PRAGMA writable_schema = 1; 121 CREATE TABLE t2( 122 x INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))=="integer" ), 123 y REAL CONSTRAINT two CHECK( typeof(coalesce(y,0.1))=='real' ), 124 z TEXT CONSTRAINT three CHECK( typeof(coalesce(z,''))=='text' ) 125 ); 126 CREATE TABLE t2n( 127 x INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))=="integer" ), 128 y NUMERIC CONSTRAINT two CHECK( typeof(coalesce(y,0.1))=='real' ), 129 z TEXT CONSTRAINT three CHECK( typeof(coalesce(z,''))=='text' ) 130 ); 131 PRAGMA writable_schema = 0; 132 } 133} {} 134do_test check-2.2 { 135 execsql { 136 INSERT INTO t2 VALUES(1,2.2,'three'); 137 SELECT * FROM t2; 138 } 139} {1 2.2 three} 140db close 141sqlite3 db test.db 142do_test check-2.3 { 143 execsql { 144 INSERT INTO t2 VALUES(NULL, NULL, NULL); 145 SELECT * FROM t2; 146 } 147} {1 2.2 three {} {} {}} 148do_test check-2.4 { 149 catchsql { 150 INSERT INTO t2 VALUES(1.1, NULL, NULL); 151 } 152} {1 {CHECK constraint failed: one}} 153do_test check-2.5 { 154 # The 5 gets automatically promoted to 5.0 because the column type is REAL 155 catchsql { 156 INSERT INTO t2 VALUES(NULL, 5, NULL); 157 } 158} {0 {}} 159do_test check-2.5b { 160 # This time the column type is NUMERIC, so not automatic promption to REAL 161 # occurs and the constraint fails. 162 catchsql { 163 INSERT INTO t2n VALUES(NULL, 5, NULL); 164 } 165} {1 {CHECK constraint failed: two}} 166do_test check-2.6 { 167 catchsql { 168 INSERT INTO t2 VALUES(NULL, NULL, 3.14159); 169 } 170} {1 {CHECK constraint failed: three}} 171 172# Undocumented behavior: The CONSTRAINT name clause can follow a constraint. 173# Such a clause is ignored. But the parser must accept it for backwards 174# compatibility. 175# 176do_test check-2.10 { 177 execsql { 178 CREATE TABLE t2b( 179 x INTEGER CHECK( typeof(coalesce(x,0))=='integer' ) CONSTRAINT one, 180 y TEXT PRIMARY KEY constraint two, 181 z INTEGER, 182 UNIQUE(x,z) constraint three 183 ); 184 } 185} {} 186do_test check-2.11 { 187 catchsql { 188 INSERT INTO t2b VALUES('xyzzy','hi',5); 189 } 190} {1 {CHECK constraint failed: t2b}} 191do_test check-2.12 { 192 execsql { 193 CREATE TABLE t2c( 194 x INTEGER CONSTRAINT x_one CONSTRAINT x_two 195 CHECK( typeof(coalesce(x,0))=='integer' ) 196 CONSTRAINT x_two CONSTRAINT x_three, 197 y INTEGER, z INTEGER, 198 CONSTRAINT u_one UNIQUE(x,y,z) CONSTRAINT u_two 199 ); 200 } 201} {} 202do_test check-2.13 { 203 catchsql { 204 INSERT INTO t2c VALUES('xyzzy',7,8); 205 } 206} {1 {CHECK constraint failed: x_two}} 207do_test check-2.cleanup { 208 execsql { 209 DROP TABLE IF EXISTS t2b; 210 DROP TABLE IF EXISTS t2c; 211 DROP TABLE IF EXISTS t2n; 212 } 213} {} 214 215ifcapable subquery { 216 do_test check-3.1 { 217 catchsql { 218 CREATE TABLE t3( 219 x, y, z, 220 CHECK( x<(SELECT min(x) FROM t1) ) 221 ); 222 } 223 } {1 {subqueries prohibited in CHECK constraints}} 224} 225 226do_test check-3.2 { 227 execsql { 228 SELECT name FROM sqlite_master ORDER BY name 229 } 230} {t1 t2} 231do_test check-3.3 { 232 catchsql { 233 CREATE TABLE t3( 234 x, y, z, 235 CHECK( q<x ) 236 ); 237 } 238} {1 {no such column: q}} 239do_test check-3.4 { 240 execsql { 241 SELECT name FROM sqlite_master ORDER BY name 242 } 243} {t1 t2} 244do_test check-3.5 { 245 catchsql { 246 CREATE TABLE t3( 247 x, y, z, 248 CHECK( t2.x<x ) 249 ); 250 } 251} {1 {no such column: t2.x}} 252do_test check-3.6 { 253 execsql { 254 SELECT name FROM sqlite_master ORDER BY name 255 } 256} {t1 t2} 257do_test check-3.7 { 258 catchsql { 259 CREATE TABLE t3( 260 x, y, z, 261 CHECK( t3.x<25 ) 262 ); 263 } 264} {0 {}} 265do_test check-3.8 { 266 execsql { 267 INSERT INTO t3 VALUES(1,2,3); 268 SELECT * FROM t3; 269 } 270} {1 2 3} 271do_test check-3.9 { 272 catchsql { 273 INSERT INTO t3 VALUES(111,222,333); 274 } 275} {1 {CHECK constraint failed: t3}} 276 277do_test check-4.1 { 278 execsql { 279 CREATE TABLE t4(x, y, 280 CHECK ( 281 x+y==11 282 OR x*y==12 283 OR x/y BETWEEN 5 AND 8 284 OR -x==y+10 285 ) 286 ); 287 } 288} {} 289do_test check-4.2 { 290 execsql { 291 INSERT INTO t4 VALUES(1,10); 292 SELECT * FROM t4 293 } 294} {1 10} 295do_test check-4.3 { 296 execsql { 297 UPDATE t4 SET x=4, y=3; 298 SELECT * FROM t4 299 } 300} {4 3} 301do_test check-4.4 { 302 execsql { 303 UPDATE t4 SET x=12, y=2; 304 SELECT * FROM t4 305 } 306} {12 2} 307do_test check-4.5 { 308 execsql { 309 UPDATE t4 SET x=12, y=-22; 310 SELECT * FROM t4 311 } 312} {12 -22} 313do_test check-4.6 { 314 catchsql { 315 UPDATE t4 SET x=0, y=1; 316 } 317} {1 {CHECK constraint failed: t4}} 318do_test check-4.7 { 319 execsql { 320 SELECT * FROM t4; 321 } 322} {12 -22} 323do_test check-4.8 { 324 execsql { 325 PRAGMA ignore_check_constraints=ON; 326 UPDATE t4 SET x=0, y=1; 327 SELECT * FROM t4; 328 PRAGMA integrity_check; 329 } 330} {0 1 ok} 331do_execsql_test check-4.8.1 { 332 PRAGMA ignore_check_constraints=OFF; 333 PRAGMA integrity_check; 334} {{CHECK constraint failed in t4}} 335do_test check-4.9 { 336 catchsql { 337 UPDATE t4 SET x=0, y=2; 338 } 339} {1 {CHECK constraint failed: t4}} 340ifcapable vacuum { 341 do_test check_4.10 { 342 catchsql { 343 VACUUM 344 } 345 } {0 {}} 346} 347 348do_test check-5.1 { 349 catchsql { 350 CREATE TABLE t5(x, y, 351 CHECK( x*y<:abc ) 352 ); 353 } 354} {1 {parameters prohibited in CHECK constraints}} 355do_test check-5.2 { 356 catchsql { 357 CREATE TABLE t5(x, y, 358 CHECK( x*y<? ) 359 ); 360 } 361} {1 {parameters prohibited in CHECK constraints}} 362 363ifcapable conflict { 364 365do_test check-6.1 { 366 execsql {SELECT * FROM t1} 367} {4 11.0} 368do_test check-6.2 { 369 execsql { 370 UPDATE OR IGNORE t1 SET x=5; 371 SELECT * FROM t1; 372 } 373} {4 11.0} 374do_test check-6.3 { 375 execsql { 376 INSERT OR IGNORE INTO t1 VALUES(5,4.0); 377 SELECT * FROM t1; 378 } 379} {4 11.0} 380do_test check-6.4 { 381 execsql { 382 INSERT OR IGNORE INTO t1 VALUES(2,20.0); 383 SELECT * FROM t1; 384 } 385} {4 11.0 2 20.0} 386do_test check-6.5 { 387 catchsql { 388 UPDATE OR FAIL t1 SET x=7-x, y=y+1; 389 } 390} {1 {CHECK constraint failed: t1}} 391do_test check-6.6 { 392 execsql { 393 SELECT * FROM t1; 394 } 395} {3 12.0 2 20.0} 396do_test check-6.7 { 397 catchsql { 398 BEGIN; 399 INSERT INTO t1 VALUES(1,30.0); 400 INSERT OR ROLLBACK INTO t1 VALUES(8,40.0); 401 } 402} {1 {CHECK constraint failed: t1}} 403do_test check-6.8 { 404 catchsql { 405 COMMIT; 406 } 407} {1 {cannot commit - no transaction is active}} 408do_test check-6.9 { 409 execsql { 410 SELECT * FROM t1 411 } 412} {3 12.0 2 20.0} 413 414do_test check-6.11 { 415 execsql {SELECT * FROM t1} 416} {3 12.0 2 20.0} 417do_test check-6.12 { 418 catchsql { 419 REPLACE INTO t1 VALUES(6,7); 420 } 421} {1 {CHECK constraint failed: t1}} 422do_test check-6.13 { 423 execsql {SELECT * FROM t1} 424} {3 12.0 2 20.0} 425do_test check-6.14 { 426 catchsql { 427 INSERT OR IGNORE INTO t1 VALUES(6,7); 428 } 429} {0 {}} 430do_test check-6.15 { 431 execsql {SELECT * FROM t1} 432} {3 12.0 2 20.0} 433 434 435} 436 437#-------------------------------------------------------------------------- 438# If a connection opens a database that contains a CHECK constraint that 439# uses an unknown UDF, the schema should not be considered malformed. 440# Attempting to modify the table should fail (since the CHECK constraint 441# cannot be tested). 442# 443reset_db 444proc myfunc {x} {expr $x < 10} 445db func myfunc -deterministic myfunc 446 447do_execsql_test 7.1 { CREATE TABLE t6(a CHECK (myfunc(a))) } 448do_execsql_test 7.2 { INSERT INTO t6 VALUES(9) } 449do_catchsql_test 7.3 { INSERT INTO t6 VALUES(11) } \ 450 {1 {CHECK constraint failed: t6}} 451 452do_test 7.4 { 453 sqlite3 db2 test.db 454 execsql { SELECT * FROM t6 } db2 455} {9} 456 457do_test 7.5 { 458 catchsql { INSERT INTO t6 VALUES(8) } db2 459} {1 {unknown function: myfunc()}} 460 461do_test 7.6 { 462 catchsql { CREATE TABLE t7(a CHECK (myfunc(a))) } db2 463} {1 {no such function: myfunc}} 464 465do_test 7.7 { 466 db2 func myfunc myfunc 467 execsql { INSERT INTO t6 VALUES(8) } db2 468} {} 469 470do_test 7.8 { 471 db2 func myfunc myfunc 472 catchsql { INSERT INTO t6 VALUES(12) } db2 473} {1 {CHECK constraint failed: t6}} 474 475# 2013-08-02: Silently ignore database name qualifiers in CHECK constraints. 476# 477do_execsql_test 8.1 { 478 CREATE TABLE t810(a, CHECK( main.t810.a>0 )); 479 CREATE TABLE t811(b, CHECK( xyzzy.t811.b BETWEEN 5 AND 10 )); 480} {} 481 482# Make sure check constraints involving the ROWID are not ignored 483# 484do_execsql_test 9.1 { 485 CREATE TABLE t1( 486 a INTEGER PRIMARY KEY, 487 b INTEGER NOT NULL CONSTRAINT 'b-check' CHECK( b>a ), 488 c INTEGER NOT NULL CONSTRAINT 'c-check' CHECK( c>rowid*2 ), 489 d INTEGER NOT NULL CONSTRAINT 'd-check' CHECK( d BETWEEN b AND c ) 490 ); 491 INSERT INTO t1(a,b,c,d) VALUES(1,2,4,3),(2,4,6,5),(3,10,30,20); 492} {} 493do_catchsql_test 9.2 { 494 UPDATE t1 SET b=0 WHERE a=1; 495} {1 {CHECK constraint failed: b-check}} 496do_catchsql_test 9.3 { 497 UPDATE t1 SET c=a*2 WHERE a=1; 498} {1 {CHECK constraint failed: c-check}} 499 500# Integrity check on a VIEW with columns. 501# 502db close 503db2 close 504forcedelete test.db 505sqlite3 db test.db 506do_execsql_test 10.1 { 507 CREATE TABLE t1(x); 508 CREATE VIEW v1(y) AS SELECT x FROM t1; 509 PRAGMA integrity_check; 510} {ok} 511 512#------------------------------------------------------------------------- 513reset_db 514do_execsql_test 11.0 { 515 CREATE TABLE t1 (Col0 CHECK(1 COLLATE BINARY BETWEEN 1 AND 1) ) ; 516} 517do_execsql_test 11.1 { 518 INSERT INTO t1 VALUES (NULL); 519} 520do_execsql_test 11.2 { 521 INSERT INTO t1 VALUES (NULL); 522} 523 524do_execsql_test 11.3 { 525 CREATE TABLE t2(b, a CHECK( 526 CASE 'abc' COLLATE nocase WHEN a THEN 1 ELSE 0 END) 527 ); 528} 529do_execsql_test 11.4 { 530 INSERT INTO t2(a) VALUES('abc'); 531} 532do_execsql_test 11.5 { 533 INSERT INTO t2(b, a) VALUES(1, 'abc'||''); 534} 535do_execsql_test 11.6 { 536 INSERT INTO t2(b, a) VALUES(2, 'abc'); 537} 538 539finish_test 540 541 542finish_test 543