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>