Annotation of embedaddon/sqlite3/test/e_fkey.test, revision 1.1
1.1 ! misho 1: # 2009 October 7
! 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: #
! 12: # This file implements tests to verify the "testable statements" in the
! 13: # foreignkeys.in document.
! 14: #
! 15: # The tests in this file are arranged to mirror the structure of
! 16: # foreignkey.in, with one exception: The statements in section 2, which
! 17: # deals with enabling/disabling foreign key support, is tested first,
! 18: # before section 1. This is because some statements in section 2 deal
! 19: # with builds that do not include complete foreign key support (because
! 20: # either SQLITE_OMIT_TRIGGER or SQLITE_OMIT_FOREIGN_KEY was defined
! 21: # at build time).
! 22: #
! 23:
! 24: set testdir [file dirname $argv0]
! 25: source $testdir/tester.tcl
! 26:
! 27: proc eqp {sql {db db}} { uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db }
! 28:
! 29: ###########################################################################
! 30: ### SECTION 2: Enabling Foreign Key Support
! 31: ###########################################################################
! 32:
! 33: #-------------------------------------------------------------------------
! 34: # EVIDENCE-OF: R-33710-56344 In order to use foreign key constraints in
! 35: # SQLite, the library must be compiled with neither
! 36: # SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER defined.
! 37: #
! 38: ifcapable trigger&&foreignkey {
! 39: do_test e_fkey-1 {
! 40: execsql {
! 41: PRAGMA foreign_keys = ON;
! 42: CREATE TABLE p(i PRIMARY KEY);
! 43: CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE);
! 44: INSERT INTO p VALUES('hello');
! 45: INSERT INTO c VALUES('hello');
! 46: UPDATE p SET i = 'world';
! 47: SELECT * FROM c;
! 48: }
! 49: } {world}
! 50: }
! 51:
! 52: #-------------------------------------------------------------------------
! 53: # Test the effects of defining OMIT_TRIGGER but not OMIT_FOREIGN_KEY.
! 54: #
! 55: # EVIDENCE-OF: R-44697-61543 If SQLITE_OMIT_TRIGGER is defined but
! 56: # SQLITE_OMIT_FOREIGN_KEY is not, then SQLite behaves as it did prior to
! 57: # version 3.6.19 - foreign key definitions are parsed and may be queried
! 58: # using PRAGMA foreign_key_list, but foreign key constraints are not
! 59: # enforced.
! 60: #
! 61: # Specifically, test that "PRAGMA foreign_keys" is a no-op in this case.
! 62: # When using the pragma to query the current setting, 0 rows are returned.
! 63: #
! 64: # EVIDENCE-OF: R-22567-44039 The PRAGMA foreign_keys command is a no-op
! 65: # in this configuration.
! 66: #
! 67: # EVIDENCE-OF: R-41784-13339 Tip: If the command "PRAGMA foreign_keys"
! 68: # returns no data instead of a single row containing "0" or "1", then
! 69: # the version of SQLite you are using does not support foreign keys
! 70: # (either because it is older than 3.6.19 or because it was compiled
! 71: # with SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER defined).
! 72: #
! 73: reset_db
! 74: ifcapable !trigger&&foreignkey {
! 75: do_test e_fkey-2.1 {
! 76: execsql {
! 77: PRAGMA foreign_keys = ON;
! 78: CREATE TABLE p(i PRIMARY KEY);
! 79: CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE);
! 80: INSERT INTO p VALUES('hello');
! 81: INSERT INTO c VALUES('hello');
! 82: UPDATE p SET i = 'world';
! 83: SELECT * FROM c;
! 84: }
! 85: } {hello}
! 86: do_test e_fkey-2.2 {
! 87: execsql { PRAGMA foreign_key_list(c) }
! 88: } {0 0 p j {} CASCADE {NO ACTION} NONE}
! 89: do_test e_fkey-2.3 {
! 90: execsql { PRAGMA foreign_keys }
! 91: } {}
! 92: }
! 93:
! 94:
! 95: #-------------------------------------------------------------------------
! 96: # Test the effects of defining OMIT_FOREIGN_KEY.
! 97: #
! 98: # EVIDENCE-OF: R-58428-36660 If OMIT_FOREIGN_KEY is defined, then
! 99: # foreign key definitions cannot even be parsed (attempting to specify a
! 100: # foreign key definition is a syntax error).
! 101: #
! 102: # Specifically, test that foreign key constraints cannot even be parsed
! 103: # in such a build.
! 104: #
! 105: reset_db
! 106: ifcapable !foreignkey {
! 107: do_test e_fkey-3.1 {
! 108: execsql { CREATE TABLE p(i PRIMARY KEY) }
! 109: catchsql { CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE) }
! 110: } {1 {near "ON": syntax error}}
! 111: do_test e_fkey-3.2 {
! 112: # This is allowed, as in this build, "REFERENCES" is not a keyword.
! 113: # The declared datatype of column j is "REFERENCES p".
! 114: execsql { CREATE TABLE c(j REFERENCES p) }
! 115: } {}
! 116: do_test e_fkey-3.3 {
! 117: execsql { PRAGMA table_info(c) }
! 118: } {0 j {REFERENCES p} 0 {} 0}
! 119: do_test e_fkey-3.4 {
! 120: execsql { PRAGMA foreign_key_list(c) }
! 121: } {}
! 122: do_test e_fkey-3.5 {
! 123: execsql { PRAGMA foreign_keys }
! 124: } {}
! 125: }
! 126:
! 127: ifcapable !foreignkey||!trigger { finish_test ; return }
! 128: reset_db
! 129:
! 130:
! 131: #-------------------------------------------------------------------------
! 132: # EVIDENCE-OF: R-07280-60510 Assuming the library is compiled with
! 133: # foreign key constraints enabled, it must still be enabled by the
! 134: # application at runtime, using the PRAGMA foreign_keys command.
! 135: #
! 136: # This also tests that foreign key constraints are disabled by default.
! 137: #
! 138: # EVIDENCE-OF: R-59578-04990 Foreign key constraints are disabled by
! 139: # default (for backwards compatibility), so must be enabled separately
! 140: # for each database connection separately.
! 141: #
! 142: drop_all_tables
! 143: do_test e_fkey-4.1 {
! 144: execsql {
! 145: CREATE TABLE p(i PRIMARY KEY);
! 146: CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE);
! 147: INSERT INTO p VALUES('hello');
! 148: INSERT INTO c VALUES('hello');
! 149: UPDATE p SET i = 'world';
! 150: SELECT * FROM c;
! 151: }
! 152: } {hello}
! 153: do_test e_fkey-4.2 {
! 154: execsql {
! 155: DELETE FROM c;
! 156: DELETE FROM p;
! 157: PRAGMA foreign_keys = ON;
! 158: INSERT INTO p VALUES('hello');
! 159: INSERT INTO c VALUES('hello');
! 160: UPDATE p SET i = 'world';
! 161: SELECT * FROM c;
! 162: }
! 163: } {world}
! 164:
! 165: #-------------------------------------------------------------------------
! 166: # EVIDENCE-OF: R-15278-54456 The application can can also use a PRAGMA
! 167: # foreign_keys statement to determine if foreign keys are currently
! 168: # enabled.
! 169: #
! 170: # This also tests the example code in section 2 of foreignkeys.in.
! 171: #
! 172: # EVIDENCE-OF: R-11255-19907
! 173: #
! 174: reset_db
! 175: do_test e_fkey-5.1 {
! 176: execsql { PRAGMA foreign_keys }
! 177: } {0}
! 178: do_test e_fkey-5.2 {
! 179: execsql {
! 180: PRAGMA foreign_keys = ON;
! 181: PRAGMA foreign_keys;
! 182: }
! 183: } {1}
! 184: do_test e_fkey-5.3 {
! 185: execsql {
! 186: PRAGMA foreign_keys = OFF;
! 187: PRAGMA foreign_keys;
! 188: }
! 189: } {0}
! 190:
! 191: #-------------------------------------------------------------------------
! 192: # Test that it is not possible to enable or disable foreign key support
! 193: # while not in auto-commit mode.
! 194: #
! 195: # EVIDENCE-OF: R-46649-58537 It is not possible to enable or disable
! 196: # foreign key constraints in the middle of a multi-statement transaction
! 197: # (when SQLite is not in autocommit mode). Attempting to do so does not
! 198: # return an error; it simply has no effect.
! 199: #
! 200: reset_db
! 201: do_test e_fkey-6.1 {
! 202: execsql {
! 203: PRAGMA foreign_keys = ON;
! 204: CREATE TABLE t1(a UNIQUE, b);
! 205: CREATE TABLE t2(c, d REFERENCES t1(a));
! 206: INSERT INTO t1 VALUES(1, 2);
! 207: INSERT INTO t2 VALUES(2, 1);
! 208: BEGIN;
! 209: PRAGMA foreign_keys = OFF;
! 210: }
! 211: catchsql {
! 212: DELETE FROM t1
! 213: }
! 214: } {1 {foreign key constraint failed}}
! 215: do_test e_fkey-6.2 {
! 216: execsql { PRAGMA foreign_keys }
! 217: } {1}
! 218: do_test e_fkey-6.3 {
! 219: execsql {
! 220: COMMIT;
! 221: PRAGMA foreign_keys = OFF;
! 222: BEGIN;
! 223: PRAGMA foreign_keys = ON;
! 224: DELETE FROM t1;
! 225: PRAGMA foreign_keys;
! 226: }
! 227: } {0}
! 228: do_test e_fkey-6.4 {
! 229: execsql COMMIT
! 230: } {}
! 231:
! 232: ###########################################################################
! 233: ### SECTION 1: Introduction to Foreign Key Constraints
! 234: ###########################################################################
! 235: execsql "PRAGMA foreign_keys = ON"
! 236:
! 237: #-------------------------------------------------------------------------
! 238: # Verify that the syntax in the first example in section 1 is valid.
! 239: #
! 240: # EVIDENCE-OF: R-04042-24825 To do so, a foreign key definition may be
! 241: # added by modifying the declaration of the track table to the
! 242: # following: CREATE TABLE track( trackid INTEGER, trackname TEXT,
! 243: # trackartist INTEGER, FOREIGN KEY(trackartist) REFERENCES
! 244: # artist(artistid) );
! 245: #
! 246: do_test e_fkey-7.1 {
! 247: execsql {
! 248: CREATE TABLE artist(
! 249: artistid INTEGER PRIMARY KEY,
! 250: artistname TEXT
! 251: );
! 252: CREATE TABLE track(
! 253: trackid INTEGER,
! 254: trackname TEXT,
! 255: trackartist INTEGER,
! 256: FOREIGN KEY(trackartist) REFERENCES artist(artistid)
! 257: );
! 258: }
! 259: } {}
! 260:
! 261: #-------------------------------------------------------------------------
! 262: # EVIDENCE-OF: R-61362-32087 Attempting to insert a row into the track
! 263: # table that does not correspond to any row in the artist table will
! 264: # fail,
! 265: #
! 266: do_test e_fkey-8.1 {
! 267: catchsql { INSERT INTO track VALUES(1, 'track 1', 1) }
! 268: } {1 {foreign key constraint failed}}
! 269: do_test e_fkey-8.2 {
! 270: execsql { INSERT INTO artist VALUES(2, 'artist 1') }
! 271: catchsql { INSERT INTO track VALUES(1, 'track 1', 1) }
! 272: } {1 {foreign key constraint failed}}
! 273: do_test e_fkey-8.2 {
! 274: execsql { INSERT INTO track VALUES(1, 'track 1', 2) }
! 275: } {}
! 276:
! 277: #-------------------------------------------------------------------------
! 278: # Attempting to delete a row from the 'artist' table while there are
! 279: # dependent rows in the track table also fails.
! 280: #
! 281: # EVIDENCE-OF: R-24401-52400 as will attempting to delete a row from the
! 282: # artist table when there exist dependent rows in the track table
! 283: #
! 284: do_test e_fkey-9.1 {
! 285: catchsql { DELETE FROM artist WHERE artistid = 2 }
! 286: } {1 {foreign key constraint failed}}
! 287: do_test e_fkey-9.2 {
! 288: execsql {
! 289: DELETE FROM track WHERE trackartist = 2;
! 290: DELETE FROM artist WHERE artistid = 2;
! 291: }
! 292: } {}
! 293:
! 294: #-------------------------------------------------------------------------
! 295: # If the foreign key column (trackartist) in table 'track' is set to NULL,
! 296: # there is no requirement for a matching row in the 'artist' table.
! 297: #
! 298: # EVIDENCE-OF: R-23980-48859 There is one exception: if the foreign key
! 299: # column in the track table is NULL, then no corresponding entry in the
! 300: # artist table is required.
! 301: #
! 302: do_test e_fkey-10.1 {
! 303: execsql {
! 304: INSERT INTO track VALUES(1, 'track 1', NULL);
! 305: INSERT INTO track VALUES(2, 'track 2', NULL);
! 306: }
! 307: } {}
! 308: do_test e_fkey-10.2 {
! 309: execsql { SELECT * FROM artist }
! 310: } {}
! 311: do_test e_fkey-10.3 {
! 312: # Setting the trackid to a non-NULL value fails, of course.
! 313: catchsql { UPDATE track SET trackartist = 5 WHERE trackid = 1 }
! 314: } {1 {foreign key constraint failed}}
! 315: do_test e_fkey-10.4 {
! 316: execsql {
! 317: INSERT INTO artist VALUES(5, 'artist 5');
! 318: UPDATE track SET trackartist = 5 WHERE trackid = 1;
! 319: }
! 320: catchsql { DELETE FROM artist WHERE artistid = 5}
! 321: } {1 {foreign key constraint failed}}
! 322: do_test e_fkey-10.5 {
! 323: execsql {
! 324: UPDATE track SET trackartist = NULL WHERE trackid = 1;
! 325: DELETE FROM artist WHERE artistid = 5;
! 326: }
! 327: } {}
! 328:
! 329: #-------------------------------------------------------------------------
! 330: # Test that the following is true fo all rows in the track table:
! 331: #
! 332: # trackartist IS NULL OR
! 333: # EXISTS(SELECT 1 FROM artist WHERE artistid=trackartist)
! 334: #
! 335: # EVIDENCE-OF: R-52486-21352 Expressed in SQL, this means that for every
! 336: # row in the track table, the following expression evaluates to true:
! 337: # trackartist IS NULL OR EXISTS(SELECT 1 FROM artist WHERE
! 338: # artistid=trackartist)
! 339:
! 340: # This procedure executes a test case to check that statement
! 341: # R-52486-21352 is true after executing the SQL statement passed.
! 342: # as the second argument.
! 343: proc test_r52486_21352 {tn sql} {
! 344: set res [catchsql $sql]
! 345: set results {
! 346: {0 {}}
! 347: {1 {PRIMARY KEY must be unique}}
! 348: {1 {foreign key constraint failed}}
! 349: }
! 350: if {[lsearch $results $res]<0} {
! 351: error $res
! 352: }
! 353:
! 354: do_test e_fkey-11.$tn {
! 355: execsql {
! 356: SELECT count(*) FROM track WHERE NOT (
! 357: trackartist IS NULL OR
! 358: EXISTS(SELECT 1 FROM artist WHERE artistid=trackartist)
! 359: )
! 360: }
! 361: } {0}
! 362: }
! 363:
! 364: # Execute a series of random INSERT, UPDATE and DELETE operations
! 365: # (some of which may fail due to FK or PK constraint violations) on
! 366: # the two tables in the example schema. Test that R-52486-21352
! 367: # is true after executing each operation.
! 368: #
! 369: set Template {
! 370: {INSERT INTO track VALUES($t, 'track $t', $a)}
! 371: {DELETE FROM track WHERE trackid = $t}
! 372: {UPDATE track SET trackartist = $a WHERE trackid = $t}
! 373: {INSERT INTO artist VALUES($a, 'artist $a')}
! 374: {DELETE FROM artist WHERE artistid = $a}
! 375: {UPDATE artist SET artistid = $a2 WHERE artistid = $a}
! 376: }
! 377: for {set i 0} {$i < 500} {incr i} {
! 378: set a [expr int(rand()*10)]
! 379: set a2 [expr int(rand()*10)]
! 380: set t [expr int(rand()*50)]
! 381: set sql [subst [lindex $Template [expr int(rand()*6)]]]
! 382:
! 383: test_r52486_21352 $i $sql
! 384: }
! 385:
! 386: #-------------------------------------------------------------------------
! 387: # Check that a NOT NULL constraint can be added to the example schema
! 388: # to prohibit NULL child keys from being inserted.
! 389: #
! 390: # EVIDENCE-OF: R-42412-59321 Tip: If the application requires a stricter
! 391: # relationship between artist and track, where NULL values are not
! 392: # permitted in the trackartist column, simply add the appropriate "NOT
! 393: # NULL" constraint to the schema.
! 394: #
! 395: drop_all_tables
! 396: do_test e_fkey-12.1 {
! 397: execsql {
! 398: CREATE TABLE artist(
! 399: artistid INTEGER PRIMARY KEY,
! 400: artistname TEXT
! 401: );
! 402: CREATE TABLE track(
! 403: trackid INTEGER,
! 404: trackname TEXT,
! 405: trackartist INTEGER NOT NULL,
! 406: FOREIGN KEY(trackartist) REFERENCES artist(artistid)
! 407: );
! 408: }
! 409: } {}
! 410: do_test e_fkey-12.2 {
! 411: catchsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', NULL) }
! 412: } {1 {track.trackartist may not be NULL}}
! 413:
! 414: #-------------------------------------------------------------------------
! 415: # EVIDENCE-OF: R-16127-35442
! 416: #
! 417: # Test an example from foreignkeys.html.
! 418: #
! 419: drop_all_tables
! 420: do_test e_fkey-13.1 {
! 421: execsql {
! 422: CREATE TABLE artist(
! 423: artistid INTEGER PRIMARY KEY,
! 424: artistname TEXT
! 425: );
! 426: CREATE TABLE track(
! 427: trackid INTEGER,
! 428: trackname TEXT,
! 429: trackartist INTEGER,
! 430: FOREIGN KEY(trackartist) REFERENCES artist(artistid)
! 431: );
! 432: INSERT INTO artist VALUES(1, 'Dean Martin');
! 433: INSERT INTO artist VALUES(2, 'Frank Sinatra');
! 434: INSERT INTO track VALUES(11, 'That''s Amore', 1);
! 435: INSERT INTO track VALUES(12, 'Christmas Blues', 1);
! 436: INSERT INTO track VALUES(13, 'My Way', 2);
! 437: }
! 438: } {}
! 439: do_test e_fkey-13.2 {
! 440: catchsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', 3) }
! 441: } {1 {foreign key constraint failed}}
! 442: do_test e_fkey-13.3 {
! 443: execsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', NULL) }
! 444: } {}
! 445: do_test e_fkey-13.4 {
! 446: catchsql {
! 447: UPDATE track SET trackartist = 3 WHERE trackname = 'Mr. Bojangles';
! 448: }
! 449: } {1 {foreign key constraint failed}}
! 450: do_test e_fkey-13.5 {
! 451: execsql {
! 452: INSERT INTO artist VALUES(3, 'Sammy Davis Jr.');
! 453: UPDATE track SET trackartist = 3 WHERE trackname = 'Mr. Bojangles';
! 454: INSERT INTO track VALUES(15, 'Boogie Woogie', 3);
! 455: }
! 456: } {}
! 457:
! 458: #-------------------------------------------------------------------------
! 459: # EVIDENCE-OF: R-15958-50233
! 460: #
! 461: # Test the second example from the first section of foreignkeys.html.
! 462: #
! 463: do_test e_fkey-14.1 {
! 464: catchsql {
! 465: DELETE FROM artist WHERE artistname = 'Frank Sinatra';
! 466: }
! 467: } {1 {foreign key constraint failed}}
! 468: do_test e_fkey-14.2 {
! 469: execsql {
! 470: DELETE FROM track WHERE trackname = 'My Way';
! 471: DELETE FROM artist WHERE artistname = 'Frank Sinatra';
! 472: }
! 473: } {}
! 474: do_test e_fkey-14.3 {
! 475: catchsql {
! 476: UPDATE artist SET artistid=4 WHERE artistname = 'Dean Martin';
! 477: }
! 478: } {1 {foreign key constraint failed}}
! 479: do_test e_fkey-14.4 {
! 480: execsql {
! 481: DELETE FROM track WHERE trackname IN('That''s Amore', 'Christmas Blues');
! 482: UPDATE artist SET artistid=4 WHERE artistname = 'Dean Martin';
! 483: }
! 484: } {}
! 485:
! 486:
! 487: #-------------------------------------------------------------------------
! 488: # EVIDENCE-OF: R-56032-24923 The foreign key constraint is satisfied if
! 489: # for each row in the child table either one or more of the child key
! 490: # columns are NULL, or there exists a row in the parent table for which
! 491: # each parent key column contains a value equal to the value in its
! 492: # associated child key column.
! 493: #
! 494: # Test also that the usual comparison rules are used when testing if there
! 495: # is a matching row in the parent table of a foreign key constraint.
! 496: #
! 497: # EVIDENCE-OF: R-57765-12380 In the above paragraph, the term "equal"
! 498: # means equal when values are compared using the rules specified here.
! 499: #
! 500: drop_all_tables
! 501: do_test e_fkey-15.1 {
! 502: execsql {
! 503: CREATE TABLE par(p PRIMARY KEY);
! 504: CREATE TABLE chi(c REFERENCES par);
! 505:
! 506: INSERT INTO par VALUES(1);
! 507: INSERT INTO par VALUES('1');
! 508: INSERT INTO par VALUES(X'31');
! 509: SELECT typeof(p) FROM par;
! 510: }
! 511: } {integer text blob}
! 512:
! 513: proc test_efkey_45 {tn isError sql} {
! 514: do_test e_fkey-15.$tn.1 "
! 515: catchsql {$sql}
! 516: " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError]
! 517:
! 518: do_test e_fkey-15.$tn.2 {
! 519: execsql {
! 520: SELECT * FROM chi WHERE c IS NOT NULL AND c NOT IN (SELECT p FROM par)
! 521: }
! 522: } {}
! 523: }
! 524:
! 525: test_efkey_45 1 0 "INSERT INTO chi VALUES(1)"
! 526: test_efkey_45 2 1 "INSERT INTO chi VALUES('1.0')"
! 527: test_efkey_45 3 0 "INSERT INTO chi VALUES('1')"
! 528: test_efkey_45 4 1 "DELETE FROM par WHERE p = '1'"
! 529: test_efkey_45 5 0 "DELETE FROM chi WHERE c = '1'"
! 530: test_efkey_45 6 0 "DELETE FROM par WHERE p = '1'"
! 531: test_efkey_45 7 1 "INSERT INTO chi VALUES('1')"
! 532: test_efkey_45 8 0 "INSERT INTO chi VALUES(X'31')"
! 533: test_efkey_45 9 1 "INSERT INTO chi VALUES(X'32')"
! 534:
! 535: #-------------------------------------------------------------------------
! 536: # Specifically, test that when comparing child and parent key values the
! 537: # default collation sequence of the parent key column is used.
! 538: #
! 539: # EVIDENCE-OF: R-15796-47513 When comparing text values, the collating
! 540: # sequence associated with the parent key column is always used.
! 541: #
! 542: drop_all_tables
! 543: do_test e_fkey-16.1 {
! 544: execsql {
! 545: CREATE TABLE t1(a COLLATE nocase PRIMARY KEY);
! 546: CREATE TABLE t2(b REFERENCES t1);
! 547: }
! 548: } {}
! 549: do_test e_fkey-16.2 {
! 550: execsql {
! 551: INSERT INTO t1 VALUES('oNe');
! 552: INSERT INTO t2 VALUES('one');
! 553: INSERT INTO t2 VALUES('ONE');
! 554: UPDATE t2 SET b = 'OnE';
! 555: UPDATE t1 SET a = 'ONE';
! 556: }
! 557: } {}
! 558: do_test e_fkey-16.3 {
! 559: catchsql { UPDATE t2 SET b = 'two' WHERE rowid = 1 }
! 560: } {1 {foreign key constraint failed}}
! 561: do_test e_fkey-16.4 {
! 562: catchsql { DELETE FROM t1 WHERE rowid = 1 }
! 563: } {1 {foreign key constraint failed}}
! 564:
! 565: #-------------------------------------------------------------------------
! 566: # Specifically, test that when comparing child and parent key values the
! 567: # affinity of the parent key column is applied to the child key value
! 568: # before the comparison takes place.
! 569: #
! 570: # EVIDENCE-OF: R-04240-13860 When comparing values, if the parent key
! 571: # column has an affinity, then that affinity is applied to the child key
! 572: # value before the comparison is performed.
! 573: #
! 574: drop_all_tables
! 575: do_test e_fkey-17.1 {
! 576: execsql {
! 577: CREATE TABLE t1(a NUMERIC PRIMARY KEY);
! 578: CREATE TABLE t2(b TEXT REFERENCES t1);
! 579: }
! 580: } {}
! 581: do_test e_fkey-17.2 {
! 582: execsql {
! 583: INSERT INTO t1 VALUES(1);
! 584: INSERT INTO t1 VALUES(2);
! 585: INSERT INTO t1 VALUES('three');
! 586: INSERT INTO t2 VALUES('2.0');
! 587: SELECT b, typeof(b) FROM t2;
! 588: }
! 589: } {2.0 text}
! 590: do_test e_fkey-17.3 {
! 591: execsql { SELECT typeof(a) FROM t1 }
! 592: } {integer integer text}
! 593: do_test e_fkey-17.4 {
! 594: catchsql { DELETE FROM t1 WHERE rowid = 2 }
! 595: } {1 {foreign key constraint failed}}
! 596:
! 597: ###########################################################################
! 598: ### SECTION 3: Required and Suggested Database Indexes
! 599: ###########################################################################
! 600:
! 601: #-------------------------------------------------------------------------
! 602: # A parent key must be either a PRIMARY KEY, subject to a UNIQUE
! 603: # constraint, or have a UNIQUE index created on it.
! 604: #
! 605: # EVIDENCE-OF: R-13435-26311 Usually, the parent key of a foreign key
! 606: # constraint is the primary key of the parent table. If they are not the
! 607: # primary key, then the parent key columns must be collectively subject
! 608: # to a UNIQUE constraint or have a UNIQUE index.
! 609: #
! 610: # Also test that if a parent key is not subject to a PRIMARY KEY or UNIQUE
! 611: # constraint, but does have a UNIQUE index created on it, then the UNIQUE index
! 612: # must use the default collation sequences associated with the parent key
! 613: # columns.
! 614: #
! 615: # EVIDENCE-OF: R-00376-39212 If the parent key columns have a UNIQUE
! 616: # index, then that index must use the collation sequences that are
! 617: # specified in the CREATE TABLE statement for the parent table.
! 618: #
! 619: drop_all_tables
! 620: do_test e_fkey-18.1 {
! 621: execsql {
! 622: CREATE TABLE t2(a REFERENCES t1(x));
! 623: }
! 624: } {}
! 625: proc test_efkey_57 {tn isError sql} {
! 626: catchsql { DROP TABLE t1 }
! 627: execsql $sql
! 628: do_test e_fkey-18.$tn {
! 629: catchsql { INSERT INTO t2 VALUES(NULL) }
! 630: } [lindex {{0 {}} {1 {foreign key mismatch}}} $isError]
! 631: }
! 632: test_efkey_57 2 0 { CREATE TABLE t1(x PRIMARY KEY) }
! 633: test_efkey_57 3 0 { CREATE TABLE t1(x UNIQUE) }
! 634: test_efkey_57 4 0 { CREATE TABLE t1(x); CREATE UNIQUE INDEX t1i ON t1(x) }
! 635: test_efkey_57 5 1 {
! 636: CREATE TABLE t1(x);
! 637: CREATE UNIQUE INDEX t1i ON t1(x COLLATE nocase);
! 638: }
! 639: test_efkey_57 6 1 { CREATE TABLE t1(x) }
! 640: test_efkey_57 7 1 { CREATE TABLE t1(x, y, PRIMARY KEY(x, y)) }
! 641: test_efkey_57 8 1 { CREATE TABLE t1(x, y, UNIQUE(x, y)) }
! 642: test_efkey_57 9 1 {
! 643: CREATE TABLE t1(x, y);
! 644: CREATE UNIQUE INDEX t1i ON t1(x, y);
! 645: }
! 646:
! 647:
! 648: #-------------------------------------------------------------------------
! 649: # This block tests an example in foreignkeys.html. Several testable
! 650: # statements refer to this example, as follows
! 651: #
! 652: # EVIDENCE-OF: R-27484-01467
! 653: #
! 654: # FK Constraints on child1, child2 and child3 are Ok.
! 655: #
! 656: # Problem with FK on child4:
! 657: #
! 658: # EVIDENCE-OF: R-51039-44840 The foreign key declared as part of table
! 659: # child4 is an error because even though the parent key column is
! 660: # indexed, the index is not UNIQUE.
! 661: #
! 662: # Problem with FK on child5:
! 663: #
! 664: # EVIDENCE-OF: R-01060-48788 The foreign key for table child5 is an
! 665: # error because even though the parent key column has a unique index,
! 666: # the index uses a different collating sequence.
! 667: #
! 668: # Problem with FK on child6 and child7:
! 669: #
! 670: # EVIDENCE-OF: R-63088-37469 Tables child6 and child7 are incorrect
! 671: # because while both have UNIQUE indices on their parent keys, the keys
! 672: # are not an exact match to the columns of a single UNIQUE index.
! 673: #
! 674: drop_all_tables
! 675: do_test e_fkey-19.1 {
! 676: execsql {
! 677: CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f);
! 678: CREATE UNIQUE INDEX i1 ON parent(c, d);
! 679: CREATE INDEX i2 ON parent(e);
! 680: CREATE UNIQUE INDEX i3 ON parent(f COLLATE nocase);
! 681:
! 682: CREATE TABLE child1(f, g REFERENCES parent(a)); -- Ok
! 683: CREATE TABLE child2(h, i REFERENCES parent(b)); -- Ok
! 684: CREATE TABLE child3(j, k, FOREIGN KEY(j, k) REFERENCES parent(c, d)); -- Ok
! 685: CREATE TABLE child4(l, m REFERENCES parent(e)); -- Err
! 686: CREATE TABLE child5(n, o REFERENCES parent(f)); -- Err
! 687: CREATE TABLE child6(p, q, FOREIGN KEY(p,q) REFERENCES parent(b, c)); -- Err
! 688: CREATE TABLE child7(r REFERENCES parent(c)); -- Err
! 689: }
! 690: } {}
! 691: do_test e_fkey-19.2 {
! 692: execsql {
! 693: INSERT INTO parent VALUES(1, 2, 3, 4, 5, 6);
! 694: INSERT INTO child1 VALUES('xxx', 1);
! 695: INSERT INTO child2 VALUES('xxx', 2);
! 696: INSERT INTO child3 VALUES(3, 4);
! 697: }
! 698: } {}
! 699: do_test e_fkey-19.2 {
! 700: catchsql { INSERT INTO child4 VALUES('xxx', 5) }
! 701: } {1 {foreign key mismatch}}
! 702: do_test e_fkey-19.3 {
! 703: catchsql { INSERT INTO child5 VALUES('xxx', 6) }
! 704: } {1 {foreign key mismatch}}
! 705: do_test e_fkey-19.4 {
! 706: catchsql { INSERT INTO child6 VALUES(2, 3) }
! 707: } {1 {foreign key mismatch}}
! 708: do_test e_fkey-19.5 {
! 709: catchsql { INSERT INTO child7 VALUES(3) }
! 710: } {1 {foreign key mismatch}}
! 711:
! 712: #-------------------------------------------------------------------------
! 713: # Test errors in the database schema that are detected while preparing
! 714: # DML statements. The error text for these messages always matches
! 715: # either "foreign key mismatch" or "no such table*" (using [string match]).
! 716: #
! 717: # EVIDENCE-OF: R-45488-08504 If the database schema contains foreign key
! 718: # errors that require looking at more than one table definition to
! 719: # identify, then those errors are not detected when the tables are
! 720: # created.
! 721: #
! 722: # EVIDENCE-OF: R-48391-38472 Instead, such errors prevent the
! 723: # application from preparing SQL statements that modify the content of
! 724: # the child or parent tables in ways that use the foreign keys.
! 725: #
! 726: # EVIDENCE-OF: R-03108-63659 The English language error message for
! 727: # foreign key DML errors is usually "foreign key mismatch" but can also
! 728: # be "no such table" if the parent table does not exist.
! 729: #
! 730: # EVIDENCE-OF: R-60781-26576 Foreign key DML errors are may be reported
! 731: # if: The parent table does not exist, or The parent key columns named
! 732: # in the foreign key constraint do not exist, or The parent key columns
! 733: # named in the foreign key constraint are not the primary key of the
! 734: # parent table and are not subject to a unique constraint using
! 735: # collating sequence specified in the CREATE TABLE, or The child table
! 736: # references the primary key of the parent without specifying the
! 737: # primary key columns and the number of primary key columns in the
! 738: # parent do not match the number of child key columns.
! 739: #
! 740: do_test e_fkey-20.1 {
! 741: execsql {
! 742: CREATE TABLE c1(c REFERENCES nosuchtable, d);
! 743:
! 744: CREATE TABLE p2(a, b, UNIQUE(a, b));
! 745: CREATE TABLE c2(c, d, FOREIGN KEY(c, d) REFERENCES p2(a, x));
! 746:
! 747: CREATE TABLE p3(a PRIMARY KEY, b);
! 748: CREATE TABLE c3(c REFERENCES p3(b), d);
! 749:
! 750: CREATE TABLE p4(a PRIMARY KEY, b);
! 751: CREATE UNIQUE INDEX p4i ON p4(b COLLATE nocase);
! 752: CREATE TABLE c4(c REFERENCES p4(b), d);
! 753:
! 754: CREATE TABLE p5(a PRIMARY KEY, b COLLATE nocase);
! 755: CREATE UNIQUE INDEX p5i ON p5(b COLLATE binary);
! 756: CREATE TABLE c5(c REFERENCES p5(b), d);
! 757:
! 758: CREATE TABLE p6(a PRIMARY KEY, b);
! 759: CREATE TABLE c6(c, d, FOREIGN KEY(c, d) REFERENCES p6);
! 760:
! 761: CREATE TABLE p7(a, b, PRIMARY KEY(a, b));
! 762: CREATE TABLE c7(c, d REFERENCES p7);
! 763: }
! 764: } {}
! 765:
! 766: foreach {tn tbl ptbl err} {
! 767: 2 c1 {} "no such table: main.nosuchtable"
! 768: 3 c2 p2 "foreign key mismatch"
! 769: 4 c3 p3 "foreign key mismatch"
! 770: 5 c4 p4 "foreign key mismatch"
! 771: 6 c5 p5 "foreign key mismatch"
! 772: 7 c6 p6 "foreign key mismatch"
! 773: 8 c7 p7 "foreign key mismatch"
! 774: } {
! 775: do_test e_fkey-20.$tn.1 {
! 776: catchsql "INSERT INTO $tbl VALUES('a', 'b')"
! 777: } [list 1 $err]
! 778: do_test e_fkey-20.$tn.2 {
! 779: catchsql "UPDATE $tbl SET c = ?, d = ?"
! 780: } [list 1 $err]
! 781: do_test e_fkey-20.$tn.3 {
! 782: catchsql "INSERT INTO $tbl SELECT ?, ?"
! 783: } [list 1 $err]
! 784:
! 785: if {$ptbl ne ""} {
! 786: do_test e_fkey-20.$tn.4 {
! 787: catchsql "DELETE FROM $ptbl"
! 788: } [list 1 $err]
! 789: do_test e_fkey-20.$tn.5 {
! 790: catchsql "UPDATE $ptbl SET a = ?, b = ?"
! 791: } [list 1 $err]
! 792: do_test e_fkey-20.$tn.6 {
! 793: catchsql "INSERT INTO $ptbl SELECT ?, ?"
! 794: } [list 1 $err]
! 795: }
! 796: }
! 797:
! 798: #-------------------------------------------------------------------------
! 799: # EVIDENCE-OF: R-19353-43643
! 800: #
! 801: # Test the example of foreign key mismatch errors caused by implicitly
! 802: # mapping a child key to the primary key of the parent table when the
! 803: # child key consists of a different number of columns to that primary key.
! 804: #
! 805: drop_all_tables
! 806: do_test e_fkey-21.1 {
! 807: execsql {
! 808: CREATE TABLE parent2(a, b, PRIMARY KEY(a,b));
! 809:
! 810: CREATE TABLE child8(x, y, FOREIGN KEY(x,y) REFERENCES parent2); -- Ok
! 811: CREATE TABLE child9(x REFERENCES parent2); -- Err
! 812: CREATE TABLE child10(x,y,z, FOREIGN KEY(x,y,z) REFERENCES parent2); -- Err
! 813: }
! 814: } {}
! 815: do_test e_fkey-21.2 {
! 816: execsql {
! 817: INSERT INTO parent2 VALUES('I', 'II');
! 818: INSERT INTO child8 VALUES('I', 'II');
! 819: }
! 820: } {}
! 821: do_test e_fkey-21.3 {
! 822: catchsql { INSERT INTO child9 VALUES('I') }
! 823: } {1 {foreign key mismatch}}
! 824: do_test e_fkey-21.4 {
! 825: catchsql { INSERT INTO child9 VALUES('II') }
! 826: } {1 {foreign key mismatch}}
! 827: do_test e_fkey-21.5 {
! 828: catchsql { INSERT INTO child9 VALUES(NULL) }
! 829: } {1 {foreign key mismatch}}
! 830: do_test e_fkey-21.6 {
! 831: catchsql { INSERT INTO child10 VALUES('I', 'II', 'III') }
! 832: } {1 {foreign key mismatch}}
! 833: do_test e_fkey-21.7 {
! 834: catchsql { INSERT INTO child10 VALUES(1, 2, 3) }
! 835: } {1 {foreign key mismatch}}
! 836: do_test e_fkey-21.8 {
! 837: catchsql { INSERT INTO child10 VALUES(NULL, NULL, NULL) }
! 838: } {1 {foreign key mismatch}}
! 839:
! 840: #-------------------------------------------------------------------------
! 841: # Test errors that are reported when creating the child table.
! 842: # Specifically:
! 843: #
! 844: # * different number of child and parent key columns, and
! 845: # * child columns that do not exist.
! 846: #
! 847: # EVIDENCE-OF: R-23682-59820 By contrast, if foreign key errors can be
! 848: # recognized simply by looking at the definition of the child table and
! 849: # without having to consult the parent table definition, then the CREATE
! 850: # TABLE statement for the child table fails.
! 851: #
! 852: # These errors are reported whether or not FK support is enabled.
! 853: #
! 854: # EVIDENCE-OF: R-33883-28833 Foreign key DDL errors are reported
! 855: # regardless of whether or not foreign key constraints are enabled when
! 856: # the table is created.
! 857: #
! 858: drop_all_tables
! 859: foreach fk [list OFF ON] {
! 860: execsql "PRAGMA foreign_keys = $fk"
! 861: set i 0
! 862: foreach {sql error} {
! 863: "CREATE TABLE child1(a, b, FOREIGN KEY(a, b) REFERENCES p(c))"
! 864: {number of columns in foreign key does not match the number of columns in the referenced table}
! 865: "CREATE TABLE child2(a, b, FOREIGN KEY(a, b) REFERENCES p(c, d, e))"
! 866: {number of columns in foreign key does not match the number of columns in the referenced table}
! 867: "CREATE TABLE child2(a, b, FOREIGN KEY(a, c) REFERENCES p(c, d))"
! 868: {unknown column "c" in foreign key definition}
! 869: "CREATE TABLE child2(a, b, FOREIGN KEY(c, b) REFERENCES p(c, d))"
! 870: {unknown column "c" in foreign key definition}
! 871: } {
! 872: do_test e_fkey-22.$fk.[incr i] {
! 873: catchsql $sql
! 874: } [list 1 $error]
! 875: }
! 876: }
! 877:
! 878: #-------------------------------------------------------------------------
! 879: # Test that a REFERENCING clause that does not specify parent key columns
! 880: # implicitly maps to the primary key of the parent table.
! 881: #
! 882: # EVIDENCE-OF: R-43879-08025 Attaching a "REFERENCES <parent-table>"
! 883: # clause to a column definition creates a foreign
! 884: # key constraint that maps the column to the primary key of
! 885: # <parent-table>.
! 886: #
! 887: do_test e_fkey-23.1 {
! 888: execsql {
! 889: CREATE TABLE p1(a, b, PRIMARY KEY(a, b));
! 890: CREATE TABLE p2(a, b PRIMARY KEY);
! 891: CREATE TABLE c1(c, d, FOREIGN KEY(c, d) REFERENCES p1);
! 892: CREATE TABLE c2(a, b REFERENCES p2);
! 893: }
! 894: } {}
! 895: proc test_efkey_60 {tn isError sql} {
! 896: do_test e_fkey-23.$tn "
! 897: catchsql {$sql}
! 898: " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError]
! 899: }
! 900:
! 901: test_efkey_60 2 1 "INSERT INTO c1 VALUES(239, 231)"
! 902: test_efkey_60 3 0 "INSERT INTO p1 VALUES(239, 231)"
! 903: test_efkey_60 4 0 "INSERT INTO c1 VALUES(239, 231)"
! 904: test_efkey_60 5 1 "INSERT INTO c2 VALUES(239, 231)"
! 905: test_efkey_60 6 0 "INSERT INTO p2 VALUES(239, 231)"
! 906: test_efkey_60 7 0 "INSERT INTO c2 VALUES(239, 231)"
! 907:
! 908: #-------------------------------------------------------------------------
! 909: # Test that an index on on the child key columns of an FK constraint
! 910: # is optional.
! 911: #
! 912: # EVIDENCE-OF: R-15417-28014 Indices are not required for child key
! 913: # columns
! 914: #
! 915: # Also test that if an index is created on the child key columns, it does
! 916: # not make a difference whether or not it is a UNIQUE index.
! 917: #
! 918: # EVIDENCE-OF: R-15741-50893 The child key index does not have to be
! 919: # (and usually will not be) a UNIQUE index.
! 920: #
! 921: drop_all_tables
! 922: do_test e_fkey-24.1 {
! 923: execsql {
! 924: CREATE TABLE parent(x, y, UNIQUE(y, x));
! 925: CREATE TABLE c1(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y));
! 926: CREATE TABLE c2(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y));
! 927: CREATE TABLE c3(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y));
! 928: CREATE INDEX c2i ON c2(a, b);
! 929: CREATE UNIQUE INDEX c3i ON c2(b, a);
! 930: }
! 931: } {}
! 932: proc test_efkey_61 {tn isError sql} {
! 933: do_test e_fkey-24.$tn "
! 934: catchsql {$sql}
! 935: " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError]
! 936: }
! 937: foreach {tn c} [list 2 c1 3 c2 4 c3] {
! 938: test_efkey_61 $tn.1 1 "INSERT INTO $c VALUES(1, 2)"
! 939: test_efkey_61 $tn.2 0 "INSERT INTO parent VALUES(1, 2)"
! 940: test_efkey_61 $tn.3 0 "INSERT INTO $c VALUES(1, 2)"
! 941:
! 942: execsql "DELETE FROM $c ; DELETE FROM parent"
! 943: }
! 944:
! 945: #-------------------------------------------------------------------------
! 946: # EVIDENCE-OF: R-00279-52283
! 947: #
! 948: # Test an example showing that when a row is deleted from the parent
! 949: # table, the child table is queried for orphaned rows as follows:
! 950: #
! 951: # SELECT rowid FROM track WHERE trackartist = ?
! 952: #
! 953: # EVIDENCE-OF: R-23302-30956 If this SELECT returns any rows at all,
! 954: # then SQLite concludes that deleting the row from the parent table
! 955: # would violate the foreign key constraint and returns an error.
! 956: #
! 957: do_test e_fkey-25.1 {
! 958: execsql {
! 959: CREATE TABLE artist(
! 960: artistid INTEGER PRIMARY KEY,
! 961: artistname TEXT
! 962: );
! 963: CREATE TABLE track(
! 964: trackid INTEGER,
! 965: trackname TEXT,
! 966: trackartist INTEGER,
! 967: FOREIGN KEY(trackartist) REFERENCES artist(artistid)
! 968: );
! 969: }
! 970: } {}
! 971: do_execsql_test e_fkey-25.2 {
! 972: PRAGMA foreign_keys = OFF;
! 973: EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
! 974: EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?;
! 975: } {
! 976: 0 0 0 {SCAN TABLE artist (~1000000 rows)}
! 977: 0 0 0 {SCAN TABLE track (~100000 rows)}
! 978: }
! 979: do_execsql_test e_fkey-25.3 {
! 980: PRAGMA foreign_keys = ON;
! 981: EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
! 982: } {
! 983: 0 0 0 {SCAN TABLE artist (~1000000 rows)}
! 984: 0 0 0 {SCAN TABLE track (~100000 rows)}
! 985: }
! 986: do_test e_fkey-25.4 {
! 987: execsql {
! 988: INSERT INTO artist VALUES(5, 'artist 5');
! 989: INSERT INTO artist VALUES(6, 'artist 6');
! 990: INSERT INTO artist VALUES(7, 'artist 7');
! 991: INSERT INTO track VALUES(1, 'track 1', 5);
! 992: INSERT INTO track VALUES(2, 'track 2', 6);
! 993: }
! 994: } {}
! 995:
! 996: do_test e_fkey-25.5 {
! 997: concat \
! 998: [execsql { SELECT rowid FROM track WHERE trackartist = 5 }] \
! 999: [catchsql { DELETE FROM artist WHERE artistid = 5 }]
! 1000: } {1 1 {foreign key constraint failed}}
! 1001:
! 1002: do_test e_fkey-25.6 {
! 1003: concat \
! 1004: [execsql { SELECT rowid FROM track WHERE trackartist = 7 }] \
! 1005: [catchsql { DELETE FROM artist WHERE artistid = 7 }]
! 1006: } {0 {}}
! 1007:
! 1008: do_test e_fkey-25.7 {
! 1009: concat \
! 1010: [execsql { SELECT rowid FROM track WHERE trackartist = 6 }] \
! 1011: [catchsql { DELETE FROM artist WHERE artistid = 6 }]
! 1012: } {2 1 {foreign key constraint failed}}
! 1013:
! 1014: #-------------------------------------------------------------------------
! 1015: # EVIDENCE-OF: R-47936-10044 Or, more generally:
! 1016: # SELECT rowid FROM <child-table> WHERE <child-key> = :parent_key_value
! 1017: #
! 1018: # Test that when a row is deleted from the parent table of an FK
! 1019: # constraint, the child table is queried for orphaned rows. The
! 1020: # query is equivalent to:
! 1021: #
! 1022: # SELECT rowid FROM <child-table> WHERE <child-key> = :parent_key_value
! 1023: #
! 1024: # Also test that when a row is inserted into the parent table, or when the
! 1025: # parent key values of an existing row are modified, a query equivalent
! 1026: # to the following is planned. In some cases it is not executed, but it
! 1027: # is always planned.
! 1028: #
! 1029: # SELECT rowid FROM <child-table> WHERE <child-key> = :parent_key_value
! 1030: #
! 1031: # EVIDENCE-OF: R-61616-46700 Similar queries may be run if the content
! 1032: # of the parent key is modified or a new row is inserted into the parent
! 1033: # table.
! 1034: #
! 1035: #
! 1036: drop_all_tables
! 1037: do_test e_fkey-26.1 {
! 1038: execsql { CREATE TABLE parent(x, y, UNIQUE(y, x)) }
! 1039: } {}
! 1040: foreach {tn sql} {
! 1041: 2 {
! 1042: CREATE TABLE child(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y))
! 1043: }
! 1044: 3 {
! 1045: CREATE TABLE child(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y));
! 1046: CREATE INDEX childi ON child(a, b);
! 1047: }
! 1048: 4 {
! 1049: CREATE TABLE child(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y));
! 1050: CREATE UNIQUE INDEX childi ON child(b, a);
! 1051: }
! 1052: } {
! 1053: execsql $sql
! 1054:
! 1055: execsql {PRAGMA foreign_keys = OFF}
! 1056: set delete [concat \
! 1057: [eqp "DELETE FROM parent WHERE 1"] \
! 1058: [eqp "SELECT rowid FROM child WHERE a = ? AND b = ?"]
! 1059: ]
! 1060: set update [concat \
! 1061: [eqp "UPDATE parent SET x=?, y=?"] \
! 1062: [eqp "SELECT rowid FROM child WHERE a = ? AND b = ?"] \
! 1063: [eqp "SELECT rowid FROM child WHERE a = ? AND b = ?"]
! 1064: ]
! 1065: execsql {PRAGMA foreign_keys = ON}
! 1066:
! 1067: do_test e_fkey-26.$tn.1 { eqp "DELETE FROM parent WHERE 1" } $delete
! 1068: do_test e_fkey-26.$tn.2 { eqp "UPDATE parent set x=?, y=?" } $update
! 1069:
! 1070: execsql {DROP TABLE child}
! 1071: }
! 1072:
! 1073: #-------------------------------------------------------------------------
! 1074: # EVIDENCE-OF: R-14553-34013
! 1075: #
! 1076: # Test the example schema at the end of section 3. Also test that is
! 1077: # is "efficient". In this case "efficient" means that foreign key
! 1078: # related operations on the parent table do not provoke linear scans.
! 1079: #
! 1080: drop_all_tables
! 1081: do_test e_fkey-27.1 {
! 1082: execsql {
! 1083: CREATE TABLE artist(
! 1084: artistid INTEGER PRIMARY KEY,
! 1085: artistname TEXT
! 1086: );
! 1087: CREATE TABLE track(
! 1088: trackid INTEGER,
! 1089: trackname TEXT,
! 1090: trackartist INTEGER REFERENCES artist
! 1091: );
! 1092: CREATE INDEX trackindex ON track(trackartist);
! 1093: }
! 1094: } {}
! 1095: do_test e_fkey-27.2 {
! 1096: eqp { INSERT INTO artist VALUES(?, ?) }
! 1097: } {}
! 1098: do_execsql_test e_fkey-27.3 {
! 1099: EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ?
! 1100: } {
! 1101: 0 0 0 {SCAN TABLE artist (~1000000 rows)}
! 1102: 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)}
! 1103: 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)}
! 1104: }
! 1105: do_execsql_test e_fkey-27.4 {
! 1106: EXPLAIN QUERY PLAN DELETE FROM artist
! 1107: } {
! 1108: 0 0 0 {SCAN TABLE artist (~1000000 rows)}
! 1109: 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)}
! 1110: }
! 1111:
! 1112:
! 1113: ###########################################################################
! 1114: ### SECTION 4.1: Composite Foreign Key Constraints
! 1115: ###########################################################################
! 1116:
! 1117: #-------------------------------------------------------------------------
! 1118: # Check that parent and child keys must have the same number of columns.
! 1119: #
! 1120: # EVIDENCE-OF: R-41062-34431 Parent and child keys must have the same
! 1121: # cardinality.
! 1122: #
! 1123: foreach {tn sql err} {
! 1124: 1 "CREATE TABLE c(jj REFERENCES p(x, y))"
! 1125: {foreign key on jj should reference only one column of table p}
! 1126:
! 1127: 2 "CREATE TABLE c(jj REFERENCES p())" {near ")": syntax error}
! 1128:
! 1129: 3 "CREATE TABLE c(jj, FOREIGN KEY(jj) REFERENCES p(x, y))"
! 1130: {number of columns in foreign key does not match the number of columns in the referenced table}
! 1131:
! 1132: 4 "CREATE TABLE c(jj, FOREIGN KEY(jj) REFERENCES p())"
! 1133: {near ")": syntax error}
! 1134:
! 1135: 5 "CREATE TABLE c(ii, jj, FOREIGN KEY(jj, ii) REFERENCES p())"
! 1136: {near ")": syntax error}
! 1137:
! 1138: 6 "CREATE TABLE c(ii, jj, FOREIGN KEY(jj, ii) REFERENCES p(x))"
! 1139: {number of columns in foreign key does not match the number of columns in the referenced table}
! 1140:
! 1141: 7 "CREATE TABLE c(ii, jj, FOREIGN KEY(jj, ii) REFERENCES p(x,y,z))"
! 1142: {number of columns in foreign key does not match the number of columns in the referenced table}
! 1143: } {
! 1144: drop_all_tables
! 1145: do_test e_fkey-28.$tn [list catchsql $sql] [list 1 $err]
! 1146: }
! 1147: do_test e_fkey-28.8 {
! 1148: drop_all_tables
! 1149: execsql {
! 1150: CREATE TABLE p(x PRIMARY KEY);
! 1151: CREATE TABLE c(a, b, FOREIGN KEY(a,b) REFERENCES p);
! 1152: }
! 1153: catchsql {DELETE FROM p}
! 1154: } {1 {foreign key mismatch}}
! 1155: do_test e_fkey-28.9 {
! 1156: drop_all_tables
! 1157: execsql {
! 1158: CREATE TABLE p(x, y, PRIMARY KEY(x,y));
! 1159: CREATE TABLE c(a REFERENCES p);
! 1160: }
! 1161: catchsql {DELETE FROM p}
! 1162: } {1 {foreign key mismatch}}
! 1163:
! 1164:
! 1165: #-------------------------------------------------------------------------
! 1166: # EVIDENCE-OF: R-24676-09859
! 1167: #
! 1168: # Test the example schema in the "Composite Foreign Key Constraints"
! 1169: # section.
! 1170: #
! 1171: do_test e_fkey-29.1 {
! 1172: execsql {
! 1173: CREATE TABLE album(
! 1174: albumartist TEXT,
! 1175: albumname TEXT,
! 1176: albumcover BINARY,
! 1177: PRIMARY KEY(albumartist, albumname)
! 1178: );
! 1179: CREATE TABLE song(
! 1180: songid INTEGER,
! 1181: songartist TEXT,
! 1182: songalbum TEXT,
! 1183: songname TEXT,
! 1184: FOREIGN KEY(songartist, songalbum) REFERENCES album(albumartist,albumname)
! 1185: );
! 1186: }
! 1187: } {}
! 1188:
! 1189: do_test e_fkey-29.2 {
! 1190: execsql {
! 1191: INSERT INTO album VALUES('Elvis Presley', 'Elvis'' Christmas Album', NULL);
! 1192: INSERT INTO song VALUES(
! 1193: 1, 'Elvis Presley', 'Elvis'' Christmas Album', 'Here Comes Santa Clause'
! 1194: );
! 1195: }
! 1196: } {}
! 1197: do_test e_fkey-29.3 {
! 1198: catchsql {
! 1199: INSERT INTO song VALUES(2, 'Elvis Presley', 'Elvis Is Back!', 'Fever');
! 1200: }
! 1201: } {1 {foreign key constraint failed}}
! 1202:
! 1203:
! 1204: #-------------------------------------------------------------------------
! 1205: # EVIDENCE-OF: R-33626-48418 In SQLite, if any of the child key columns
! 1206: # (in this case songartist and songalbum) are NULL, then there is no
! 1207: # requirement for a corresponding row in the parent table.
! 1208: #
! 1209: do_test e_fkey-30.1 {
! 1210: execsql {
! 1211: INSERT INTO song VALUES(2, 'Elvis Presley', NULL, 'Fever');
! 1212: INSERT INTO song VALUES(3, NULL, 'Elvis Is Back', 'Soldier Boy');
! 1213: }
! 1214: } {}
! 1215:
! 1216: ###########################################################################
! 1217: ### SECTION 4.2: Deferred Foreign Key Constraints
! 1218: ###########################################################################
! 1219:
! 1220: #-------------------------------------------------------------------------
! 1221: # Test that if a statement violates an immediate FK constraint, and the
! 1222: # database does not satisfy the FK constraint once all effects of the
! 1223: # statement have been applied, an error is reported and the effects of
! 1224: # the statement rolled back.
! 1225: #
! 1226: # EVIDENCE-OF: R-09323-30470 If a statement modifies the contents of the
! 1227: # database so that an immediate foreign key constraint is in violation
! 1228: # at the conclusion the statement, an exception is thrown and the
! 1229: # effects of the statement are reverted.
! 1230: #
! 1231: drop_all_tables
! 1232: do_test e_fkey-31.1 {
! 1233: execsql {
! 1234: CREATE TABLE king(a, b, PRIMARY KEY(a));
! 1235: CREATE TABLE prince(c REFERENCES king, d);
! 1236: }
! 1237: } {}
! 1238:
! 1239: do_test e_fkey-31.2 {
! 1240: # Execute a statement that violates the immediate FK constraint.
! 1241: catchsql { INSERT INTO prince VALUES(1, 2) }
! 1242: } {1 {foreign key constraint failed}}
! 1243:
! 1244: do_test e_fkey-31.3 {
! 1245: # This time, use a trigger to fix the constraint violation before the
! 1246: # statement has finished executing. Then execute the same statement as
! 1247: # in the previous test case. This time, no error.
! 1248: execsql {
! 1249: CREATE TRIGGER kt AFTER INSERT ON prince WHEN
! 1250: NOT EXISTS (SELECT a FROM king WHERE a = new.c)
! 1251: BEGIN
! 1252: INSERT INTO king VALUES(new.c, NULL);
! 1253: END
! 1254: }
! 1255: execsql { INSERT INTO prince VALUES(1, 2) }
! 1256: } {}
! 1257:
! 1258: # Test that operating inside a transaction makes no difference to
! 1259: # immediate constraint violation handling.
! 1260: do_test e_fkey-31.4 {
! 1261: execsql {
! 1262: BEGIN;
! 1263: INSERT INTO prince VALUES(2, 3);
! 1264: DROP TRIGGER kt;
! 1265: }
! 1266: catchsql { INSERT INTO prince VALUES(3, 4) }
! 1267: } {1 {foreign key constraint failed}}
! 1268: do_test e_fkey-31.5 {
! 1269: execsql {
! 1270: COMMIT;
! 1271: SELECT * FROM king;
! 1272: }
! 1273: } {1 {} 2 {}}
! 1274:
! 1275: #-------------------------------------------------------------------------
! 1276: # Test that if a deferred constraint is violated within a transaction,
! 1277: # nothing happens immediately and the database is allowed to persist
! 1278: # in a state that does not satisfy the FK constraint. However attempts
! 1279: # to COMMIT the transaction fail until the FK constraint is satisfied.
! 1280: #
! 1281: # EVIDENCE-OF: R-49178-21358 By contrast, if a statement modifies the
! 1282: # contents of the database such that a deferred foreign key constraint
! 1283: # is violated, the violation is not reported immediately.
! 1284: #
! 1285: # EVIDENCE-OF: R-39692-12488 Deferred foreign key constraints are not
! 1286: # checked until the transaction tries to COMMIT.
! 1287: #
! 1288: # EVIDENCE-OF: R-55147-47664 For as long as the user has an open
! 1289: # transaction, the database is allowed to exist in a state that violates
! 1290: # any number of deferred foreign key constraints.
! 1291: #
! 1292: # EVIDENCE-OF: R-29604-30395 However, COMMIT will fail as long as
! 1293: # foreign key constraints remain in violation.
! 1294: #
! 1295: proc test_efkey_34 {tn isError sql} {
! 1296: do_test e_fkey-32.$tn "
! 1297: catchsql {$sql}
! 1298: " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError]
! 1299: }
! 1300: drop_all_tables
! 1301:
! 1302: test_efkey_34 1 0 {
! 1303: CREATE TABLE ll(k PRIMARY KEY);
! 1304: CREATE TABLE kk(c REFERENCES ll DEFERRABLE INITIALLY DEFERRED);
! 1305: }
! 1306: test_efkey_34 2 0 "BEGIN"
! 1307: test_efkey_34 3 0 "INSERT INTO kk VALUES(5)"
! 1308: test_efkey_34 4 0 "INSERT INTO kk VALUES(10)"
! 1309: test_efkey_34 5 1 "COMMIT"
! 1310: test_efkey_34 6 0 "INSERT INTO ll VALUES(10)"
! 1311: test_efkey_34 7 1 "COMMIT"
! 1312: test_efkey_34 8 0 "INSERT INTO ll VALUES(5)"
! 1313: test_efkey_34 9 0 "COMMIT"
! 1314:
! 1315: #-------------------------------------------------------------------------
! 1316: # When not running inside a transaction, a deferred constraint is similar
! 1317: # to an immediate constraint (violations are reported immediately).
! 1318: #
! 1319: # EVIDENCE-OF: R-56844-61705 If the current statement is not inside an
! 1320: # explicit transaction (a BEGIN/COMMIT/ROLLBACK block), then an implicit
! 1321: # transaction is committed as soon as the statement has finished
! 1322: # executing. In this case deferred constraints behave the same as
! 1323: # immediate constraints.
! 1324: #
! 1325: drop_all_tables
! 1326: proc test_efkey_35 {tn isError sql} {
! 1327: do_test e_fkey-33.$tn "
! 1328: catchsql {$sql}
! 1329: " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError]
! 1330: }
! 1331: do_test e_fkey-33.1 {
! 1332: execsql {
! 1333: CREATE TABLE parent(x, y);
! 1334: CREATE UNIQUE INDEX pi ON parent(x, y);
! 1335: CREATE TABLE child(a, b,
! 1336: FOREIGN KEY(a, b) REFERENCES parent(x, y) DEFERRABLE INITIALLY DEFERRED
! 1337: );
! 1338: }
! 1339: } {}
! 1340: test_efkey_35 2 1 "INSERT INTO child VALUES('x', 'y')"
! 1341: test_efkey_35 3 0 "INSERT INTO parent VALUES('x', 'y')"
! 1342: test_efkey_35 4 0 "INSERT INTO child VALUES('x', 'y')"
! 1343:
! 1344:
! 1345: #-------------------------------------------------------------------------
! 1346: # EVIDENCE-OF: R-12782-61841
! 1347: #
! 1348: # Test that an FK constraint is made deferred by adding the following
! 1349: # to the definition:
! 1350: #
! 1351: # DEFERRABLE INITIALLY DEFERRED
! 1352: #
! 1353: # EVIDENCE-OF: R-09005-28791
! 1354: #
! 1355: # Also test that adding any of the following to a foreign key definition
! 1356: # makes the constraint IMMEDIATE:
! 1357: #
! 1358: # NOT DEFERRABLE INITIALLY DEFERRED
! 1359: # NOT DEFERRABLE INITIALLY IMMEDIATE
! 1360: # NOT DEFERRABLE
! 1361: # DEFERRABLE INITIALLY IMMEDIATE
! 1362: # DEFERRABLE
! 1363: #
! 1364: # Foreign keys are IMMEDIATE by default (if there is no DEFERRABLE or NOT
! 1365: # DEFERRABLE clause).
! 1366: #
! 1367: # EVIDENCE-OF: R-35290-16460 Foreign key constraints are immediate by
! 1368: # default.
! 1369: #
! 1370: # EVIDENCE-OF: R-30323-21917 Each foreign key constraint in SQLite is
! 1371: # classified as either immediate or deferred.
! 1372: #
! 1373: drop_all_tables
! 1374: do_test e_fkey-34.1 {
! 1375: execsql {
! 1376: CREATE TABLE parent(x, y, z, PRIMARY KEY(x,y,z));
! 1377: CREATE TABLE c1(a, b, c,
! 1378: FOREIGN KEY(a, b, c) REFERENCES parent NOT DEFERRABLE INITIALLY DEFERRED
! 1379: );
! 1380: CREATE TABLE c2(a, b, c,
! 1381: FOREIGN KEY(a, b, c) REFERENCES parent NOT DEFERRABLE INITIALLY IMMEDIATE
! 1382: );
! 1383: CREATE TABLE c3(a, b, c,
! 1384: FOREIGN KEY(a, b, c) REFERENCES parent NOT DEFERRABLE
! 1385: );
! 1386: CREATE TABLE c4(a, b, c,
! 1387: FOREIGN KEY(a, b, c) REFERENCES parent DEFERRABLE INITIALLY IMMEDIATE
! 1388: );
! 1389: CREATE TABLE c5(a, b, c,
! 1390: FOREIGN KEY(a, b, c) REFERENCES parent DEFERRABLE
! 1391: );
! 1392: CREATE TABLE c6(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent);
! 1393:
! 1394: -- This FK constraint is the only deferrable one.
! 1395: CREATE TABLE c7(a, b, c,
! 1396: FOREIGN KEY(a, b, c) REFERENCES parent DEFERRABLE INITIALLY DEFERRED
! 1397: );
! 1398:
! 1399: INSERT INTO parent VALUES('a', 'b', 'c');
! 1400: INSERT INTO parent VALUES('d', 'e', 'f');
! 1401: INSERT INTO parent VALUES('g', 'h', 'i');
! 1402: INSERT INTO parent VALUES('j', 'k', 'l');
! 1403: INSERT INTO parent VALUES('m', 'n', 'o');
! 1404: INSERT INTO parent VALUES('p', 'q', 'r');
! 1405: INSERT INTO parent VALUES('s', 't', 'u');
! 1406:
! 1407: INSERT INTO c1 VALUES('a', 'b', 'c');
! 1408: INSERT INTO c2 VALUES('d', 'e', 'f');
! 1409: INSERT INTO c3 VALUES('g', 'h', 'i');
! 1410: INSERT INTO c4 VALUES('j', 'k', 'l');
! 1411: INSERT INTO c5 VALUES('m', 'n', 'o');
! 1412: INSERT INTO c6 VALUES('p', 'q', 'r');
! 1413: INSERT INTO c7 VALUES('s', 't', 'u');
! 1414: }
! 1415: } {}
! 1416:
! 1417: proc test_efkey_29 {tn sql isError} {
! 1418: do_test e_fkey-34.$tn "catchsql {$sql}" [
! 1419: lindex {{0 {}} {1 {foreign key constraint failed}}} $isError
! 1420: ]
! 1421: }
! 1422: test_efkey_29 2 "BEGIN" 0
! 1423: test_efkey_29 3 "DELETE FROM parent WHERE x = 'a'" 1
! 1424: test_efkey_29 4 "DELETE FROM parent WHERE x = 'd'" 1
! 1425: test_efkey_29 5 "DELETE FROM parent WHERE x = 'g'" 1
! 1426: test_efkey_29 6 "DELETE FROM parent WHERE x = 'j'" 1
! 1427: test_efkey_29 7 "DELETE FROM parent WHERE x = 'm'" 1
! 1428: test_efkey_29 8 "DELETE FROM parent WHERE x = 'p'" 1
! 1429: test_efkey_29 9 "DELETE FROM parent WHERE x = 's'" 0
! 1430: test_efkey_29 10 "COMMIT" 1
! 1431: test_efkey_29 11 "ROLLBACK" 0
! 1432:
! 1433: test_efkey_29 9 "BEGIN" 0
! 1434: test_efkey_29 10 "UPDATE parent SET z = 'z' WHERE z = 'c'" 1
! 1435: test_efkey_29 11 "UPDATE parent SET z = 'z' WHERE z = 'f'" 1
! 1436: test_efkey_29 12 "UPDATE parent SET z = 'z' WHERE z = 'i'" 1
! 1437: test_efkey_29 13 "UPDATE parent SET z = 'z' WHERE z = 'l'" 1
! 1438: test_efkey_29 14 "UPDATE parent SET z = 'z' WHERE z = 'o'" 1
! 1439: test_efkey_29 15 "UPDATE parent SET z = 'z' WHERE z = 'r'" 1
! 1440: test_efkey_29 16 "UPDATE parent SET z = 'z' WHERE z = 'u'" 0
! 1441: test_efkey_29 17 "COMMIT" 1
! 1442: test_efkey_29 18 "ROLLBACK" 0
! 1443:
! 1444: test_efkey_29 17 "BEGIN" 0
! 1445: test_efkey_29 18 "INSERT INTO c1 VALUES(1, 2, 3)" 1
! 1446: test_efkey_29 19 "INSERT INTO c2 VALUES(1, 2, 3)" 1
! 1447: test_efkey_29 20 "INSERT INTO c3 VALUES(1, 2, 3)" 1
! 1448: test_efkey_29 21 "INSERT INTO c4 VALUES(1, 2, 3)" 1
! 1449: test_efkey_29 22 "INSERT INTO c5 VALUES(1, 2, 3)" 1
! 1450: test_efkey_29 22 "INSERT INTO c6 VALUES(1, 2, 3)" 1
! 1451: test_efkey_29 22 "INSERT INTO c7 VALUES(1, 2, 3)" 0
! 1452: test_efkey_29 23 "COMMIT" 1
! 1453: test_efkey_29 24 "INSERT INTO parent VALUES(1, 2, 3)" 0
! 1454: test_efkey_29 25 "COMMIT" 0
! 1455:
! 1456: test_efkey_29 26 "BEGIN" 0
! 1457: test_efkey_29 27 "UPDATE c1 SET a = 10" 1
! 1458: test_efkey_29 28 "UPDATE c2 SET a = 10" 1
! 1459: test_efkey_29 29 "UPDATE c3 SET a = 10" 1
! 1460: test_efkey_29 30 "UPDATE c4 SET a = 10" 1
! 1461: test_efkey_29 31 "UPDATE c5 SET a = 10" 1
! 1462: test_efkey_29 31 "UPDATE c6 SET a = 10" 1
! 1463: test_efkey_29 31 "UPDATE c7 SET a = 10" 0
! 1464: test_efkey_29 32 "COMMIT" 1
! 1465: test_efkey_29 33 "ROLLBACK" 0
! 1466:
! 1467: #-------------------------------------------------------------------------
! 1468: # EVIDENCE-OF: R-24499-57071
! 1469: #
! 1470: # Test an example from foreignkeys.html dealing with a deferred foreign
! 1471: # key constraint.
! 1472: #
! 1473: do_test e_fkey-35.1 {
! 1474: drop_all_tables
! 1475: execsql {
! 1476: CREATE TABLE artist(
! 1477: artistid INTEGER PRIMARY KEY,
! 1478: artistname TEXT
! 1479: );
! 1480: CREATE TABLE track(
! 1481: trackid INTEGER,
! 1482: trackname TEXT,
! 1483: trackartist INTEGER REFERENCES artist(artistid) DEFERRABLE INITIALLY DEFERRED
! 1484: );
! 1485: }
! 1486: } {}
! 1487: do_test e_fkey-35.2 {
! 1488: execsql {
! 1489: BEGIN;
! 1490: INSERT INTO track VALUES(1, 'White Christmas', 5);
! 1491: }
! 1492: catchsql COMMIT
! 1493: } {1 {foreign key constraint failed}}
! 1494: do_test e_fkey-35.3 {
! 1495: execsql {
! 1496: INSERT INTO artist VALUES(5, 'Bing Crosby');
! 1497: COMMIT;
! 1498: }
! 1499: } {}
! 1500:
! 1501: #-------------------------------------------------------------------------
! 1502: # Verify that a nested savepoint may be released without satisfying
! 1503: # deferred foreign key constraints.
! 1504: #
! 1505: # EVIDENCE-OF: R-07223-48323 A nested savepoint transaction may be
! 1506: # RELEASEd while the database is in a state that does not satisfy a
! 1507: # deferred foreign key constraint.
! 1508: #
! 1509: drop_all_tables
! 1510: do_test e_fkey-36.1 {
! 1511: execsql {
! 1512: CREATE TABLE t1(a PRIMARY KEY,
! 1513: b REFERENCES t1 DEFERRABLE INITIALLY DEFERRED
! 1514: );
! 1515: INSERT INTO t1 VALUES(1, 1);
! 1516: INSERT INTO t1 VALUES(2, 2);
! 1517: INSERT INTO t1 VALUES(3, 3);
! 1518: }
! 1519: } {}
! 1520: do_test e_fkey-36.2 {
! 1521: execsql {
! 1522: BEGIN;
! 1523: SAVEPOINT one;
! 1524: INSERT INTO t1 VALUES(4, 5);
! 1525: RELEASE one;
! 1526: }
! 1527: } {}
! 1528: do_test e_fkey-36.3 {
! 1529: catchsql COMMIT
! 1530: } {1 {foreign key constraint failed}}
! 1531: do_test e_fkey-36.4 {
! 1532: execsql {
! 1533: UPDATE t1 SET a = 5 WHERE a = 4;
! 1534: COMMIT;
! 1535: }
! 1536: } {}
! 1537:
! 1538:
! 1539: #-------------------------------------------------------------------------
! 1540: # Check that a transaction savepoint (an outermost savepoint opened when
! 1541: # the database was in auto-commit mode) cannot be released without
! 1542: # satisfying deferred foreign key constraints. It may be rolled back.
! 1543: #
! 1544: # EVIDENCE-OF: R-44295-13823 A transaction savepoint (a non-nested
! 1545: # savepoint that was opened while there was not currently an open
! 1546: # transaction), on the other hand, is subject to the same restrictions
! 1547: # as a COMMIT - attempting to RELEASE it while the database is in such a
! 1548: # state will fail.
! 1549: #
! 1550: do_test e_fkey-37.1 {
! 1551: execsql {
! 1552: SAVEPOINT one;
! 1553: SAVEPOINT two;
! 1554: INSERT INTO t1 VALUES(6, 7);
! 1555: RELEASE two;
! 1556: }
! 1557: } {}
! 1558: do_test e_fkey-37.2 {
! 1559: catchsql {RELEASE one}
! 1560: } {1 {foreign key constraint failed}}
! 1561: do_test e_fkey-37.3 {
! 1562: execsql {
! 1563: UPDATE t1 SET a = 7 WHERE a = 6;
! 1564: RELEASE one;
! 1565: }
! 1566: } {}
! 1567: do_test e_fkey-37.4 {
! 1568: execsql {
! 1569: SAVEPOINT one;
! 1570: SAVEPOINT two;
! 1571: INSERT INTO t1 VALUES(9, 10);
! 1572: RELEASE two;
! 1573: }
! 1574: } {}
! 1575: do_test e_fkey-37.5 {
! 1576: catchsql {RELEASE one}
! 1577: } {1 {foreign key constraint failed}}
! 1578: do_test e_fkey-37.6 {
! 1579: execsql {ROLLBACK TO one ; RELEASE one}
! 1580: } {}
! 1581:
! 1582: #-------------------------------------------------------------------------
! 1583: # Test that if a COMMIT operation fails due to deferred foreign key
! 1584: # constraints, any nested savepoints remain open.
! 1585: #
! 1586: # EVIDENCE-OF: R-37736-42616 If a COMMIT statement (or the RELEASE of a
! 1587: # transaction SAVEPOINT) fails because the database is currently in a
! 1588: # state that violates a deferred foreign key constraint and there are
! 1589: # currently nested savepoints, the nested savepoints remain open.
! 1590: #
! 1591: do_test e_fkey-38.1 {
! 1592: execsql {
! 1593: DELETE FROM t1 WHERE a>3;
! 1594: SELECT * FROM t1;
! 1595: }
! 1596: } {1 1 2 2 3 3}
! 1597: do_test e_fkey-38.2 {
! 1598: execsql {
! 1599: BEGIN;
! 1600: INSERT INTO t1 VALUES(4, 4);
! 1601: SAVEPOINT one;
! 1602: INSERT INTO t1 VALUES(5, 6);
! 1603: SELECT * FROM t1;
! 1604: }
! 1605: } {1 1 2 2 3 3 4 4 5 6}
! 1606: do_test e_fkey-38.3 {
! 1607: catchsql COMMIT
! 1608: } {1 {foreign key constraint failed}}
! 1609: do_test e_fkey-38.4 {
! 1610: execsql {
! 1611: ROLLBACK TO one;
! 1612: COMMIT;
! 1613: SELECT * FROM t1;
! 1614: }
! 1615: } {1 1 2 2 3 3 4 4}
! 1616:
! 1617: do_test e_fkey-38.5 {
! 1618: execsql {
! 1619: SAVEPOINT a;
! 1620: INSERT INTO t1 VALUES(5, 5);
! 1621: SAVEPOINT b;
! 1622: INSERT INTO t1 VALUES(6, 7);
! 1623: SAVEPOINT c;
! 1624: INSERT INTO t1 VALUES(7, 8);
! 1625: }
! 1626: } {}
! 1627: do_test e_fkey-38.6 {
! 1628: catchsql {RELEASE a}
! 1629: } {1 {foreign key constraint failed}}
! 1630: do_test e_fkey-38.7 {
! 1631: execsql {ROLLBACK TO c}
! 1632: catchsql {RELEASE a}
! 1633: } {1 {foreign key constraint failed}}
! 1634: do_test e_fkey-38.8 {
! 1635: execsql {
! 1636: ROLLBACK TO b;
! 1637: RELEASE a;
! 1638: SELECT * FROM t1;
! 1639: }
! 1640: } {1 1 2 2 3 3 4 4 5 5}
! 1641:
! 1642: ###########################################################################
! 1643: ### SECTION 4.3: ON DELETE and ON UPDATE Actions
! 1644: ###########################################################################
! 1645:
! 1646: #-------------------------------------------------------------------------
! 1647: # Test that configured ON DELETE and ON UPDATE actions take place when
! 1648: # deleting or modifying rows of the parent table, respectively.
! 1649: #
! 1650: # EVIDENCE-OF: R-48270-44282 Foreign key ON DELETE and ON UPDATE clauses
! 1651: # are used to configure actions that take place when deleting rows from
! 1652: # the parent table (ON DELETE), or modifying the parent key values of
! 1653: # existing rows (ON UPDATE).
! 1654: #
! 1655: # Test that a single FK constraint may have different actions configured
! 1656: # for ON DELETE and ON UPDATE.
! 1657: #
! 1658: # EVIDENCE-OF: R-48124-63225 A single foreign key constraint may have
! 1659: # different actions configured for ON DELETE and ON UPDATE.
! 1660: #
! 1661: do_test e_fkey-39.1 {
! 1662: execsql {
! 1663: CREATE TABLE p(a, b PRIMARY KEY, c);
! 1664: CREATE TABLE c1(d, e, f DEFAULT 'k0' REFERENCES p
! 1665: ON UPDATE SET DEFAULT
! 1666: ON DELETE SET NULL
! 1667: );
! 1668:
! 1669: INSERT INTO p VALUES(0, 'k0', '');
! 1670: INSERT INTO p VALUES(1, 'k1', 'I');
! 1671: INSERT INTO p VALUES(2, 'k2', 'II');
! 1672: INSERT INTO p VALUES(3, 'k3', 'III');
! 1673:
! 1674: INSERT INTO c1 VALUES(1, 'xx', 'k1');
! 1675: INSERT INTO c1 VALUES(2, 'xx', 'k2');
! 1676: INSERT INTO c1 VALUES(3, 'xx', 'k3');
! 1677: }
! 1678: } {}
! 1679: do_test e_fkey-39.2 {
! 1680: execsql {
! 1681: UPDATE p SET b = 'k4' WHERE a = 1;
! 1682: SELECT * FROM c1;
! 1683: }
! 1684: } {1 xx k0 2 xx k2 3 xx k3}
! 1685: do_test e_fkey-39.3 {
! 1686: execsql {
! 1687: DELETE FROM p WHERE a = 2;
! 1688: SELECT * FROM c1;
! 1689: }
! 1690: } {1 xx k0 2 xx {} 3 xx k3}
! 1691: do_test e_fkey-39.4 {
! 1692: execsql {
! 1693: CREATE UNIQUE INDEX pi ON p(c);
! 1694: REPLACE INTO p VALUES(5, 'k5', 'III');
! 1695: SELECT * FROM c1;
! 1696: }
! 1697: } {1 xx k0 2 xx {} 3 xx {}}
! 1698:
! 1699: #-------------------------------------------------------------------------
! 1700: # Each foreign key in the system has an ON UPDATE and ON DELETE action,
! 1701: # either "NO ACTION", "RESTRICT", "SET NULL", "SET DEFAULT" or "CASCADE".
! 1702: #
! 1703: # EVIDENCE-OF: R-33326-45252 The ON DELETE and ON UPDATE action
! 1704: # associated with each foreign key in an SQLite database is one of "NO
! 1705: # ACTION", "RESTRICT", "SET NULL", "SET DEFAULT" or "CASCADE".
! 1706: #
! 1707: # If none is specified explicitly, "NO ACTION" is the default.
! 1708: #
! 1709: # EVIDENCE-OF: R-19803-45884 If an action is not explicitly specified,
! 1710: # it defaults to "NO ACTION".
! 1711: #
! 1712: drop_all_tables
! 1713: do_test e_fkey-40.1 {
! 1714: execsql {
! 1715: CREATE TABLE parent(x PRIMARY KEY, y);
! 1716: CREATE TABLE child1(a,
! 1717: b REFERENCES parent ON UPDATE NO ACTION ON DELETE RESTRICT
! 1718: );
! 1719: CREATE TABLE child2(a,
! 1720: b REFERENCES parent ON UPDATE RESTRICT ON DELETE SET NULL
! 1721: );
! 1722: CREATE TABLE child3(a,
! 1723: b REFERENCES parent ON UPDATE SET NULL ON DELETE SET DEFAULT
! 1724: );
! 1725: CREATE TABLE child4(a,
! 1726: b REFERENCES parent ON UPDATE SET DEFAULT ON DELETE CASCADE
! 1727: );
! 1728:
! 1729: -- Create some foreign keys that use the default action - "NO ACTION"
! 1730: CREATE TABLE child5(a, b REFERENCES parent ON UPDATE CASCADE);
! 1731: CREATE TABLE child6(a, b REFERENCES parent ON DELETE RESTRICT);
! 1732: CREATE TABLE child7(a, b REFERENCES parent ON DELETE NO ACTION);
! 1733: CREATE TABLE child8(a, b REFERENCES parent ON UPDATE NO ACTION);
! 1734: }
! 1735: } {}
! 1736:
! 1737: foreach {tn zTab lRes} {
! 1738: 2 child1 {0 0 parent b {} {NO ACTION} RESTRICT NONE}
! 1739: 3 child2 {0 0 parent b {} RESTRICT {SET NULL} NONE}
! 1740: 4 child3 {0 0 parent b {} {SET NULL} {SET DEFAULT} NONE}
! 1741: 5 child4 {0 0 parent b {} {SET DEFAULT} CASCADE NONE}
! 1742: 6 child5 {0 0 parent b {} CASCADE {NO ACTION} NONE}
! 1743: 7 child6 {0 0 parent b {} {NO ACTION} RESTRICT NONE}
! 1744: 8 child7 {0 0 parent b {} {NO ACTION} {NO ACTION} NONE}
! 1745: 9 child8 {0 0 parent b {} {NO ACTION} {NO ACTION} NONE}
! 1746: } {
! 1747: do_test e_fkey-40.$tn { execsql "PRAGMA foreign_key_list($zTab)" } $lRes
! 1748: }
! 1749:
! 1750: #-------------------------------------------------------------------------
! 1751: # Test that "NO ACTION" means that nothing happens to a child row when
! 1752: # it's parent row is updated or deleted.
! 1753: #
! 1754: # EVIDENCE-OF: R-19971-54976 Configuring "NO ACTION" means just that:
! 1755: # when a parent key is modified or deleted from the database, no special
! 1756: # action is taken.
! 1757: #
! 1758: drop_all_tables
! 1759: do_test e_fkey-41.1 {
! 1760: execsql {
! 1761: CREATE TABLE parent(p1, p2, PRIMARY KEY(p1, p2));
! 1762: CREATE TABLE child(c1, c2,
! 1763: FOREIGN KEY(c1, c2) REFERENCES parent
! 1764: ON UPDATE NO ACTION
! 1765: ON DELETE NO ACTION
! 1766: DEFERRABLE INITIALLY DEFERRED
! 1767: );
! 1768: INSERT INTO parent VALUES('j', 'k');
! 1769: INSERT INTO parent VALUES('l', 'm');
! 1770: INSERT INTO child VALUES('j', 'k');
! 1771: INSERT INTO child VALUES('l', 'm');
! 1772: }
! 1773: } {}
! 1774: do_test e_fkey-41.2 {
! 1775: execsql {
! 1776: BEGIN;
! 1777: UPDATE parent SET p1='k' WHERE p1='j';
! 1778: DELETE FROM parent WHERE p1='l';
! 1779: SELECT * FROM child;
! 1780: }
! 1781: } {j k l m}
! 1782: do_test e_fkey-41.3 {
! 1783: catchsql COMMIT
! 1784: } {1 {foreign key constraint failed}}
! 1785: do_test e_fkey-41.4 {
! 1786: execsql ROLLBACK
! 1787: } {}
! 1788:
! 1789: #-------------------------------------------------------------------------
! 1790: # Test that "RESTRICT" means the application is prohibited from deleting
! 1791: # or updating a parent table row when there exists one or more child keys
! 1792: # mapped to it.
! 1793: #
! 1794: # EVIDENCE-OF: R-04272-38653 The "RESTRICT" action means that the
! 1795: # application is prohibited from deleting (for ON DELETE RESTRICT) or
! 1796: # modifying (for ON UPDATE RESTRICT) a parent key when there exists one
! 1797: # or more child keys mapped to it.
! 1798: #
! 1799: drop_all_tables
! 1800: do_test e_fkey-41.1 {
! 1801: execsql {
! 1802: CREATE TABLE parent(p1, p2);
! 1803: CREATE UNIQUE INDEX parent_i ON parent(p1, p2);
! 1804: CREATE TABLE child1(c1, c2,
! 1805: FOREIGN KEY(c2, c1) REFERENCES parent(p1, p2) ON DELETE RESTRICT
! 1806: );
! 1807: CREATE TABLE child2(c1, c2,
! 1808: FOREIGN KEY(c2, c1) REFERENCES parent(p1, p2) ON UPDATE RESTRICT
! 1809: );
! 1810: }
! 1811: } {}
! 1812: do_test e_fkey-41.2 {
! 1813: execsql {
! 1814: INSERT INTO parent VALUES('a', 'b');
! 1815: INSERT INTO parent VALUES('c', 'd');
! 1816: INSERT INTO child1 VALUES('b', 'a');
! 1817: INSERT INTO child2 VALUES('d', 'c');
! 1818: }
! 1819: } {}
! 1820: do_test e_fkey-41.3 {
! 1821: catchsql { DELETE FROM parent WHERE p1 = 'a' }
! 1822: } {1 {foreign key constraint failed}}
! 1823: do_test e_fkey-41.4 {
! 1824: catchsql { UPDATE parent SET p2 = 'e' WHERE p1 = 'c' }
! 1825: } {1 {foreign key constraint failed}}
! 1826:
! 1827: #-------------------------------------------------------------------------
! 1828: # Test that RESTRICT is slightly different from NO ACTION for IMMEDIATE
! 1829: # constraints, in that it is enforced immediately, not at the end of the
! 1830: # statement.
! 1831: #
! 1832: # EVIDENCE-OF: R-37997-42187 The difference between the effect of a
! 1833: # RESTRICT action and normal foreign key constraint enforcement is that
! 1834: # the RESTRICT action processing happens as soon as the field is updated
! 1835: # - not at the end of the current statement as it would with an
! 1836: # immediate constraint, or at the end of the current transaction as it
! 1837: # would with a deferred constraint.
! 1838: #
! 1839: drop_all_tables
! 1840: do_test e_fkey-42.1 {
! 1841: execsql {
! 1842: CREATE TABLE parent(x PRIMARY KEY);
! 1843: CREATE TABLE child1(c REFERENCES parent ON UPDATE RESTRICT);
! 1844: CREATE TABLE child2(c REFERENCES parent ON UPDATE NO ACTION);
! 1845:
! 1846: INSERT INTO parent VALUES('key1');
! 1847: INSERT INTO parent VALUES('key2');
! 1848: INSERT INTO child1 VALUES('key1');
! 1849: INSERT INTO child2 VALUES('key2');
! 1850:
! 1851: CREATE TRIGGER parent_t AFTER UPDATE ON parent BEGIN
! 1852: UPDATE child1 set c = new.x WHERE c = old.x;
! 1853: UPDATE child2 set c = new.x WHERE c = old.x;
! 1854: END;
! 1855: }
! 1856: } {}
! 1857: do_test e_fkey-42.2 {
! 1858: catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' }
! 1859: } {1 {foreign key constraint failed}}
! 1860: do_test e_fkey-42.3 {
! 1861: execsql {
! 1862: UPDATE parent SET x = 'key two' WHERE x = 'key2';
! 1863: SELECT * FROM child2;
! 1864: }
! 1865: } {{key two}}
! 1866:
! 1867: drop_all_tables
! 1868: do_test e_fkey-42.4 {
! 1869: execsql {
! 1870: CREATE TABLE parent(x PRIMARY KEY);
! 1871: CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT);
! 1872: CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION);
! 1873:
! 1874: INSERT INTO parent VALUES('key1');
! 1875: INSERT INTO parent VALUES('key2');
! 1876: INSERT INTO child1 VALUES('key1');
! 1877: INSERT INTO child2 VALUES('key2');
! 1878:
! 1879: CREATE TRIGGER parent_t AFTER DELETE ON parent BEGIN
! 1880: UPDATE child1 SET c = NULL WHERE c = old.x;
! 1881: UPDATE child2 SET c = NULL WHERE c = old.x;
! 1882: END;
! 1883: }
! 1884: } {}
! 1885: do_test e_fkey-42.5 {
! 1886: catchsql { DELETE FROM parent WHERE x = 'key1' }
! 1887: } {1 {foreign key constraint failed}}
! 1888: do_test e_fkey-42.6 {
! 1889: execsql {
! 1890: DELETE FROM parent WHERE x = 'key2';
! 1891: SELECT * FROM child2;
! 1892: }
! 1893: } {{}}
! 1894:
! 1895: drop_all_tables
! 1896: do_test e_fkey-42.7 {
! 1897: execsql {
! 1898: CREATE TABLE parent(x PRIMARY KEY);
! 1899: CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT);
! 1900: CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION);
! 1901:
! 1902: INSERT INTO parent VALUES('key1');
! 1903: INSERT INTO parent VALUES('key2');
! 1904: INSERT INTO child1 VALUES('key1');
! 1905: INSERT INTO child2 VALUES('key2');
! 1906: }
! 1907: } {}
! 1908: do_test e_fkey-42.8 {
! 1909: catchsql { REPLACE INTO parent VALUES('key1') }
! 1910: } {1 {foreign key constraint failed}}
! 1911: do_test e_fkey-42.9 {
! 1912: execsql {
! 1913: REPLACE INTO parent VALUES('key2');
! 1914: SELECT * FROM child2;
! 1915: }
! 1916: } {key2}
! 1917:
! 1918: #-------------------------------------------------------------------------
! 1919: # Test that RESTRICT is enforced immediately, even for a DEFERRED constraint.
! 1920: #
! 1921: # EVIDENCE-OF: R-24179-60523 Even if the foreign key constraint it is
! 1922: # attached to is deferred, configuring a RESTRICT action causes SQLite
! 1923: # to return an error immediately if a parent key with dependent child
! 1924: # keys is deleted or modified.
! 1925: #
! 1926: drop_all_tables
! 1927: do_test e_fkey-43.1 {
! 1928: execsql {
! 1929: CREATE TABLE parent(x PRIMARY KEY);
! 1930: CREATE TABLE child1(c REFERENCES parent ON UPDATE RESTRICT
! 1931: DEFERRABLE INITIALLY DEFERRED
! 1932: );
! 1933: CREATE TABLE child2(c REFERENCES parent ON UPDATE NO ACTION
! 1934: DEFERRABLE INITIALLY DEFERRED
! 1935: );
! 1936:
! 1937: INSERT INTO parent VALUES('key1');
! 1938: INSERT INTO parent VALUES('key2');
! 1939: INSERT INTO child1 VALUES('key1');
! 1940: INSERT INTO child2 VALUES('key2');
! 1941: BEGIN;
! 1942: }
! 1943: } {}
! 1944: do_test e_fkey-43.2 {
! 1945: catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' }
! 1946: } {1 {foreign key constraint failed}}
! 1947: do_test e_fkey-43.3 {
! 1948: execsql { UPDATE parent SET x = 'key two' WHERE x = 'key2' }
! 1949: } {}
! 1950: do_test e_fkey-43.4 {
! 1951: catchsql COMMIT
! 1952: } {1 {foreign key constraint failed}}
! 1953: do_test e_fkey-43.5 {
! 1954: execsql {
! 1955: UPDATE child2 SET c = 'key two';
! 1956: COMMIT;
! 1957: }
! 1958: } {}
! 1959:
! 1960: drop_all_tables
! 1961: do_test e_fkey-43.6 {
! 1962: execsql {
! 1963: CREATE TABLE parent(x PRIMARY KEY);
! 1964: CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT
! 1965: DEFERRABLE INITIALLY DEFERRED
! 1966: );
! 1967: CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION
! 1968: DEFERRABLE INITIALLY DEFERRED
! 1969: );
! 1970:
! 1971: INSERT INTO parent VALUES('key1');
! 1972: INSERT INTO parent VALUES('key2');
! 1973: INSERT INTO child1 VALUES('key1');
! 1974: INSERT INTO child2 VALUES('key2');
! 1975: BEGIN;
! 1976: }
! 1977: } {}
! 1978: do_test e_fkey-43.7 {
! 1979: catchsql { DELETE FROM parent WHERE x = 'key1' }
! 1980: } {1 {foreign key constraint failed}}
! 1981: do_test e_fkey-43.8 {
! 1982: execsql { DELETE FROM parent WHERE x = 'key2' }
! 1983: } {}
! 1984: do_test e_fkey-43.9 {
! 1985: catchsql COMMIT
! 1986: } {1 {foreign key constraint failed}}
! 1987: do_test e_fkey-43.10 {
! 1988: execsql {
! 1989: UPDATE child2 SET c = NULL;
! 1990: COMMIT;
! 1991: }
! 1992: } {}
! 1993:
! 1994: #-------------------------------------------------------------------------
! 1995: # Test SET NULL actions.
! 1996: #
! 1997: # EVIDENCE-OF: R-03353-05327 If the configured action is "SET NULL",
! 1998: # then when a parent key is deleted (for ON DELETE SET NULL) or modified
! 1999: # (for ON UPDATE SET NULL), the child key columns of all rows in the
! 2000: # child table that mapped to the parent key are set to contain SQL NULL
! 2001: # values.
! 2002: #
! 2003: drop_all_tables
! 2004: do_test e_fkey-44.1 {
! 2005: execsql {
! 2006: CREATE TABLE pA(x PRIMARY KEY);
! 2007: CREATE TABLE cA(c REFERENCES pA ON DELETE SET NULL);
! 2008: CREATE TABLE cB(c REFERENCES pA ON UPDATE SET NULL);
! 2009:
! 2010: INSERT INTO pA VALUES(X'ABCD');
! 2011: INSERT INTO pA VALUES(X'1234');
! 2012: INSERT INTO cA VALUES(X'ABCD');
! 2013: INSERT INTO cB VALUES(X'1234');
! 2014: }
! 2015: } {}
! 2016: do_test e_fkey-44.2 {
! 2017: execsql {
! 2018: DELETE FROM pA WHERE rowid = 1;
! 2019: SELECT quote(x) FROM pA;
! 2020: }
! 2021: } {X'1234'}
! 2022: do_test e_fkey-44.3 {
! 2023: execsql {
! 2024: SELECT quote(c) FROM cA;
! 2025: }
! 2026: } {NULL}
! 2027: do_test e_fkey-44.4 {
! 2028: execsql {
! 2029: UPDATE pA SET x = X'8765' WHERE rowid = 2;
! 2030: SELECT quote(x) FROM pA;
! 2031: }
! 2032: } {X'8765'}
! 2033: do_test e_fkey-44.5 {
! 2034: execsql { SELECT quote(c) FROM cB }
! 2035: } {NULL}
! 2036:
! 2037: #-------------------------------------------------------------------------
! 2038: # Test SET DEFAULT actions.
! 2039: #
! 2040: # EVIDENCE-OF: R-43054-54832 The "SET DEFAULT" actions are similar to
! 2041: # "SET NULL", except that each of the child key columns is set to
! 2042: # contain the columns default value instead of NULL.
! 2043: #
! 2044: drop_all_tables
! 2045: do_test e_fkey-45.1 {
! 2046: execsql {
! 2047: CREATE TABLE pA(x PRIMARY KEY);
! 2048: CREATE TABLE cA(c DEFAULT X'0000' REFERENCES pA ON DELETE SET DEFAULT);
! 2049: CREATE TABLE cB(c DEFAULT X'9999' REFERENCES pA ON UPDATE SET DEFAULT);
! 2050:
! 2051: INSERT INTO pA(rowid, x) VALUES(1, X'0000');
! 2052: INSERT INTO pA(rowid, x) VALUES(2, X'9999');
! 2053: INSERT INTO pA(rowid, x) VALUES(3, X'ABCD');
! 2054: INSERT INTO pA(rowid, x) VALUES(4, X'1234');
! 2055:
! 2056: INSERT INTO cA VALUES(X'ABCD');
! 2057: INSERT INTO cB VALUES(X'1234');
! 2058: }
! 2059: } {}
! 2060: do_test e_fkey-45.2 {
! 2061: execsql {
! 2062: DELETE FROM pA WHERE rowid = 3;
! 2063: SELECT quote(x) FROM pA;
! 2064: }
! 2065: } {X'0000' X'9999' X'1234'}
! 2066: do_test e_fkey-45.3 {
! 2067: execsql { SELECT quote(c) FROM cA }
! 2068: } {X'0000'}
! 2069: do_test e_fkey-45.4 {
! 2070: execsql {
! 2071: UPDATE pA SET x = X'8765' WHERE rowid = 4;
! 2072: SELECT quote(x) FROM pA;
! 2073: }
! 2074: } {X'0000' X'9999' X'8765'}
! 2075: do_test e_fkey-45.5 {
! 2076: execsql { SELECT quote(c) FROM cB }
! 2077: } {X'9999'}
! 2078:
! 2079: #-------------------------------------------------------------------------
! 2080: # Test ON DELETE CASCADE actions.
! 2081: #
! 2082: # EVIDENCE-OF: R-61376-57267 A "CASCADE" action propagates the delete or
! 2083: # update operation on the parent key to each dependent child key.
! 2084: #
! 2085: # EVIDENCE-OF: R-61809-62207 For an "ON DELETE CASCADE" action, this
! 2086: # means that each row in the child table that was associated with the
! 2087: # deleted parent row is also deleted.
! 2088: #
! 2089: drop_all_tables
! 2090: do_test e_fkey-46.1 {
! 2091: execsql {
! 2092: CREATE TABLE p1(a, b UNIQUE);
! 2093: CREATE TABLE c1(c REFERENCES p1(b) ON DELETE CASCADE, d);
! 2094: INSERT INTO p1 VALUES(NULL, NULL);
! 2095: INSERT INTO p1 VALUES(4, 4);
! 2096: INSERT INTO p1 VALUES(5, 5);
! 2097: INSERT INTO c1 VALUES(NULL, NULL);
! 2098: INSERT INTO c1 VALUES(4, 4);
! 2099: INSERT INTO c1 VALUES(5, 5);
! 2100: SELECT count(*) FROM c1;
! 2101: }
! 2102: } {3}
! 2103: do_test e_fkey-46.2 {
! 2104: execsql {
! 2105: DELETE FROM p1 WHERE a = 4;
! 2106: SELECT d, c FROM c1;
! 2107: }
! 2108: } {{} {} 5 5}
! 2109: do_test e_fkey-46.3 {
! 2110: execsql {
! 2111: DELETE FROM p1;
! 2112: SELECT d, c FROM c1;
! 2113: }
! 2114: } {{} {}}
! 2115: do_test e_fkey-46.4 {
! 2116: execsql { SELECT * FROM p1 }
! 2117: } {}
! 2118:
! 2119:
! 2120: #-------------------------------------------------------------------------
! 2121: # Test ON UPDATE CASCADE actions.
! 2122: #
! 2123: # EVIDENCE-OF: R-13877-64542 For an "ON UPDATE CASCADE" action, it means
! 2124: # that the values stored in each dependent child key are modified to
! 2125: # match the new parent key values.
! 2126: #
! 2127: # EVIDENCE-OF: R-61376-57267 A "CASCADE" action propagates the delete or
! 2128: # update operation on the parent key to each dependent child key.
! 2129: #
! 2130: drop_all_tables
! 2131: do_test e_fkey-47.1 {
! 2132: execsql {
! 2133: CREATE TABLE p1(a, b UNIQUE);
! 2134: CREATE TABLE c1(c REFERENCES p1(b) ON UPDATE CASCADE, d);
! 2135: INSERT INTO p1 VALUES(NULL, NULL);
! 2136: INSERT INTO p1 VALUES(4, 4);
! 2137: INSERT INTO p1 VALUES(5, 5);
! 2138: INSERT INTO c1 VALUES(NULL, NULL);
! 2139: INSERT INTO c1 VALUES(4, 4);
! 2140: INSERT INTO c1 VALUES(5, 5);
! 2141: SELECT count(*) FROM c1;
! 2142: }
! 2143: } {3}
! 2144: do_test e_fkey-47.2 {
! 2145: execsql {
! 2146: UPDATE p1 SET b = 10 WHERE b = 5;
! 2147: SELECT d, c FROM c1;
! 2148: }
! 2149: } {{} {} 4 4 5 10}
! 2150: do_test e_fkey-47.3 {
! 2151: execsql {
! 2152: UPDATE p1 SET b = 11 WHERE b = 4;
! 2153: SELECT d, c FROM c1;
! 2154: }
! 2155: } {{} {} 4 11 5 10}
! 2156: do_test e_fkey-47.4 {
! 2157: execsql {
! 2158: UPDATE p1 SET b = 6 WHERE b IS NULL;
! 2159: SELECT d, c FROM c1;
! 2160: }
! 2161: } {{} {} 4 11 5 10}
! 2162: do_test e_fkey-46.5 {
! 2163: execsql { SELECT * FROM p1 }
! 2164: } {{} 6 4 11 5 10}
! 2165:
! 2166: #-------------------------------------------------------------------------
! 2167: # EVIDENCE-OF: R-65058-57158
! 2168: #
! 2169: # Test an example from the "ON DELETE and ON UPDATE Actions" section
! 2170: # of foreignkeys.html.
! 2171: #
! 2172: drop_all_tables
! 2173: do_test e_fkey-48.1 {
! 2174: execsql {
! 2175: CREATE TABLE artist(
! 2176: artistid INTEGER PRIMARY KEY,
! 2177: artistname TEXT
! 2178: );
! 2179: CREATE TABLE track(
! 2180: trackid INTEGER,
! 2181: trackname TEXT,
! 2182: trackartist INTEGER REFERENCES artist(artistid) ON UPDATE CASCADE
! 2183: );
! 2184:
! 2185: INSERT INTO artist VALUES(1, 'Dean Martin');
! 2186: INSERT INTO artist VALUES(2, 'Frank Sinatra');
! 2187: INSERT INTO track VALUES(11, 'That''s Amore', 1);
! 2188: INSERT INTO track VALUES(12, 'Christmas Blues', 1);
! 2189: INSERT INTO track VALUES(13, 'My Way', 2);
! 2190: }
! 2191: } {}
! 2192: do_test e_fkey-48.2 {
! 2193: execsql {
! 2194: UPDATE artist SET artistid = 100 WHERE artistname = 'Dean Martin';
! 2195: }
! 2196: } {}
! 2197: do_test e_fkey-48.3 {
! 2198: execsql { SELECT * FROM artist }
! 2199: } {2 {Frank Sinatra} 100 {Dean Martin}}
! 2200: do_test e_fkey-48.4 {
! 2201: execsql { SELECT * FROM track }
! 2202: } {11 {That's Amore} 100 12 {Christmas Blues} 100 13 {My Way} 2}
! 2203:
! 2204:
! 2205: #-------------------------------------------------------------------------
! 2206: # Verify that adding an FK action does not absolve the user of the
! 2207: # requirement not to violate the foreign key constraint.
! 2208: #
! 2209: # EVIDENCE-OF: R-53968-51642 Configuring an ON UPDATE or ON DELETE
! 2210: # action does not mean that the foreign key constraint does not need to
! 2211: # be satisfied.
! 2212: #
! 2213: drop_all_tables
! 2214: do_test e_fkey-49.1 {
! 2215: execsql {
! 2216: CREATE TABLE parent(a COLLATE nocase, b, c, PRIMARY KEY(c, a));
! 2217: CREATE TABLE child(d DEFAULT 'a', e, f DEFAULT 'c',
! 2218: FOREIGN KEY(f, d) REFERENCES parent ON UPDATE SET DEFAULT
! 2219: );
! 2220:
! 2221: INSERT INTO parent VALUES('A', 'b', 'c');
! 2222: INSERT INTO parent VALUES('ONE', 'two', 'three');
! 2223: INSERT INTO child VALUES('one', 'two', 'three');
! 2224: }
! 2225: } {}
! 2226: do_test e_fkey-49.2 {
! 2227: execsql {
! 2228: BEGIN;
! 2229: UPDATE parent SET a = '' WHERE a = 'oNe';
! 2230: SELECT * FROM child;
! 2231: }
! 2232: } {a two c}
! 2233: do_test e_fkey-49.3 {
! 2234: execsql {
! 2235: ROLLBACK;
! 2236: DELETE FROM parent WHERE a = 'A';
! 2237: SELECT * FROM parent;
! 2238: }
! 2239: } {ONE two three}
! 2240: do_test e_fkey-49.4 {
! 2241: catchsql { UPDATE parent SET a = '' WHERE a = 'oNe' }
! 2242: } {1 {foreign key constraint failed}}
! 2243:
! 2244:
! 2245: #-------------------------------------------------------------------------
! 2246: # EVIDENCE-OF: R-11856-19836
! 2247: #
! 2248: # Test an example from the "ON DELETE and ON UPDATE Actions" section
! 2249: # of foreignkeys.html. This example shows that adding an "ON DELETE DEFAULT"
! 2250: # clause does not abrogate the need to satisfy the foreign key constraint
! 2251: # (R-28220-46694).
! 2252: #
! 2253: # EVIDENCE-OF: R-28220-46694 For example, if an "ON DELETE SET DEFAULT"
! 2254: # action is configured, but there is no row in the parent table that
! 2255: # corresponds to the default values of the child key columns, deleting a
! 2256: # parent key while dependent child keys exist still causes a foreign key
! 2257: # violation.
! 2258: #
! 2259: drop_all_tables
! 2260: do_test e_fkey-50.1 {
! 2261: execsql {
! 2262: CREATE TABLE artist(
! 2263: artistid INTEGER PRIMARY KEY,
! 2264: artistname TEXT
! 2265: );
! 2266: CREATE TABLE track(
! 2267: trackid INTEGER,
! 2268: trackname TEXT,
! 2269: trackartist INTEGER DEFAULT 0 REFERENCES artist(artistid) ON DELETE SET DEFAULT
! 2270: );
! 2271: INSERT INTO artist VALUES(3, 'Sammy Davis Jr.');
! 2272: INSERT INTO track VALUES(14, 'Mr. Bojangles', 3);
! 2273: }
! 2274: } {}
! 2275: do_test e_fkey-50.2 {
! 2276: catchsql { DELETE FROM artist WHERE artistname = 'Sammy Davis Jr.' }
! 2277: } {1 {foreign key constraint failed}}
! 2278: do_test e_fkey-50.3 {
! 2279: execsql {
! 2280: INSERT INTO artist VALUES(0, 'Unknown Artist');
! 2281: DELETE FROM artist WHERE artistname = 'Sammy Davis Jr.';
! 2282: }
! 2283: } {}
! 2284: do_test e_fkey-50.4 {
! 2285: execsql { SELECT * FROM artist }
! 2286: } {0 {Unknown Artist}}
! 2287: do_test e_fkey-50.5 {
! 2288: execsql { SELECT * FROM track }
! 2289: } {14 {Mr. Bojangles} 0}
! 2290:
! 2291: #-------------------------------------------------------------------------
! 2292: # EVIDENCE-OF: R-09564-22170
! 2293: #
! 2294: # Check that the order of steps in an UPDATE or DELETE on a parent
! 2295: # table is as follows:
! 2296: #
! 2297: # 1. Execute applicable BEFORE trigger programs,
! 2298: # 2. Check local (non foreign key) constraints,
! 2299: # 3. Update or delete the row in the parent table,
! 2300: # 4. Perform any required foreign key actions,
! 2301: # 5. Execute applicable AFTER trigger programs.
! 2302: #
! 2303: drop_all_tables
! 2304: do_test e_fkey-51.1 {
! 2305: proc maxparent {args} { db one {SELECT max(x) FROM parent} }
! 2306: db func maxparent maxparent
! 2307:
! 2308: execsql {
! 2309: CREATE TABLE parent(x PRIMARY KEY);
! 2310:
! 2311: CREATE TRIGGER bu BEFORE UPDATE ON parent BEGIN
! 2312: INSERT INTO parent VALUES(new.x-old.x);
! 2313: END;
! 2314: CREATE TABLE child(
! 2315: a DEFAULT (maxparent()) REFERENCES parent ON UPDATE SET DEFAULT
! 2316: );
! 2317: CREATE TRIGGER au AFTER UPDATE ON parent BEGIN
! 2318: INSERT INTO parent VALUES(new.x+old.x);
! 2319: END;
! 2320:
! 2321: INSERT INTO parent VALUES(1);
! 2322: INSERT INTO child VALUES(1);
! 2323: }
! 2324: } {}
! 2325: do_test e_fkey-51.2 {
! 2326: execsql {
! 2327: UPDATE parent SET x = 22;
! 2328: SELECT * FROM parent UNION ALL SELECT 'xxx' UNION ALL SELECT a FROM child;
! 2329: }
! 2330: } {22 21 23 xxx 22}
! 2331: do_test e_fkey-51.3 {
! 2332: execsql {
! 2333: DELETE FROM child;
! 2334: DELETE FROM parent;
! 2335: INSERT INTO parent VALUES(-1);
! 2336: INSERT INTO child VALUES(-1);
! 2337: UPDATE parent SET x = 22;
! 2338: SELECT * FROM parent UNION ALL SELECT 'xxx' UNION ALL SELECT a FROM child;
! 2339: }
! 2340: } {22 23 21 xxx 23}
! 2341:
! 2342:
! 2343: #-------------------------------------------------------------------------
! 2344: # Verify that ON UPDATE actions only actually take place if the parent key
! 2345: # is set to a new value that is distinct from the old value. The default
! 2346: # collation sequence and affinity are used to determine if the new value
! 2347: # is 'distinct' from the old or not.
! 2348: #
! 2349: # EVIDENCE-OF: R-27383-10246 An ON UPDATE action is only taken if the
! 2350: # values of the parent key are modified so that the new parent key
! 2351: # values are not equal to the old.
! 2352: #
! 2353: drop_all_tables
! 2354: do_test e_fkey-52.1 {
! 2355: execsql {
! 2356: CREATE TABLE zeus(a INTEGER COLLATE NOCASE, b, PRIMARY KEY(a, b));
! 2357: CREATE TABLE apollo(c, d,
! 2358: FOREIGN KEY(c, d) REFERENCES zeus ON UPDATE CASCADE
! 2359: );
! 2360: INSERT INTO zeus VALUES('abc', 'xyz');
! 2361: INSERT INTO apollo VALUES('ABC', 'xyz');
! 2362: }
! 2363: execsql {
! 2364: UPDATE zeus SET a = 'aBc';
! 2365: SELECT * FROM apollo;
! 2366: }
! 2367: } {ABC xyz}
! 2368: do_test e_fkey-52.2 {
! 2369: execsql {
! 2370: UPDATE zeus SET a = 1, b = 1;
! 2371: SELECT * FROM apollo;
! 2372: }
! 2373: } {1 1}
! 2374: do_test e_fkey-52.3 {
! 2375: execsql {
! 2376: UPDATE zeus SET a = 1, b = 1;
! 2377: SELECT typeof(c), c, typeof(d), d FROM apollo;
! 2378: }
! 2379: } {integer 1 integer 1}
! 2380: do_test e_fkey-52.4 {
! 2381: execsql {
! 2382: UPDATE zeus SET a = '1';
! 2383: SELECT typeof(c), c, typeof(d), d FROM apollo;
! 2384: }
! 2385: } {integer 1 integer 1}
! 2386: do_test e_fkey-52.5 {
! 2387: execsql {
! 2388: UPDATE zeus SET b = '1';
! 2389: SELECT typeof(c), c, typeof(d), d FROM apollo;
! 2390: }
! 2391: } {integer 1 text 1}
! 2392: do_test e_fkey-52.6 {
! 2393: execsql {
! 2394: UPDATE zeus SET b = NULL;
! 2395: SELECT typeof(c), c, typeof(d), d FROM apollo;
! 2396: }
! 2397: } {integer 1 null {}}
! 2398:
! 2399: #-------------------------------------------------------------------------
! 2400: # EVIDENCE-OF: R-35129-58141
! 2401: #
! 2402: # Test an example from the "ON DELETE and ON UPDATE Actions" section
! 2403: # of foreignkeys.html. This example demonstrates that ON UPDATE actions
! 2404: # only take place if at least one parent key column is set to a value
! 2405: # that is distinct from its previous value.
! 2406: #
! 2407: drop_all_tables
! 2408: do_test e_fkey-53.1 {
! 2409: execsql {
! 2410: CREATE TABLE parent(x PRIMARY KEY);
! 2411: CREATE TABLE child(y REFERENCES parent ON UPDATE SET NULL);
! 2412: INSERT INTO parent VALUES('key');
! 2413: INSERT INTO child VALUES('key');
! 2414: }
! 2415: } {}
! 2416: do_test e_fkey-53.2 {
! 2417: execsql {
! 2418: UPDATE parent SET x = 'key';
! 2419: SELECT IFNULL(y, 'null') FROM child;
! 2420: }
! 2421: } {key}
! 2422: do_test e_fkey-53.3 {
! 2423: execsql {
! 2424: UPDATE parent SET x = 'key2';
! 2425: SELECT IFNULL(y, 'null') FROM child;
! 2426: }
! 2427: } {null}
! 2428:
! 2429: ###########################################################################
! 2430: ### SECTION 5: CREATE, ALTER and DROP TABLE commands
! 2431: ###########################################################################
! 2432:
! 2433: #-------------------------------------------------------------------------
! 2434: # Test that parent keys are not checked when tables are created.
! 2435: #
! 2436: # EVIDENCE-OF: R-36018-21755 The parent key definitions of foreign key
! 2437: # constraints are not checked when a table is created.
! 2438: #
! 2439: # EVIDENCE-OF: R-25384-39337 There is nothing stopping the user from
! 2440: # creating a foreign key definition that refers to a parent table that
! 2441: # does not exist, or to parent key columns that do not exist or are not
! 2442: # collectively bound by a PRIMARY KEY or UNIQUE constraint.
! 2443: #
! 2444: # Child keys are checked to ensure all component columns exist. If parent
! 2445: # key columns are explicitly specified, SQLite checks to make sure there
! 2446: # are the same number of columns in the child and parent keys. (TODO: This
! 2447: # is tested but does not correspond to any testable statement.)
! 2448: #
! 2449: # Also test that the above statements are true regardless of whether or not
! 2450: # foreign keys are enabled: "A CREATE TABLE command operates the same whether
! 2451: # or not foreign key constraints are enabled."
! 2452: #
! 2453: # EVIDENCE-OF: R-08908-23439 A CREATE TABLE command operates the same
! 2454: # whether or not foreign key constraints are enabled.
! 2455: #
! 2456: foreach {tn zCreateTbl lRes} {
! 2457: 1 "CREATE TABLE t1(a, b REFERENCES t1)" {0 {}}
! 2458: 2 "CREATE TABLE t1(a, b REFERENCES t2)" {0 {}}
! 2459: 3 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t1)" {0 {}}
! 2460: 4 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t2)" {0 {}}
! 2461: 5 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t2)" {0 {}}
! 2462: 6 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t2(n,d))" {0 {}}
! 2463: 7 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t1(a,b))" {0 {}}
! 2464:
! 2465: A "CREATE TABLE t1(a, b, FOREIGN KEY(c,b) REFERENCES t2)"
! 2466: {1 {unknown column "c" in foreign key definition}}
! 2467: B "CREATE TABLE t1(a, b, FOREIGN KEY(c,b) REFERENCES t2(d))"
! 2468: {1 {number of columns in foreign key does not match the number of columns in the referenced table}}
! 2469: } {
! 2470: do_test e_fkey-54.$tn.off {
! 2471: drop_all_tables
! 2472: execsql {PRAGMA foreign_keys = OFF}
! 2473: catchsql $zCreateTbl
! 2474: } $lRes
! 2475: do_test e_fkey-54.$tn.on {
! 2476: drop_all_tables
! 2477: execsql {PRAGMA foreign_keys = ON}
! 2478: catchsql $zCreateTbl
! 2479: } $lRes
! 2480: }
! 2481:
! 2482: #-------------------------------------------------------------------------
! 2483: # EVIDENCE-OF: R-47952-62498 It is not possible to use the "ALTER TABLE
! 2484: # ... ADD COLUMN" syntax to add a column that includes a REFERENCES
! 2485: # clause, unless the default value of the new column is NULL. Attempting
! 2486: # to do so returns an error.
! 2487: #
! 2488: proc test_efkey_6 {tn zAlter isError} {
! 2489: drop_all_tables
! 2490:
! 2491: do_test e_fkey-56.$tn.1 "
! 2492: execsql { CREATE TABLE tbl(a, b) }
! 2493: [list catchsql $zAlter]
! 2494: " [lindex {{0 {}} {1 {Cannot add a REFERENCES column with non-NULL default value}}} $isError]
! 2495:
! 2496: }
! 2497:
! 2498: test_efkey_6 1 "ALTER TABLE tbl ADD COLUMN c REFERENCES xx" 0
! 2499: test_efkey_6 2 "ALTER TABLE tbl ADD COLUMN c DEFAULT NULL REFERENCES xx" 0
! 2500: test_efkey_6 3 "ALTER TABLE tbl ADD COLUMN c DEFAULT 0 REFERENCES xx" 1
! 2501:
! 2502: #-------------------------------------------------------------------------
! 2503: # Test that ALTER TABLE adjusts REFERENCES clauses when the parent table
! 2504: # is RENAMED.
! 2505: #
! 2506: # EVIDENCE-OF: R-47080-02069 If an "ALTER TABLE ... RENAME TO" command
! 2507: # is used to rename a table that is the parent table of one or more
! 2508: # foreign key constraints, the definitions of the foreign key
! 2509: # constraints are modified to refer to the parent table by its new name
! 2510: #
! 2511: # Test that these adjustments are visible in the sqlite_master table.
! 2512: #
! 2513: # EVIDENCE-OF: R-63827-54774 The text of the child CREATE TABLE
! 2514: # statement or statements stored in the sqlite_master table are modified
! 2515: # to reflect the new parent table name.
! 2516: #
! 2517: do_test e_fkey-56.1 {
! 2518: drop_all_tables
! 2519: execsql {
! 2520: CREATE TABLE 'p 1 "parent one"'(a REFERENCES 'p 1 "parent one"', b, PRIMARY KEY(b));
! 2521:
! 2522: CREATE TABLE c1(c, d REFERENCES 'p 1 "parent one"' ON UPDATE CASCADE);
! 2523: CREATE TABLE c2(e, f, FOREIGN KEY(f) REFERENCES 'p 1 "parent one"' ON UPDATE CASCADE);
! 2524: CREATE TABLE c3(e, 'f col 2', FOREIGN KEY('f col 2') REFERENCES 'p 1 "parent one"' ON UPDATE CASCADE);
! 2525:
! 2526: INSERT INTO 'p 1 "parent one"' VALUES(1, 1);
! 2527: INSERT INTO c1 VALUES(1, 1);
! 2528: INSERT INTO c2 VALUES(1, 1);
! 2529: INSERT INTO c3 VALUES(1, 1);
! 2530:
! 2531: -- CREATE TABLE q(a, b, PRIMARY KEY(b));
! 2532: }
! 2533: } {}
! 2534: do_test e_fkey-56.2 {
! 2535: execsql { ALTER TABLE 'p 1 "parent one"' RENAME TO p }
! 2536: } {}
! 2537: do_test e_fkey-56.3 {
! 2538: execsql {
! 2539: UPDATE p SET a = 'xxx', b = 'xxx';
! 2540: SELECT * FROM p;
! 2541: SELECT * FROM c1;
! 2542: SELECT * FROM c2;
! 2543: SELECT * FROM c3;
! 2544: }
! 2545: } {xxx xxx 1 xxx 1 xxx 1 xxx}
! 2546: do_test e_fkey-56.4 {
! 2547: execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
! 2548: } [list \
! 2549: {CREATE TABLE "p"(a REFERENCES "p", b, PRIMARY KEY(b))} \
! 2550: {CREATE TABLE c1(c, d REFERENCES "p" ON UPDATE CASCADE)} \
! 2551: {CREATE TABLE c2(e, f, FOREIGN KEY(f) REFERENCES "p" ON UPDATE CASCADE)} \
! 2552: {CREATE TABLE c3(e, 'f col 2', FOREIGN KEY('f col 2') REFERENCES "p" ON UPDATE CASCADE)} \
! 2553: ]
! 2554:
! 2555: #-------------------------------------------------------------------------
! 2556: # Check that a DROP TABLE does an implicit DELETE FROM. Which does not
! 2557: # cause any triggers to fire, but does fire foreign key actions.
! 2558: #
! 2559: # EVIDENCE-OF: R-14208-23986 If foreign key constraints are enabled when
! 2560: # it is prepared, the DROP TABLE command performs an implicit DELETE to
! 2561: # remove all rows from the table before dropping it.
! 2562: #
! 2563: # EVIDENCE-OF: R-11078-03945 The implicit DELETE does not cause any SQL
! 2564: # triggers to fire, but may invoke foreign key actions or constraint
! 2565: # violations.
! 2566: #
! 2567: do_test e_fkey-57.1 {
! 2568: drop_all_tables
! 2569: execsql {
! 2570: CREATE TABLE p(a, b, PRIMARY KEY(a, b));
! 2571:
! 2572: CREATE TABLE c1(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE SET NULL);
! 2573: CREATE TABLE c2(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE SET DEFAULT);
! 2574: CREATE TABLE c3(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE CASCADE);
! 2575: CREATE TABLE c4(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE RESTRICT);
! 2576: CREATE TABLE c5(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE NO ACTION);
! 2577:
! 2578: CREATE TABLE c6(c, d,
! 2579: FOREIGN KEY(c, d) REFERENCES p ON DELETE RESTRICT
! 2580: DEFERRABLE INITIALLY DEFERRED
! 2581: );
! 2582: CREATE TABLE c7(c, d,
! 2583: FOREIGN KEY(c, d) REFERENCES p ON DELETE NO ACTION
! 2584: DEFERRABLE INITIALLY DEFERRED
! 2585: );
! 2586:
! 2587: CREATE TABLE log(msg);
! 2588: CREATE TRIGGER tt AFTER DELETE ON p BEGIN
! 2589: INSERT INTO log VALUES('delete ' || old.rowid);
! 2590: END;
! 2591: }
! 2592: } {}
! 2593:
! 2594: do_test e_fkey-57.2 {
! 2595: execsql {
! 2596: INSERT INTO p VALUES('a', 'b');
! 2597: INSERT INTO c1 VALUES('a', 'b');
! 2598: INSERT INTO c2 VALUES('a', 'b');
! 2599: INSERT INTO c3 VALUES('a', 'b');
! 2600: BEGIN;
! 2601: DROP TABLE p;
! 2602: SELECT * FROM c1;
! 2603: }
! 2604: } {{} {}}
! 2605: do_test e_fkey-57.3 {
! 2606: execsql { SELECT * FROM c2 }
! 2607: } {{} {}}
! 2608: do_test e_fkey-57.4 {
! 2609: execsql { SELECT * FROM c3 }
! 2610: } {}
! 2611: do_test e_fkey-57.5 {
! 2612: execsql { SELECT * FROM log }
! 2613: } {}
! 2614: do_test e_fkey-57.6 {
! 2615: execsql ROLLBACK
! 2616: } {}
! 2617: do_test e_fkey-57.7 {
! 2618: execsql {
! 2619: BEGIN;
! 2620: DELETE FROM p;
! 2621: SELECT * FROM log;
! 2622: ROLLBACK;
! 2623: }
! 2624: } {{delete 1}}
! 2625:
! 2626: #-------------------------------------------------------------------------
! 2627: # If an IMMEDIATE foreign key fails as a result of a DROP TABLE, the
! 2628: # DROP TABLE command fails.
! 2629: #
! 2630: # EVIDENCE-OF: R-32768-47925 If an immediate foreign key constraint is
! 2631: # violated, the DROP TABLE statement fails and the table is not dropped.
! 2632: #
! 2633: do_test e_fkey-58.1 {
! 2634: execsql {
! 2635: DELETE FROM c1;
! 2636: DELETE FROM c2;
! 2637: DELETE FROM c3;
! 2638: }
! 2639: execsql { INSERT INTO c5 VALUES('a', 'b') }
! 2640: catchsql { DROP TABLE p }
! 2641: } {1 {foreign key constraint failed}}
! 2642: do_test e_fkey-58.2 {
! 2643: execsql { SELECT * FROM p }
! 2644: } {a b}
! 2645: do_test e_fkey-58.3 {
! 2646: catchsql {
! 2647: BEGIN;
! 2648: DROP TABLE p;
! 2649: }
! 2650: } {1 {foreign key constraint failed}}
! 2651: do_test e_fkey-58.4 {
! 2652: execsql {
! 2653: SELECT * FROM p;
! 2654: SELECT * FROM c5;
! 2655: ROLLBACK;
! 2656: }
! 2657: } {a b a b}
! 2658:
! 2659: #-------------------------------------------------------------------------
! 2660: # If a DEFERRED foreign key fails as a result of a DROP TABLE, attempting
! 2661: # to commit the transaction fails unless the violation is fixed.
! 2662: #
! 2663: # EVIDENCE-OF: R-05903-08460 If a deferred foreign key constraint is
! 2664: # violated, then an error is reported when the user attempts to commit
! 2665: # the transaction if the foreign key constraint violations still exist
! 2666: # at that point.
! 2667: #
! 2668: do_test e_fkey-59.1 {
! 2669: execsql {
! 2670: DELETE FROM c1 ; DELETE FROM c2 ; DELETE FROM c3 ;
! 2671: DELETE FROM c4 ; DELETE FROM c5 ; DELETE FROM c6 ;
! 2672: DELETE FROM c7
! 2673: }
! 2674: } {}
! 2675: do_test e_fkey-59.2 {
! 2676: execsql { INSERT INTO c7 VALUES('a', 'b') }
! 2677: execsql {
! 2678: BEGIN;
! 2679: DROP TABLE p;
! 2680: }
! 2681: } {}
! 2682: do_test e_fkey-59.3 {
! 2683: catchsql COMMIT
! 2684: } {1 {foreign key constraint failed}}
! 2685: do_test e_fkey-59.4 {
! 2686: execsql { CREATE TABLE p(a, b, PRIMARY KEY(a, b)) }
! 2687: catchsql COMMIT
! 2688: } {1 {foreign key constraint failed}}
! 2689: do_test e_fkey-59.5 {
! 2690: execsql { INSERT INTO p VALUES('a', 'b') }
! 2691: execsql COMMIT
! 2692: } {}
! 2693:
! 2694: #-------------------------------------------------------------------------
! 2695: # Any "foreign key mismatch" errors encountered while running an implicit
! 2696: # "DELETE FROM tbl" are ignored.
! 2697: #
! 2698: # EVIDENCE-OF: R-57242-37005 Any "foreign key mismatch" errors
! 2699: # encountered as part of an implicit DELETE are ignored.
! 2700: #
! 2701: drop_all_tables
! 2702: do_test e_fkey-60.1 {
! 2703: execsql {
! 2704: PRAGMA foreign_keys = OFF;
! 2705:
! 2706: CREATE TABLE p(a PRIMARY KEY, b REFERENCES nosuchtable);
! 2707: CREATE TABLE c1(c, d, FOREIGN KEY(c, d) REFERENCES a);
! 2708: CREATE TABLE c2(c REFERENCES p(b), d);
! 2709: CREATE TABLE c3(c REFERENCES p ON DELETE SET NULL, d);
! 2710:
! 2711: INSERT INTO p VALUES(1, 2);
! 2712: INSERT INTO c1 VALUES(1, 2);
! 2713: INSERT INTO c2 VALUES(1, 2);
! 2714: INSERT INTO c3 VALUES(1, 2);
! 2715: }
! 2716: } {}
! 2717: do_test e_fkey-60.2 {
! 2718: execsql { PRAGMA foreign_keys = ON }
! 2719: catchsql { DELETE FROM p }
! 2720: } {1 {no such table: main.nosuchtable}}
! 2721: do_test e_fkey-60.3 {
! 2722: execsql {
! 2723: BEGIN;
! 2724: DROP TABLE p;
! 2725: SELECT * FROM c3;
! 2726: ROLLBACK;
! 2727: }
! 2728: } {{} 2}
! 2729: do_test e_fkey-60.4 {
! 2730: execsql { CREATE TABLE nosuchtable(x PRIMARY KEY) }
! 2731: catchsql { DELETE FROM p }
! 2732: } {1 {foreign key mismatch}}
! 2733: do_test e_fkey-60.5 {
! 2734: execsql { DROP TABLE c1 }
! 2735: catchsql { DELETE FROM p }
! 2736: } {1 {foreign key mismatch}}
! 2737: do_test e_fkey-60.6 {
! 2738: execsql { DROP TABLE c2 }
! 2739: execsql { DELETE FROM p }
! 2740: } {}
! 2741:
! 2742: #-------------------------------------------------------------------------
! 2743: # Test that the special behaviours of ALTER and DROP TABLE are only
! 2744: # activated when foreign keys are enabled. Special behaviours are:
! 2745: #
! 2746: # 1. ADD COLUMN not allowing a REFERENCES clause with a non-NULL
! 2747: # default value.
! 2748: # 2. Modifying foreign key definitions when a parent table is RENAMEd.
! 2749: # 3. Running an implicit DELETE FROM command as part of DROP TABLE.
! 2750: #
! 2751: # EVIDENCE-OF: R-54142-41346 The properties of the DROP TABLE and ALTER
! 2752: # TABLE commands described above only apply if foreign keys are enabled.
! 2753: #
! 2754: do_test e_fkey-61.1.1 {
! 2755: drop_all_tables
! 2756: execsql { CREATE TABLE t1(a, b) }
! 2757: catchsql { ALTER TABLE t1 ADD COLUMN c DEFAULT 'xxx' REFERENCES t2 }
! 2758: } {1 {Cannot add a REFERENCES column with non-NULL default value}}
! 2759: do_test e_fkey-61.1.2 {
! 2760: execsql { PRAGMA foreign_keys = OFF }
! 2761: execsql { ALTER TABLE t1 ADD COLUMN c DEFAULT 'xxx' REFERENCES t2 }
! 2762: execsql { SELECT sql FROM sqlite_master WHERE name = 't1' }
! 2763: } {{CREATE TABLE t1(a, b, c DEFAULT 'xxx' REFERENCES t2)}}
! 2764: do_test e_fkey-61.1.3 {
! 2765: execsql { PRAGMA foreign_keys = ON }
! 2766: } {}
! 2767:
! 2768: do_test e_fkey-61.2.1 {
! 2769: drop_all_tables
! 2770: execsql {
! 2771: CREATE TABLE p(a UNIQUE);
! 2772: CREATE TABLE c(b REFERENCES p(a));
! 2773: BEGIN;
! 2774: ALTER TABLE p RENAME TO parent;
! 2775: SELECT sql FROM sqlite_master WHERE name = 'c';
! 2776: ROLLBACK;
! 2777: }
! 2778: } {{CREATE TABLE c(b REFERENCES "parent"(a))}}
! 2779: do_test e_fkey-61.2.2 {
! 2780: execsql {
! 2781: PRAGMA foreign_keys = OFF;
! 2782: ALTER TABLE p RENAME TO parent;
! 2783: SELECT sql FROM sqlite_master WHERE name = 'c';
! 2784: }
! 2785: } {{CREATE TABLE c(b REFERENCES p(a))}}
! 2786: do_test e_fkey-61.2.3 {
! 2787: execsql { PRAGMA foreign_keys = ON }
! 2788: } {}
! 2789:
! 2790: do_test e_fkey-61.3.1 {
! 2791: drop_all_tables
! 2792: execsql {
! 2793: CREATE TABLE p(a UNIQUE);
! 2794: CREATE TABLE c(b REFERENCES p(a) ON DELETE SET NULL);
! 2795: INSERT INTO p VALUES('x');
! 2796: INSERT INTO c VALUES('x');
! 2797: BEGIN;
! 2798: DROP TABLE p;
! 2799: SELECT * FROM c;
! 2800: ROLLBACK;
! 2801: }
! 2802: } {{}}
! 2803: do_test e_fkey-61.3.2 {
! 2804: execsql {
! 2805: PRAGMA foreign_keys = OFF;
! 2806: DROP TABLE p;
! 2807: SELECT * FROM c;
! 2808: }
! 2809: } {x}
! 2810: do_test e_fkey-61.3.3 {
! 2811: execsql { PRAGMA foreign_keys = ON }
! 2812: } {}
! 2813:
! 2814: ###########################################################################
! 2815: ### SECTION 6: Limits and Unsupported Features
! 2816: ###########################################################################
! 2817:
! 2818: #-------------------------------------------------------------------------
! 2819: # Test that MATCH clauses are parsed, but SQLite treats every foreign key
! 2820: # constraint as if it were "MATCH SIMPLE".
! 2821: #
! 2822: # EVIDENCE-OF: R-24728-13230 SQLite parses MATCH clauses (i.e. does not
! 2823: # report a syntax error if you specify one), but does not enforce them.
! 2824: #
! 2825: # EVIDENCE-OF: R-24450-46174 All foreign key constraints in SQLite are
! 2826: # handled as if MATCH SIMPLE were specified.
! 2827: #
! 2828: foreach zMatch [list SIMPLE PARTIAL FULL Simple parTIAL FuLL ] {
! 2829: drop_all_tables
! 2830: do_test e_fkey-62.$zMatch.1 {
! 2831: execsql "
! 2832: CREATE TABLE p(a, b, c, PRIMARY KEY(b, c));
! 2833: CREATE TABLE c(d, e, f, FOREIGN KEY(e, f) REFERENCES p MATCH $zMatch);
! 2834: "
! 2835: } {}
! 2836: do_test e_fkey-62.$zMatch.2 {
! 2837: execsql { INSERT INTO p VALUES(1, 2, 3) }
! 2838:
! 2839: # MATCH SIMPLE behaviour: Allow any child key that contains one or more
! 2840: # NULL value to be inserted. Non-NULL values do not have to map to any
! 2841: # parent key values, so long as at least one field of the child key is
! 2842: # NULL.
! 2843: execsql { INSERT INTO c VALUES('w', 2, 3) }
! 2844: execsql { INSERT INTO c VALUES('x', 'x', NULL) }
! 2845: execsql { INSERT INTO c VALUES('y', NULL, 'x') }
! 2846: execsql { INSERT INTO c VALUES('z', NULL, NULL) }
! 2847:
! 2848: # Check that the FK is enforced properly if there are no NULL values
! 2849: # in the child key columns.
! 2850: catchsql { INSERT INTO c VALUES('a', 2, 4) }
! 2851: } {1 {foreign key constraint failed}}
! 2852: }
! 2853:
! 2854: #-------------------------------------------------------------------------
! 2855: # Test that SQLite does not support the SET CONSTRAINT statement. And
! 2856: # that it is possible to create both immediate and deferred constraints.
! 2857: #
! 2858: # EVIDENCE-OF: R-21599-16038 In SQLite, a foreign key constraint is
! 2859: # permanently marked as deferred or immediate when it is created.
! 2860: #
! 2861: drop_all_tables
! 2862: do_test e_fkey-62.1 {
! 2863: catchsql { SET CONSTRAINTS ALL IMMEDIATE }
! 2864: } {1 {near "SET": syntax error}}
! 2865: do_test e_fkey-62.2 {
! 2866: catchsql { SET CONSTRAINTS ALL DEFERRED }
! 2867: } {1 {near "SET": syntax error}}
! 2868:
! 2869: do_test e_fkey-62.3 {
! 2870: execsql {
! 2871: CREATE TABLE p(a, b, PRIMARY KEY(a, b));
! 2872: CREATE TABLE cd(c, d,
! 2873: FOREIGN KEY(c, d) REFERENCES p DEFERRABLE INITIALLY DEFERRED);
! 2874: CREATE TABLE ci(c, d,
! 2875: FOREIGN KEY(c, d) REFERENCES p DEFERRABLE INITIALLY IMMEDIATE);
! 2876: BEGIN;
! 2877: }
! 2878: } {}
! 2879: do_test e_fkey-62.4 {
! 2880: catchsql { INSERT INTO ci VALUES('x', 'y') }
! 2881: } {1 {foreign key constraint failed}}
! 2882: do_test e_fkey-62.5 {
! 2883: catchsql { INSERT INTO cd VALUES('x', 'y') }
! 2884: } {0 {}}
! 2885: do_test e_fkey-62.6 {
! 2886: catchsql { COMMIT }
! 2887: } {1 {foreign key constraint failed}}
! 2888: do_test e_fkey-62.7 {
! 2889: execsql {
! 2890: DELETE FROM cd;
! 2891: COMMIT;
! 2892: }
! 2893: } {}
! 2894:
! 2895: #-------------------------------------------------------------------------
! 2896: # Test that the maximum recursion depth of foreign key action programs is
! 2897: # governed by the SQLITE_MAX_TRIGGER_DEPTH and SQLITE_LIMIT_TRIGGER_DEPTH
! 2898: # settings.
! 2899: #
! 2900: # EVIDENCE-OF: R-42264-30503 The SQLITE_MAX_TRIGGER_DEPTH and
! 2901: # SQLITE_LIMIT_TRIGGER_DEPTH settings determine the maximum allowable
! 2902: # depth of trigger program recursion. For the purposes of these limits,
! 2903: # foreign key actions are considered trigger programs.
! 2904: #
! 2905: proc test_on_delete_recursion {limit} {
! 2906: drop_all_tables
! 2907: execsql {
! 2908: BEGIN;
! 2909: CREATE TABLE t0(a PRIMARY KEY, b);
! 2910: INSERT INTO t0 VALUES('x0', NULL);
! 2911: }
! 2912: for {set i 1} {$i <= $limit} {incr i} {
! 2913: execsql "
! 2914: CREATE TABLE t$i (
! 2915: a PRIMARY KEY, b REFERENCES t[expr $i-1] ON DELETE CASCADE
! 2916: );
! 2917: INSERT INTO t$i VALUES('x$i', 'x[expr $i-1]');
! 2918: "
! 2919: }
! 2920: execsql COMMIT
! 2921: catchsql "
! 2922: DELETE FROM t0;
! 2923: SELECT count(*) FROM t$limit;
! 2924: "
! 2925: }
! 2926: proc test_on_update_recursion {limit} {
! 2927: drop_all_tables
! 2928: execsql {
! 2929: BEGIN;
! 2930: CREATE TABLE t0(a PRIMARY KEY);
! 2931: INSERT INTO t0 VALUES('xxx');
! 2932: }
! 2933: for {set i 1} {$i <= $limit} {incr i} {
! 2934: set j [expr $i-1]
! 2935:
! 2936: execsql "
! 2937: CREATE TABLE t$i (a PRIMARY KEY REFERENCES t$j ON UPDATE CASCADE);
! 2938: INSERT INTO t$i VALUES('xxx');
! 2939: "
! 2940: }
! 2941: execsql COMMIT
! 2942: catchsql "
! 2943: UPDATE t0 SET a = 'yyy';
! 2944: SELECT NOT (a='yyy') FROM t$limit;
! 2945: "
! 2946: }
! 2947:
! 2948: do_test e_fkey-63.1.1 {
! 2949: test_on_delete_recursion $SQLITE_MAX_TRIGGER_DEPTH
! 2950: } {0 0}
! 2951: do_test e_fkey-63.1.2 {
! 2952: test_on_delete_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1]
! 2953: } {1 {too many levels of trigger recursion}}
! 2954: do_test e_fkey-63.1.3 {
! 2955: sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5
! 2956: test_on_delete_recursion 5
! 2957: } {0 0}
! 2958: do_test e_fkey-63.1.4 {
! 2959: test_on_delete_recursion 6
! 2960: } {1 {too many levels of trigger recursion}}
! 2961: do_test e_fkey-63.1.5 {
! 2962: sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000
! 2963: } {5}
! 2964: do_test e_fkey-63.2.1 {
! 2965: test_on_update_recursion $SQLITE_MAX_TRIGGER_DEPTH
! 2966: } {0 0}
! 2967: do_test e_fkey-63.2.2 {
! 2968: test_on_update_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1]
! 2969: } {1 {too many levels of trigger recursion}}
! 2970: do_test e_fkey-63.2.3 {
! 2971: sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5
! 2972: test_on_update_recursion 5
! 2973: } {0 0}
! 2974: do_test e_fkey-63.2.4 {
! 2975: test_on_update_recursion 6
! 2976: } {1 {too many levels of trigger recursion}}
! 2977: do_test e_fkey-63.2.5 {
! 2978: sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000
! 2979: } {5}
! 2980:
! 2981: #-------------------------------------------------------------------------
! 2982: # The setting of the recursive_triggers pragma does not affect foreign
! 2983: # key actions.
! 2984: #
! 2985: # EVIDENCE-OF: R-51769-32730 The PRAGMA recursive_triggers setting does
! 2986: # not not affect the operation of foreign key actions.
! 2987: #
! 2988: foreach recursive_triggers_setting [list 0 1 ON OFF] {
! 2989: drop_all_tables
! 2990: execsql "PRAGMA recursive_triggers = $recursive_triggers_setting"
! 2991:
! 2992: do_test e_fkey-64.$recursive_triggers_setting.1 {
! 2993: execsql {
! 2994: CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1 ON DELETE CASCADE);
! 2995: INSERT INTO t1 VALUES(1, NULL);
! 2996: INSERT INTO t1 VALUES(2, 1);
! 2997: INSERT INTO t1 VALUES(3, 2);
! 2998: INSERT INTO t1 VALUES(4, 3);
! 2999: INSERT INTO t1 VALUES(5, 4);
! 3000: SELECT count(*) FROM t1;
! 3001: }
! 3002: } {5}
! 3003: do_test e_fkey-64.$recursive_triggers_setting.2 {
! 3004: execsql { SELECT count(*) FROM t1 WHERE a = 1 }
! 3005: } {1}
! 3006: do_test e_fkey-64.$recursive_triggers_setting.3 {
! 3007: execsql {
! 3008: DELETE FROM t1 WHERE a = 1;
! 3009: SELECT count(*) FROM t1;
! 3010: }
! 3011: } {0}
! 3012: }
! 3013:
! 3014: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>