Annotation of embedaddon/sqlite3/test/fkey2.test, revision 1.1

1.1     ! misho       1: # 2009 September 15
        !             2: #
        !             3: # The author disclaims copyright to this source code.  In place of
        !             4: # a legal notice, here is a blessing:
        !             5: #
        !             6: #    May you do good and not evil.
        !             7: #    May you find forgiveness for yourself and forgive others.
        !             8: #    May you share freely, never taking more than you give.
        !             9: #
        !            10: #***********************************************************************
        !            11: # This file implements regression tests for SQLite library.
        !            12: #
        !            13: # This file implements tests for foreign keys.
        !            14: #
        !            15: 
        !            16: set testdir [file dirname $argv0]
        !            17: source $testdir/tester.tcl
        !            18: 
        !            19: ifcapable {!foreignkey||!trigger} {
        !            20:   finish_test
        !            21:   return
        !            22: }
        !            23: 
        !            24: #-------------------------------------------------------------------------
        !            25: # Test structure:
        !            26: #
        !            27: # fkey2-1.*: Simple tests to check that immediate and deferred foreign key 
        !            28: #            constraints work when not inside a transaction.
        !            29: #            
        !            30: # fkey2-2.*: Tests to verify that deferred foreign keys work inside
        !            31: #            explicit transactions (i.e that processing really is deferred).
        !            32: #
        !            33: # fkey2-3.*: Tests that a statement transaction is rolled back if an
        !            34: #            immediate foreign key constraint is violated.
        !            35: #
        !            36: # fkey2-4.*: Test that FK actions may recurse even when recursive triggers
        !            37: #            are disabled.
        !            38: #
        !            39: # fkey2-5.*: Check that if foreign-keys are enabled, it is not possible
        !            40: #            to write to an FK column using the incremental blob API.
        !            41: #
        !            42: # fkey2-6.*: Test that FK processing is automatically disabled when 
        !            43: #            running VACUUM.
        !            44: #
        !            45: # fkey2-7.*: Test using an IPK as the key in the child (referencing) table.
        !            46: #
        !            47: # fkey2-8.*: Test that enabling/disabling foreign key support while a 
        !            48: #            transaction is active is not possible.
        !            49: #
        !            50: # fkey2-9.*: Test SET DEFAULT actions.
        !            51: #
        !            52: # fkey2-10.*: Test errors.
        !            53: #
        !            54: # fkey2-11.*: Test CASCADE actions.
        !            55: #
        !            56: # fkey2-12.*: Test RESTRICT actions.
        !            57: #
        !            58: # fkey2-13.*: Test that FK processing is performed when a row is REPLACED by
        !            59: #             an UPDATE or INSERT statement.
        !            60: #
        !            61: # fkey2-14.*: Test the ALTER TABLE and DROP TABLE commands.
        !            62: #
        !            63: # fkey2-15.*: Test that if there are no (known) outstanding foreign key 
        !            64: #             constraint violations in the database, inserting into a parent
        !            65: #             table or deleting from a child table does not cause SQLite
        !            66: #             to check if this has repaired an outstanding violation.
        !            67: #
        !            68: # fkey2-16.*: Test that rows that refer to themselves may be inserted, 
        !            69: #             updated and deleted.
        !            70: #
        !            71: # fkey2-17.*: Test that the "count_changes" pragma does not interfere with
        !            72: #             FK constraint processing.
        !            73: # 
        !            74: # fkey2-18.*: Test that the authorization callback is invoked when processing
        !            75: #             FK constraints.
        !            76: #
        !            77: # fkey2-20.*: Test that ON CONFLICT clauses specified as part of statements
        !            78: #             do not affect the operation of FK constraints.
        !            79: #
        !            80: # fkey2-genfkey.*: Tests that were used with the shell tool .genfkey
        !            81: #            command. Recycled to test the built-in implementation.
        !            82: #
        !            83: # fkey2-dd08e5.*:  Tests to verify that ticket dd08e5a988d00decc4a543daa8d
        !            84: #                  has been fixed.
        !            85: #
        !            86: 
        !            87: 
        !            88: execsql { PRAGMA foreign_keys = on }
        !            89: 
        !            90: set FkeySimpleSchema {
        !            91:   PRAGMA foreign_keys = on;
        !            92:   CREATE TABLE t1(a PRIMARY KEY, b);
        !            93:   CREATE TABLE t2(c REFERENCES t1(a) /D/ , d);
        !            94: 
        !            95:   CREATE TABLE t3(a PRIMARY KEY, b);
        !            96:   CREATE TABLE t4(c REFERENCES t3 /D/, d);
        !            97: 
        !            98:   CREATE TABLE t7(a, b INTEGER PRIMARY KEY);
        !            99:   CREATE TABLE t8(c REFERENCES t7 /D/, d);
        !           100: 
        !           101:   CREATE TABLE t9(a REFERENCES nosuchtable, b);
        !           102:   CREATE TABLE t10(a REFERENCES t9(c) /D/, b);
        !           103: }
        !           104: 
        !           105: 
        !           106: set FkeySimpleTests {
        !           107:   1.1  "INSERT INTO t2 VALUES(1, 3)"      {1 {foreign key constraint failed}}
        !           108:   1.2  "INSERT INTO t1 VALUES(1, 2)"      {0 {}}
        !           109:   1.3  "INSERT INTO t2 VALUES(1, 3)"      {0 {}}
        !           110:   1.4  "INSERT INTO t2 VALUES(2, 4)"      {1 {foreign key constraint failed}}
        !           111:   1.5  "INSERT INTO t2 VALUES(NULL, 4)"   {0 {}}
        !           112:   1.6  "UPDATE t2 SET c=2 WHERE d=4"      {1 {foreign key constraint failed}}
        !           113:   1.7  "UPDATE t2 SET c=1 WHERE d=4"      {0 {}}
        !           114:   1.9  "UPDATE t2 SET c=1 WHERE d=4"      {0 {}}
        !           115:   1.10 "UPDATE t2 SET c=NULL WHERE d=4"   {0 {}}
        !           116:   1.11 "DELETE FROM t1 WHERE a=1"         {1 {foreign key constraint failed}}
        !           117:   1.12 "UPDATE t1 SET a = 2"              {1 {foreign key constraint failed}}
        !           118:   1.13 "UPDATE t1 SET a = 1"              {0 {}}
        !           119: 
        !           120:   2.1  "INSERT INTO t4 VALUES(1, 3)"      {1 {foreign key constraint failed}}
        !           121:   2.2  "INSERT INTO t3 VALUES(1, 2)"      {0 {}}
        !           122:   2.3  "INSERT INTO t4 VALUES(1, 3)"      {0 {}}
        !           123: 
        !           124:   4.1  "INSERT INTO t8 VALUES(1, 3)"      {1 {foreign key constraint failed}}
        !           125:   4.2  "INSERT INTO t7 VALUES(2, 1)"      {0 {}}
        !           126:   4.3  "INSERT INTO t8 VALUES(1, 3)"      {0 {}}
        !           127:   4.4  "INSERT INTO t8 VALUES(2, 4)"      {1 {foreign key constraint failed}}
        !           128:   4.5  "INSERT INTO t8 VALUES(NULL, 4)"   {0 {}}
        !           129:   4.6  "UPDATE t8 SET c=2 WHERE d=4"      {1 {foreign key constraint failed}}
        !           130:   4.7  "UPDATE t8 SET c=1 WHERE d=4"      {0 {}}
        !           131:   4.9  "UPDATE t8 SET c=1 WHERE d=4"      {0 {}}
        !           132:   4.10 "UPDATE t8 SET c=NULL WHERE d=4"   {0 {}}
        !           133:   4.11 "DELETE FROM t7 WHERE b=1"         {1 {foreign key constraint failed}}
        !           134:   4.12 "UPDATE t7 SET b = 2"              {1 {foreign key constraint failed}}
        !           135:   4.13 "UPDATE t7 SET b = 1"              {0 {}}
        !           136:   4.14 "INSERT INTO t8 VALUES('a', 'b')"  {1 {foreign key constraint failed}}
        !           137:   4.15 "UPDATE t7 SET b = 5"              {1 {foreign key constraint failed}}
        !           138:   4.16 "UPDATE t7 SET rowid = 5"          {1 {foreign key constraint failed}}
        !           139:   4.17 "UPDATE t7 SET a = 10"             {0 {}}
        !           140: 
        !           141:   5.1  "INSERT INTO t9 VALUES(1, 3)"      {1 {no such table: main.nosuchtable}}
        !           142:   5.2  "INSERT INTO t10 VALUES(1, 3)"     {1 {foreign key mismatch}}
        !           143: }
        !           144: 
        !           145: do_test fkey2-1.1.0 {
        !           146:   execsql [string map {/D/ {}} $FkeySimpleSchema]
        !           147: } {}
        !           148: foreach {tn zSql res} $FkeySimpleTests {
        !           149:   do_test fkey2-1.1.$tn { catchsql $zSql } $res
        !           150: }
        !           151: drop_all_tables
        !           152: 
        !           153: do_test fkey2-1.2.0 {
        !           154:   execsql [string map {/D/ {DEFERRABLE INITIALLY DEFERRED}} $FkeySimpleSchema]
        !           155: } {}
        !           156: foreach {tn zSql res} $FkeySimpleTests {
        !           157:   do_test fkey2-1.2.$tn { catchsql $zSql } $res
        !           158: }
        !           159: drop_all_tables
        !           160: 
        !           161: do_test fkey2-1.3.0 {
        !           162:   execsql [string map {/D/ {}} $FkeySimpleSchema]
        !           163:   execsql { PRAGMA count_changes = 1 }
        !           164: } {}
        !           165: foreach {tn zSql res} $FkeySimpleTests {
        !           166:   if {$res == "0 {}"} { set res {0 1} }
        !           167:   do_test fkey2-1.3.$tn { catchsql $zSql } $res
        !           168: }
        !           169: execsql { PRAGMA count_changes = 0 }
        !           170: drop_all_tables
        !           171: 
        !           172: do_test fkey2-1.4.0 {
        !           173:   execsql [string map {/D/ {}} $FkeySimpleSchema]
        !           174:   execsql { PRAGMA count_changes = 1 }
        !           175: } {}
        !           176: foreach {tn zSql res} $FkeySimpleTests {
        !           177:   if {$res == "0 {}"} { set res {0 1} }
        !           178:   execsql BEGIN
        !           179:   do_test fkey2-1.4.$tn { catchsql $zSql } $res
        !           180:   execsql COMMIT
        !           181: }
        !           182: execsql { PRAGMA count_changes = 0 }
        !           183: drop_all_tables
        !           184: 
        !           185: # Special test: When the parent key is an IPK, make sure the affinity of
        !           186: # the IPK is not applied to the child key value before it is inserted
        !           187: # into the child table.
        !           188: do_test fkey2-1.5.1 {
        !           189:   execsql {
        !           190:     CREATE TABLE i(i INTEGER PRIMARY KEY);
        !           191:     CREATE TABLE j(j REFERENCES i);
        !           192:     INSERT INTO i VALUES(35);
        !           193:     INSERT INTO j VALUES('35.0');
        !           194:     SELECT j, typeof(j) FROM j;
        !           195:   }
        !           196: } {35.0 text}
        !           197: do_test fkey2-1.5.2 {
        !           198:   catchsql { DELETE FROM i }
        !           199: } {1 {foreign key constraint failed}}
        !           200: 
        !           201: # Same test using a regular primary key with integer affinity.
        !           202: drop_all_tables
        !           203: do_test fkey2-1.6.1 {
        !           204:   execsql {
        !           205:     CREATE TABLE i(i INT UNIQUE);
        !           206:     CREATE TABLE j(j REFERENCES i(i));
        !           207:     INSERT INTO i VALUES('35.0');
        !           208:     INSERT INTO j VALUES('35.0');
        !           209:     SELECT j, typeof(j) FROM j;
        !           210:     SELECT i, typeof(i) FROM i;
        !           211:   }
        !           212: } {35.0 text 35 integer}
        !           213: do_test fkey2-1.6.2 {
        !           214:   catchsql { DELETE FROM i }
        !           215: } {1 {foreign key constraint failed}}
        !           216: 
        !           217: # Use a collation sequence on the parent key.
        !           218: drop_all_tables
        !           219: do_test fkey2-1.7.1 {
        !           220:   execsql {
        !           221:     CREATE TABLE i(i TEXT COLLATE nocase PRIMARY KEY);
        !           222:     CREATE TABLE j(j TEXT COLLATE binary REFERENCES i(i));
        !           223:     INSERT INTO i VALUES('SQLite');
        !           224:     INSERT INTO j VALUES('sqlite');
        !           225:   }
        !           226:   catchsql { DELETE FROM i }
        !           227: } {1 {foreign key constraint failed}}
        !           228: 
        !           229: # Use the parent key collation even if it is default and the child key
        !           230: # has an explicit value.
        !           231: drop_all_tables
        !           232: do_test fkey2-1.7.2 {
        !           233:   execsql {
        !           234:     CREATE TABLE i(i TEXT PRIMARY KEY);        -- Colseq is "BINARY"
        !           235:     CREATE TABLE j(j TEXT COLLATE nocase REFERENCES i(i));
        !           236:     INSERT INTO i VALUES('SQLite');
        !           237:   }
        !           238:   catchsql { INSERT INTO j VALUES('sqlite') }
        !           239: } {1 {foreign key constraint failed}}
        !           240: do_test fkey2-1.7.3 {
        !           241:   execsql {
        !           242:     INSERT INTO i VALUES('sqlite');
        !           243:     INSERT INTO j VALUES('sqlite');
        !           244:     DELETE FROM i WHERE i = 'SQLite';
        !           245:   }
        !           246:   catchsql { DELETE FROM i WHERE i = 'sqlite' }
        !           247: } {1 {foreign key constraint failed}}
        !           248: 
        !           249: #-------------------------------------------------------------------------
        !           250: # This section (test cases fkey2-2.*) contains tests to check that the
        !           251: # deferred foreign key constraint logic works.
        !           252: #
        !           253: proc fkey2-2-test {tn nocommit sql {res {}}} {
        !           254:   if {$res eq "FKV"} {
        !           255:     set expected {1 {foreign key constraint failed}}
        !           256:   } else {
        !           257:     set expected [list 0 $res]
        !           258:   }
        !           259:   do_test fkey2-2.$tn [list catchsql $sql] $expected
        !           260:   if {$nocommit} {
        !           261:     do_test fkey2-2.${tn}c {
        !           262:       catchsql COMMIT
        !           263:     } {1 {foreign key constraint failed}}
        !           264:   }
        !           265: }
        !           266: 
        !           267: fkey2-2-test 1 0 {
        !           268:   CREATE TABLE node(
        !           269:     nodeid PRIMARY KEY,
        !           270:     parent REFERENCES node DEFERRABLE INITIALLY DEFERRED
        !           271:   );
        !           272:   CREATE TABLE leaf(
        !           273:     cellid PRIMARY KEY,
        !           274:     parent REFERENCES node DEFERRABLE INITIALLY DEFERRED
        !           275:   );
        !           276: }
        !           277: 
        !           278: fkey2-2-test 1  0 "INSERT INTO node VALUES(1, 0)"       FKV
        !           279: fkey2-2-test 2  0 "BEGIN"
        !           280: fkey2-2-test 3  1   "INSERT INTO node VALUES(1, 0)"
        !           281: fkey2-2-test 4  0   "UPDATE node SET parent = NULL"
        !           282: fkey2-2-test 5  0 "COMMIT"
        !           283: fkey2-2-test 6  0 "SELECT * FROM node" {1 {}}
        !           284: 
        !           285: fkey2-2-test 7  0 "BEGIN"
        !           286: fkey2-2-test 8  1   "INSERT INTO leaf VALUES('a', 2)"
        !           287: fkey2-2-test 9  1   "INSERT INTO node VALUES(2, 0)"
        !           288: fkey2-2-test 10 0   "UPDATE node SET parent = 1 WHERE nodeid = 2"
        !           289: fkey2-2-test 11 0 "COMMIT"
        !           290: fkey2-2-test 12 0 "SELECT * FROM node" {1 {} 2 1}
        !           291: fkey2-2-test 13 0 "SELECT * FROM leaf" {a 2}
        !           292: 
        !           293: fkey2-2-test 14 0 "BEGIN"
        !           294: fkey2-2-test 15 1   "DELETE FROM node WHERE nodeid = 2"
        !           295: fkey2-2-test 16 0   "INSERT INTO node VALUES(2, NULL)"
        !           296: fkey2-2-test 17 0 "COMMIT"
        !           297: fkey2-2-test 18 0 "SELECT * FROM node" {1 {} 2 {}}
        !           298: fkey2-2-test 19 0 "SELECT * FROM leaf" {a 2}
        !           299: 
        !           300: fkey2-2-test 20 0 "BEGIN"
        !           301: fkey2-2-test 21 0   "INSERT INTO leaf VALUES('b', 1)"
        !           302: fkey2-2-test 22 0   "SAVEPOINT save"
        !           303: fkey2-2-test 23 0     "DELETE FROM node WHERE nodeid = 1"
        !           304: fkey2-2-test 24 0   "ROLLBACK TO save"
        !           305: fkey2-2-test 25 0 "COMMIT"
        !           306: fkey2-2-test 26 0 "SELECT * FROM node" {1 {} 2 {}}
        !           307: fkey2-2-test 27 0 "SELECT * FROM leaf" {a 2 b 1}
        !           308: 
        !           309: fkey2-2-test 28 0 "BEGIN"
        !           310: fkey2-2-test 29 0   "INSERT INTO leaf VALUES('c', 1)"
        !           311: fkey2-2-test 30 0   "SAVEPOINT save"
        !           312: fkey2-2-test 31 0     "DELETE FROM node WHERE nodeid = 1"
        !           313: fkey2-2-test 32 1   "RELEASE save"
        !           314: fkey2-2-test 33 1   "DELETE FROM leaf WHERE cellid = 'b'"
        !           315: fkey2-2-test 34 0   "DELETE FROM leaf WHERE cellid = 'c'"
        !           316: fkey2-2-test 35 0 "COMMIT"
        !           317: fkey2-2-test 36 0 "SELECT * FROM node" {2 {}} 
        !           318: fkey2-2-test 37 0 "SELECT * FROM leaf" {a 2}
        !           319: 
        !           320: fkey2-2-test 38 0 "SAVEPOINT outer"
        !           321: fkey2-2-test 39 1   "INSERT INTO leaf VALUES('d', 3)"
        !           322: fkey2-2-test 40 1 "RELEASE outer"    FKV
        !           323: fkey2-2-test 41 1   "INSERT INTO leaf VALUES('e', 3)"
        !           324: fkey2-2-test 42 0   "INSERT INTO node VALUES(3, 2)"
        !           325: fkey2-2-test 43 0 "RELEASE outer"
        !           326: 
        !           327: fkey2-2-test 44 0 "SAVEPOINT outer"
        !           328: fkey2-2-test 45 1   "DELETE FROM node WHERE nodeid=3"
        !           329: fkey2-2-test 47 0   "INSERT INTO node VALUES(3, 2)"
        !           330: fkey2-2-test 48 0 "ROLLBACK TO outer"
        !           331: fkey2-2-test 49 0 "RELEASE outer"
        !           332: 
        !           333: fkey2-2-test 50 0 "SAVEPOINT outer"
        !           334: fkey2-2-test 51 1   "INSERT INTO leaf VALUES('f', 4)"
        !           335: fkey2-2-test 52 1   "SAVEPOINT inner"
        !           336: fkey2-2-test 53 1     "INSERT INTO leaf VALUES('g', 4)"
        !           337: fkey2-2-test 54 1  "RELEASE outer"   FKV
        !           338: fkey2-2-test 55 1   "ROLLBACK TO inner"
        !           339: fkey2-2-test 56 0  "COMMIT"          FKV
        !           340: fkey2-2-test 57 0   "INSERT INTO node VALUES(4, NULL)"
        !           341: fkey2-2-test 58 0 "RELEASE outer"
        !           342: fkey2-2-test 59 0 "SELECT * FROM node" {2 {} 3 2 4 {}}
        !           343: fkey2-2-test 60 0 "SELECT * FROM leaf" {a 2 d 3 e 3 f 4}
        !           344: 
        !           345: # The following set of tests check that if a statement that affects 
        !           346: # multiple rows violates some foreign key constraints, then strikes a 
        !           347: # constraint that causes the statement-transaction to be rolled back, 
        !           348: # the deferred constraint counter is correctly reset to the value it 
        !           349: # had before the statement-transaction was opened.
        !           350: #
        !           351: fkey2-2-test 61 0 "BEGIN"
        !           352: fkey2-2-test 62 0   "DELETE FROM leaf"
        !           353: fkey2-2-test 63 0   "DELETE FROM node"
        !           354: fkey2-2-test 64 1   "INSERT INTO leaf VALUES('a', 1)"
        !           355: fkey2-2-test 65 1   "INSERT INTO leaf VALUES('b', 2)"
        !           356: fkey2-2-test 66 1   "INSERT INTO leaf VALUES('c', 1)"
        !           357: do_test fkey2-2-test-67 {
        !           358:   catchsql          "INSERT INTO node SELECT parent, 3 FROM leaf"
        !           359: } {1 {column nodeid is not unique}}
        !           360: fkey2-2-test 68 0 "COMMIT"           FKV
        !           361: fkey2-2-test 69 1   "INSERT INTO node VALUES(1, NULL)"
        !           362: fkey2-2-test 70 0   "INSERT INTO node VALUES(2, NULL)"
        !           363: fkey2-2-test 71 0 "COMMIT"
        !           364: 
        !           365: fkey2-2-test 72 0 "BEGIN"
        !           366: fkey2-2-test 73 1   "DELETE FROM node"
        !           367: fkey2-2-test 74 0   "INSERT INTO node(nodeid) SELECT DISTINCT parent FROM leaf"
        !           368: fkey2-2-test 75 0 "COMMIT"
        !           369: 
        !           370: #-------------------------------------------------------------------------
        !           371: # Test cases fkey2-3.* test that a program that executes foreign key
        !           372: # actions (CASCADE, SET DEFAULT, SET NULL etc.) or tests FK constraints
        !           373: # opens a statement transaction if required.
        !           374: #
        !           375: # fkey2-3.1.*: Test UPDATE statements.
        !           376: # fkey2-3.2.*: Test DELETE statements.
        !           377: #
        !           378: drop_all_tables
        !           379: do_test fkey2-3.1.1 {
        !           380:   execsql {
        !           381:     CREATE TABLE ab(a PRIMARY KEY, b);
        !           382:     CREATE TABLE cd(
        !           383:       c PRIMARY KEY REFERENCES ab ON UPDATE CASCADE ON DELETE CASCADE, 
        !           384:       d
        !           385:     );
        !           386:     CREATE TABLE ef(
        !           387:       e REFERENCES cd ON UPDATE CASCADE, 
        !           388:       f, CHECK (e!=5)
        !           389:     );
        !           390:   }
        !           391: } {}
        !           392: do_test fkey2-3.1.2 {
        !           393:   execsql {
        !           394:     INSERT INTO ab VALUES(1, 'b');
        !           395:     INSERT INTO cd VALUES(1, 'd');
        !           396:     INSERT INTO ef VALUES(1, 'e');
        !           397:   }
        !           398: } {}
        !           399: do_test fkey2-3.1.3 {
        !           400:   catchsql { UPDATE ab SET a = 5 }
        !           401: } {1 {constraint failed}}
        !           402: do_test fkey2-3.1.4 {
        !           403:   execsql { SELECT * FROM ab }
        !           404: } {1 b}
        !           405: do_test fkey2-3.1.4 {
        !           406:   execsql BEGIN;
        !           407:   catchsql { UPDATE ab SET a = 5 }
        !           408: } {1 {constraint failed}}
        !           409: do_test fkey2-3.1.5 {
        !           410:   execsql COMMIT;
        !           411:   execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef }
        !           412: } {1 b 1 d 1 e}
        !           413: 
        !           414: do_test fkey2-3.2.1 {
        !           415:   execsql BEGIN;
        !           416:   catchsql { DELETE FROM ab }
        !           417: } {1 {foreign key constraint failed}}
        !           418: do_test fkey2-3.2.2 {
        !           419:   execsql COMMIT
        !           420:   execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef }
        !           421: } {1 b 1 d 1 e}
        !           422: 
        !           423: #-------------------------------------------------------------------------
        !           424: # Test cases fkey2-4.* test that recursive foreign key actions 
        !           425: # (i.e. CASCADE) are allowed even if recursive triggers are disabled.
        !           426: #
        !           427: drop_all_tables
        !           428: do_test fkey2-4.1 {
        !           429:   execsql {
        !           430:     CREATE TABLE t1(
        !           431:       node PRIMARY KEY, 
        !           432:       parent REFERENCES t1 ON DELETE CASCADE
        !           433:     );
        !           434:     CREATE TABLE t2(node PRIMARY KEY, parent);
        !           435:     CREATE TRIGGER t2t AFTER DELETE ON t2 BEGIN
        !           436:       DELETE FROM t2 WHERE parent = old.node;
        !           437:     END;
        !           438:     INSERT INTO t1 VALUES(1, NULL);
        !           439:     INSERT INTO t1 VALUES(2, 1);
        !           440:     INSERT INTO t1 VALUES(3, 1);
        !           441:     INSERT INTO t1 VALUES(4, 2);
        !           442:     INSERT INTO t1 VALUES(5, 2);
        !           443:     INSERT INTO t1 VALUES(6, 3);
        !           444:     INSERT INTO t1 VALUES(7, 3);
        !           445:     INSERT INTO t2 SELECT * FROM t1;
        !           446:   }
        !           447: } {}
        !           448: do_test fkey2-4.2 {
        !           449:   execsql { PRAGMA recursive_triggers = off }
        !           450:   execsql { 
        !           451:     BEGIN;
        !           452:       DELETE FROM t1 WHERE node = 1;
        !           453:       SELECT node FROM t1;
        !           454:   }
        !           455: } {}
        !           456: do_test fkey2-4.3 {
        !           457:   execsql { 
        !           458:       DELETE FROM t2 WHERE node = 1;
        !           459:       SELECT node FROM t2;
        !           460:     ROLLBACK;
        !           461:   }
        !           462: } {4 5 6 7}
        !           463: do_test fkey2-4.4 {
        !           464:   execsql { PRAGMA recursive_triggers = on }
        !           465:   execsql { 
        !           466:     BEGIN;
        !           467:       DELETE FROM t1 WHERE node = 1;
        !           468:       SELECT node FROM t1;
        !           469:   }
        !           470: } {}
        !           471: do_test fkey2-4.3 {
        !           472:   execsql { 
        !           473:       DELETE FROM t2 WHERE node = 1;
        !           474:       SELECT node FROM t2;
        !           475:     ROLLBACK;
        !           476:   }
        !           477: } {}
        !           478: 
        !           479: #-------------------------------------------------------------------------
        !           480: # Test cases fkey2-5.* verify that the incremental blob API may not
        !           481: # write to a foreign key column while foreign-keys are enabled.
        !           482: #
        !           483: drop_all_tables
        !           484: ifcapable incrblob {
        !           485:   do_test fkey2-5.1 {
        !           486:     execsql {
        !           487:       CREATE TABLE t1(a PRIMARY KEY, b);
        !           488:       CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1(a));
        !           489:       INSERT INTO t1 VALUES('hello', 'world');
        !           490:       INSERT INTO t2 VALUES('key', 'hello');
        !           491:     }
        !           492:   } {}
        !           493:   do_test fkey2-5.2 {
        !           494:     set rc [catch { set fd [db incrblob t2 b 1] } msg]
        !           495:     list $rc $msg
        !           496:   } {1 {cannot open foreign key column for writing}}
        !           497:   do_test fkey2-5.3 {
        !           498:     set rc [catch { set fd [db incrblob -readonly t2 b 1] } msg]
        !           499:     close $fd
        !           500:     set rc
        !           501:   } {0}
        !           502:   do_test fkey2-5.4 {
        !           503:     execsql { PRAGMA foreign_keys = off }
        !           504:     set rc [catch { set fd [db incrblob t2 b 1] } msg]
        !           505:     close $fd
        !           506:     set rc
        !           507:   } {0}
        !           508:   do_test fkey2-5.5 {
        !           509:     execsql { PRAGMA foreign_keys = on }
        !           510:   } {}
        !           511: }
        !           512: 
        !           513: drop_all_tables
        !           514: ifcapable vacuum {
        !           515:   do_test fkey2-6.1 {
        !           516:     execsql {
        !           517:       CREATE TABLE t1(a REFERENCES t2(c), b);
        !           518:       CREATE TABLE t2(c UNIQUE, b);
        !           519:       INSERT INTO t2 VALUES(1, 2);
        !           520:       INSERT INTO t1 VALUES(1, 2);
        !           521:       VACUUM;
        !           522:     }
        !           523:   } {}
        !           524: }
        !           525: 
        !           526: #-------------------------------------------------------------------------
        !           527: # Test that it is possible to use an INTEGER PRIMARY KEY as the child key
        !           528: # of a foreign constraint.
        !           529: # 
        !           530: drop_all_tables
        !           531: do_test fkey2-7.1 {
        !           532:   execsql {
        !           533:     CREATE TABLE t1(a PRIMARY KEY, b);
        !           534:     CREATE TABLE t2(c INTEGER PRIMARY KEY REFERENCES t1, b);
        !           535:   }
        !           536: } {}
        !           537: do_test fkey2-7.2 {
        !           538:   catchsql { INSERT INTO t2 VALUES(1, 'A'); }
        !           539: } {1 {foreign key constraint failed}}
        !           540: do_test fkey2-7.3 {
        !           541:   execsql { 
        !           542:     INSERT INTO t1 VALUES(1, 2);
        !           543:     INSERT INTO t1 VALUES(2, 3);
        !           544:     INSERT INTO t2 VALUES(1, 'A');
        !           545:   }
        !           546: } {}
        !           547: do_test fkey2-7.4 {
        !           548:   execsql { UPDATE t2 SET c = 2 }
        !           549: } {}
        !           550: do_test fkey2-7.5 {
        !           551:   catchsql { UPDATE t2 SET c = 3 }
        !           552: } {1 {foreign key constraint failed}}
        !           553: do_test fkey2-7.6 {
        !           554:   catchsql { DELETE FROM t1 WHERE a = 2 }
        !           555: } {1 {foreign key constraint failed}}
        !           556: do_test fkey2-7.7 {
        !           557:   execsql { DELETE FROM t1 WHERE a = 1 }
        !           558: } {}
        !           559: do_test fkey2-7.8 {
        !           560:   catchsql { UPDATE t1 SET a = 3 }
        !           561: } {1 {foreign key constraint failed}}
        !           562: do_test fkey2-7.9 {
        !           563:   catchsql { UPDATE t2 SET rowid = 3 }
        !           564: } {1 {foreign key constraint failed}}
        !           565: 
        !           566: #-------------------------------------------------------------------------
        !           567: # Test that it is not possible to enable/disable FK support while a
        !           568: # transaction is open.
        !           569: # 
        !           570: drop_all_tables
        !           571: proc fkey2-8-test {tn zSql value} {
        !           572:   do_test fkey-2.8.$tn.1 [list execsql $zSql] {}
        !           573:   do_test fkey-2.8.$tn.2 { execsql "PRAGMA foreign_keys" } $value
        !           574: }
        !           575: fkey2-8-test  1 { PRAGMA foreign_keys = 0     } 0
        !           576: fkey2-8-test  2 { PRAGMA foreign_keys = 1     } 1
        !           577: fkey2-8-test  3 { BEGIN                       } 1
        !           578: fkey2-8-test  4 { PRAGMA foreign_keys = 0     } 1
        !           579: fkey2-8-test  5 { COMMIT                      } 1
        !           580: fkey2-8-test  6 { PRAGMA foreign_keys = 0     } 0
        !           581: fkey2-8-test  7 { BEGIN                       } 0
        !           582: fkey2-8-test  8 { PRAGMA foreign_keys = 1     } 0
        !           583: fkey2-8-test  9 { COMMIT                      } 0
        !           584: fkey2-8-test 10 { PRAGMA foreign_keys = 1     } 1
        !           585: fkey2-8-test 11 { PRAGMA foreign_keys = off   } 0
        !           586: fkey2-8-test 12 { PRAGMA foreign_keys = on    } 1
        !           587: fkey2-8-test 13 { PRAGMA foreign_keys = no    } 0
        !           588: fkey2-8-test 14 { PRAGMA foreign_keys = yes   } 1
        !           589: fkey2-8-test 15 { PRAGMA foreign_keys = false } 0
        !           590: fkey2-8-test 16 { PRAGMA foreign_keys = true  } 1
        !           591: 
        !           592: #-------------------------------------------------------------------------
        !           593: # The following tests, fkey2-9.*, test SET DEFAULT actions.
        !           594: #
        !           595: drop_all_tables
        !           596: do_test fkey2-9.1.1 {
        !           597:   execsql {
        !           598:     CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
        !           599:     CREATE TABLE t2(
        !           600:       c INTEGER PRIMARY KEY,
        !           601:       d INTEGER DEFAULT 1 REFERENCES t1 ON DELETE SET DEFAULT
        !           602:     );
        !           603:     DELETE FROM t1;
        !           604:   }
        !           605: } {}
        !           606: do_test fkey2-9.1.2 {
        !           607:   execsql {
        !           608:     INSERT INTO t1 VALUES(1, 'one');
        !           609:     INSERT INTO t1 VALUES(2, 'two');
        !           610:     INSERT INTO t2 VALUES(1, 2);
        !           611:     SELECT * FROM t2;
        !           612:     DELETE FROM t1 WHERE a = 2;
        !           613:     SELECT * FROM t2;
        !           614:   }
        !           615: } {1 2 1 1}
        !           616: do_test fkey2-9.1.3 {
        !           617:   execsql {
        !           618:     INSERT INTO t1 VALUES(2, 'two');
        !           619:     UPDATE t2 SET d = 2;
        !           620:     DELETE FROM t1 WHERE a = 1;
        !           621:     SELECT * FROM t2;
        !           622:   }
        !           623: } {1 2}
        !           624: do_test fkey2-9.1.4 {
        !           625:   execsql { SELECT * FROM t1 }
        !           626: } {2 two}
        !           627: do_test fkey2-9.1.5 {
        !           628:   catchsql { DELETE FROM t1 }
        !           629: } {1 {foreign key constraint failed}}
        !           630: 
        !           631: do_test fkey2-9.2.1 {
        !           632:   execsql {
        !           633:     CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c));
        !           634:     CREATE TABLE cc(d DEFAULT 3, e DEFAULT 1, f DEFAULT 2,
        !           635:         FOREIGN KEY(f, d) REFERENCES pp 
        !           636:         ON UPDATE SET DEFAULT 
        !           637:         ON DELETE SET NULL
        !           638:     );
        !           639:     INSERT INTO pp VALUES(1, 2, 3);
        !           640:     INSERT INTO pp VALUES(4, 5, 6);
        !           641:     INSERT INTO pp VALUES(7, 8, 9);
        !           642:   }
        !           643: } {}
        !           644: do_test fkey2-9.2.2 {
        !           645:   execsql {
        !           646:     INSERT INTO cc VALUES(6, 'A', 5);
        !           647:     INSERT INTO cc VALUES(6, 'B', 5);
        !           648:     INSERT INTO cc VALUES(9, 'A', 8);
        !           649:     INSERT INTO cc VALUES(9, 'B', 8);
        !           650:     UPDATE pp SET b = 1 WHERE a = 7;
        !           651:     SELECT * FROM cc;
        !           652:   }
        !           653: } {6 A 5 6 B 5 3 A 2 3 B 2}
        !           654: do_test fkey2-9.2.3 {
        !           655:   execsql {
        !           656:     DELETE FROM pp WHERE a = 4;
        !           657:     SELECT * FROM cc;
        !           658:   }
        !           659: } {{} A {} {} B {} 3 A 2 3 B 2}
        !           660: 
        !           661: #-------------------------------------------------------------------------
        !           662: # The following tests, fkey2-10.*, test "foreign key mismatch" and 
        !           663: # other errors.
        !           664: #
        !           665: set tn 0
        !           666: foreach zSql [list {
        !           667:   CREATE TABLE p(a PRIMARY KEY, b);
        !           668:   CREATE TABLE c(x REFERENCES p(c));
        !           669: } {
        !           670:   CREATE TABLE c(x REFERENCES v(y));
        !           671:   CREATE VIEW v AS SELECT x AS y FROM c;
        !           672: } {
        !           673:   CREATE TABLE p(a, b, PRIMARY KEY(a, b));
        !           674:   CREATE TABLE c(x REFERENCES p);
        !           675: } {
        !           676:   CREATE TABLE p(a COLLATE binary, b);
        !           677:   CREATE UNIQUE INDEX i ON p(a COLLATE nocase);
        !           678:   CREATE TABLE c(x REFERENCES p(a));
        !           679: }] {
        !           680:   drop_all_tables
        !           681:   do_test fkey2-10.1.[incr tn] {
        !           682:     execsql $zSql
        !           683:     catchsql { INSERT INTO c DEFAULT VALUES }
        !           684:   } {1 {foreign key mismatch}}
        !           685: }
        !           686: 
        !           687: # "rowid" cannot be used as part of a child or parent key definition 
        !           688: # unless it happens to be the name of an explicitly declared column.
        !           689: #
        !           690: do_test fkey2-10.2.1 {
        !           691:   drop_all_tables
        !           692:   catchsql {
        !           693:     CREATE TABLE t1(a PRIMARY KEY, b);
        !           694:     CREATE TABLE t2(c, d, FOREIGN KEY(rowid) REFERENCES t1(a));
        !           695:   }
        !           696: } {1 {unknown column "rowid" in foreign key definition}}
        !           697: do_test fkey2-10.2.2 {
        !           698:   drop_all_tables
        !           699:   catchsql {
        !           700:     CREATE TABLE t1(a PRIMARY KEY, b);
        !           701:     CREATE TABLE t2(rowid, d, FOREIGN KEY(rowid) REFERENCES t1(a));
        !           702:   }
        !           703: } {0 {}}
        !           704: do_test fkey2-10.2.1 {
        !           705:   drop_all_tables
        !           706:   catchsql {
        !           707:     CREATE TABLE t1(a, b);
        !           708:     CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid));
        !           709:     INSERT INTO t1(rowid, a, b) VALUES(1, 1, 1);
        !           710:     INSERT INTO t2 VALUES(1, 1);
        !           711:   }
        !           712: } {1 {foreign key mismatch}}
        !           713: do_test fkey2-10.2.2 {
        !           714:   drop_all_tables
        !           715:   catchsql {
        !           716:     CREATE TABLE t1(rowid PRIMARY KEY, b);
        !           717:     CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid));
        !           718:     INSERT INTO t1(rowid, b) VALUES(1, 1);
        !           719:     INSERT INTO t2 VALUES(1, 1);
        !           720:   }
        !           721: } {0 {}}
        !           722: 
        !           723: 
        !           724: #-------------------------------------------------------------------------
        !           725: # The following tests, fkey2-11.*, test CASCADE actions.
        !           726: #
        !           727: drop_all_tables
        !           728: do_test fkey2-11.1.1 {
        !           729:   execsql {
        !           730:     CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
        !           731:     CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(a) ON UPDATE CASCADE);
        !           732: 
        !           733:     INSERT INTO t1 VALUES(10, 100);
        !           734:     INSERT INTO t2 VALUES(10, 100);
        !           735:     UPDATE t1 SET a = 15;
        !           736:     SELECT * FROM t2;
        !           737:   }
        !           738: } {15 100}
        !           739: 
        !           740: #-------------------------------------------------------------------------
        !           741: # The following tests, fkey2-12.*, test RESTRICT actions.
        !           742: #
        !           743: drop_all_tables
        !           744: do_test fkey2-12.1.1 {
        !           745:   execsql {
        !           746:     CREATE TABLE t1(a, b PRIMARY KEY);
        !           747:     CREATE TABLE t2(
        !           748:       x REFERENCES t1 ON UPDATE RESTRICT DEFERRABLE INITIALLY DEFERRED 
        !           749:     );
        !           750:     INSERT INTO t1 VALUES(1, 'one');
        !           751:     INSERT INTO t1 VALUES(2, 'two');
        !           752:     INSERT INTO t1 VALUES(3, 'three');
        !           753:   }
        !           754: } {}
        !           755: do_test fkey2-12.1.2        !           756:   execsql "BEGIN"
        !           757:   execsql "INSERT INTO t2 VALUES('two')"
        !           758: } {}
        !           759: do_test fkey2-12.1.3        !           760:   execsql "UPDATE t1 SET b = 'four' WHERE b = 'one'"
        !           761: } {}
        !           762: do_test fkey2-12.1.4        !           763:   catchsql "UPDATE t1 SET b = 'five' WHERE b = 'two'"
        !           764: } {1 {foreign key constraint failed}}
        !           765: do_test fkey2-12.1.5        !           766:   execsql "DELETE FROM t1 WHERE b = 'two'"
        !           767: } {}
        !           768: do_test fkey2-12.1.6        !           769:   catchsql "COMMIT"
        !           770: } {1 {foreign key constraint failed}}
        !           771: do_test fkey2-12.1.7        !           772:   execsql {
        !           773:     INSERT INTO t1 VALUES(2, 'two');
        !           774:     COMMIT;
        !           775:   }
        !           776: } {}
        !           777: 
        !           778: drop_all_tables
        !           779: do_test fkey2-12.2.1 {
        !           780:   execsql {
        !           781:     CREATE TABLE t1(x COLLATE NOCASE PRIMARY KEY);
        !           782:     CREATE TRIGGER tt1 AFTER DELETE ON t1 
        !           783:       WHEN EXISTS ( SELECT 1 FROM t2 WHERE old.x = y )
        !           784:     BEGIN
        !           785:       INSERT INTO t1 VALUES(old.x);
        !           786:     END;
        !           787:     CREATE TABLE t2(y REFERENCES t1);
        !           788:     INSERT INTO t1 VALUES('A');
        !           789:     INSERT INTO t1 VALUES('B');
        !           790:     INSERT INTO t2 VALUES('a');
        !           791:     INSERT INTO t2 VALUES('b');
        !           792: 
        !           793:     SELECT * FROM t1;
        !           794:     SELECT * FROM t2;
        !           795:   }
        !           796: } {A B a b}
        !           797: do_test fkey2-12.2.2 {
        !           798:   execsql { DELETE FROM t1 }
        !           799:   execsql {
        !           800:     SELECT * FROM t1;
        !           801:     SELECT * FROM t2;
        !           802:   }
        !           803: } {A B a b}
        !           804: do_test fkey2-12.2.3 {
        !           805:   execsql {
        !           806:     DROP TABLE t2;
        !           807:     CREATE TABLE t2(y REFERENCES t1 ON DELETE RESTRICT);
        !           808:     INSERT INTO t2 VALUES('a');
        !           809:     INSERT INTO t2 VALUES('b');
        !           810:   }
        !           811:   catchsql { DELETE FROM t1 }
        !           812: } {1 {foreign key constraint failed}}
        !           813: do_test fkey2-12.2.4 {
        !           814:   execsql {
        !           815:     SELECT * FROM t1;
        !           816:     SELECT * FROM t2;
        !           817:   }
        !           818: } {A B a b}
        !           819: 
        !           820: drop_all_tables
        !           821: do_test fkey2-12.3.1 {
        !           822:   execsql {
        !           823:     CREATE TABLE up(
        !           824:       c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
        !           825:       c10, c11, c12, c13, c14, c15, c16, c17, c18, c19,
        !           826:       c20, c21, c22, c23, c24, c25, c26, c27, c28, c29,
        !           827:       c30, c31, c32, c33, c34, c35, c36, c37, c38, c39,
        !           828:       PRIMARY KEY(c34, c35)
        !           829:     );
        !           830:     CREATE TABLE down(
        !           831:       c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
        !           832:       c10, c11, c12, c13, c14, c15, c16, c17, c18, c19,
        !           833:       c20, c21, c22, c23, c24, c25, c26, c27, c28, c29,
        !           834:       c30, c31, c32, c33, c34, c35, c36, c37, c38, c39,
        !           835:       FOREIGN KEY(c39, c38) REFERENCES up ON UPDATE CASCADE
        !           836:     );
        !           837:   }
        !           838: } {}
        !           839: do_test fkey2-12.3.2 {
        !           840:   execsql {
        !           841:     INSERT INTO up(c34, c35) VALUES('yes', 'no');
        !           842:     INSERT INTO down(c39, c38) VALUES('yes', 'no');
        !           843:     UPDATE up SET c34 = 'possibly';
        !           844:     SELECT c38, c39 FROM down;
        !           845:     DELETE FROM down;
        !           846:   }
        !           847: } {no possibly}
        !           848: do_test fkey2-12.3.3 {
        !           849:   catchsql { INSERT INTO down(c39, c38) VALUES('yes', 'no') }
        !           850: } {1 {foreign key constraint failed}}
        !           851: do_test fkey2-12.3.4 {
        !           852:   execsql { 
        !           853:     INSERT INTO up(c34, c35) VALUES('yes', 'no');
        !           854:     INSERT INTO down(c39, c38) VALUES('yes', 'no');
        !           855:   }
        !           856:   catchsql { DELETE FROM up WHERE c34 = 'yes' }
        !           857: } {1 {foreign key constraint failed}}
        !           858: do_test fkey2-12.3.5 {
        !           859:   execsql { 
        !           860:     DELETE FROM up WHERE c34 = 'possibly';
        !           861:     SELECT c34, c35 FROM up;
        !           862:     SELECT c39, c38 FROM down;
        !           863:   }
        !           864: } {yes no yes no}
        !           865: 
        !           866: #-------------------------------------------------------------------------
        !           867: # The following tests, fkey2-13.*, test that FK processing is performed
        !           868: # when rows are REPLACEd.
        !           869: #
        !           870: drop_all_tables
        !           871: do_test fkey2-13.1.1 {
        !           872:   execsql {
        !           873:     CREATE TABLE pp(a UNIQUE, b, c, PRIMARY KEY(b, c));
        !           874:     CREATE TABLE cc(d, e, f UNIQUE, FOREIGN KEY(d, e) REFERENCES pp);
        !           875:     INSERT INTO pp VALUES(1, 2, 3);
        !           876:     INSERT INTO cc VALUES(2, 3, 1);
        !           877:   }
        !           878: } {}
        !           879: foreach {tn stmt} {
        !           880:   1   "REPLACE INTO pp VALUES(1, 4, 5)"
        !           881:   2   "REPLACE INTO pp(rowid, a, b, c) VALUES(1, 2, 3, 4)"
        !           882: } {
        !           883:   do_test fkey2-13.1.$tn.1 {
        !           884:     catchsql $stmt
        !           885:   } {1 {foreign key constraint failed}}
        !           886:   do_test fkey2-13.1.$tn.2 {
        !           887:     execsql {
        !           888:       SELECT * FROM pp;
        !           889:       SELECT * FROM cc;
        !           890:     }
        !           891:   } {1 2 3 2 3 1}
        !           892:   do_test fkey2-13.1.$tn.3 {
        !           893:     execsql BEGIN;
        !           894:     catchsql $stmt
        !           895:   } {1 {foreign key constraint failed}}
        !           896:   do_test fkey2-13.1.$tn.4 {
        !           897:     execsql {
        !           898:       COMMIT;
        !           899:       SELECT * FROM pp;
        !           900:       SELECT * FROM cc;
        !           901:     }
        !           902:   } {1 2 3 2 3 1}
        !           903: }
        !           904: do_test fkey2-13.1.3 {
        !           905:   execsql { 
        !           906:     REPLACE INTO pp(rowid, a, b, c) VALUES(1, 2, 2, 3);
        !           907:     SELECT rowid, * FROM pp;
        !           908:     SELECT * FROM cc;
        !           909:   }
        !           910: } {1 2 2 3 2 3 1}
        !           911: do_test fkey2-13.1.4 {
        !           912:   execsql { 
        !           913:     REPLACE INTO pp(rowid, a, b, c) VALUES(2, 2, 2, 3);
        !           914:     SELECT rowid, * FROM pp;
        !           915:     SELECT * FROM cc;
        !           916:   }
        !           917: } {2 2 2 3 2 3 1}
        !           918: 
        !           919: #-------------------------------------------------------------------------
        !           920: # The following tests, fkey2-14.*, test that the "DROP TABLE" and "ALTER
        !           921: # TABLE" commands work as expected wrt foreign key constraints.
        !           922: #
        !           923: # fkey2-14.1*: ALTER TABLE ADD COLUMN
        !           924: # fkey2-14.2*: ALTER TABLE RENAME TABLE
        !           925: # fkey2-14.3*: DROP TABLE
        !           926: #
        !           927: drop_all_tables
        !           928: ifcapable altertable {
        !           929:   do_test fkey2-14.1.1 {
        !           930:     # Adding a column with a REFERENCES clause is not supported.
        !           931:     execsql { 
        !           932:       CREATE TABLE t1(a PRIMARY KEY);
        !           933:       CREATE TABLE t2(a, b);
        !           934:     }
        !           935:     catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
        !           936:   } {0 {}}
        !           937:   do_test fkey2-14.1.2 {
        !           938:     catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
        !           939:   } {0 {}}
        !           940:   do_test fkey2-14.1.3 {
        !           941:     catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
        !           942:   } {0 {}}
        !           943:   do_test fkey2-14.1.4 {
        !           944:     catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
        !           945:   } {1 {Cannot add a REFERENCES column with non-NULL default value}}
        !           946:   do_test fkey2-14.1.5 {
        !           947:     catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
        !           948:   } {1 {Cannot add a REFERENCES column with non-NULL default value}}
        !           949:   do_test fkey2-14.1.6 {
        !           950:     execsql { 
        !           951:       PRAGMA foreign_keys = off;
        !           952:       ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
        !           953:       PRAGMA foreign_keys = on;
        !           954:       SELECT sql FROM sqlite_master WHERE name='t2';
        !           955:     }
        !           956:   } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
        !           957:   
        !           958:   
        !           959:   # Test the sqlite_rename_parent() function directly.
        !           960:   #
        !           961:   proc test_rename_parent {zCreate zOld zNew} {
        !           962:     db eval {SELECT sqlite_rename_parent($zCreate, $zOld, $zNew)}
        !           963:   }
        !           964:   do_test fkey2-14.2.1.1 {
        !           965:     test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
        !           966:   } {{CREATE TABLE t1(a REFERENCES "t3")}}
        !           967:   do_test fkey2-14.2.1.2 {
        !           968:     test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
        !           969:   } {{CREATE TABLE t1(a REFERENCES t2)}}
        !           970:   do_test fkey2-14.2.1.3 {
        !           971:     test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
        !           972:   } {{CREATE TABLE t1(a REFERENCES "t3")}}
        !           973:   
        !           974:   # Test ALTER TABLE RENAME TABLE a bit.
        !           975:   #
        !           976:   do_test fkey2-14.2.2.1 {
        !           977:     drop_all_tables
        !           978:     execsql {
        !           979:       CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1);
        !           980:       CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
        !           981:       CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
        !           982:     }
        !           983:     execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
        !           984:   } [list \
        !           985:     {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)}                     \
        !           986:     {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)}    \
        !           987:     {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)}  \
        !           988:   ]
        !           989:   do_test fkey2-14.2.2.2 {
        !           990:     execsql { ALTER TABLE t1 RENAME TO t4 }
        !           991:     execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
        !           992:   } [list \
        !           993:     {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")}                    \
        !           994:     {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)}     \
        !           995:     {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
        !           996:   ]
        !           997:   do_test fkey2-14.2.2.3 {
        !           998:     catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
        !           999:   } {1 {foreign key constraint failed}}
        !          1000:   do_test fkey2-14.2.2.4 {
        !          1001:     execsql { INSERT INTO t4 VALUES(1, NULL) }
        !          1002:   } {}
        !          1003:   do_test fkey2-14.2.2.5 {
        !          1004:     catchsql { UPDATE t4 SET b = 5 }
        !          1005:   } {1 {foreign key constraint failed}}
        !          1006:   do_test fkey2-14.2.2.6 {
        !          1007:     catchsql { UPDATE t4 SET b = 1 }
        !          1008:   } {0 {}}
        !          1009:   do_test fkey2-14.2.2.7 {
        !          1010:     execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
        !          1011:   } {}
        !          1012: 
        !          1013:   # Repeat for TEMP tables
        !          1014:   #
        !          1015:   drop_all_tables
        !          1016:   do_test fkey2-14.1tmp.1 {
        !          1017:     # Adding a column with a REFERENCES clause is not supported.
        !          1018:     execsql { 
        !          1019:       CREATE TEMP TABLE t1(a PRIMARY KEY);
        !          1020:       CREATE TEMP TABLE t2(a, b);
        !          1021:     }
        !          1022:     catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
        !          1023:   } {0 {}}
        !          1024:   do_test fkey2-14.1tmp.2 {
        !          1025:     catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
        !          1026:   } {0 {}}
        !          1027:   do_test fkey2-14.1tmp.3 {
        !          1028:     catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
        !          1029:   } {0 {}}
        !          1030:   do_test fkey2-14.1tmp.4 {
        !          1031:     catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
        !          1032:   } {1 {Cannot add a REFERENCES column with non-NULL default value}}
        !          1033:   do_test fkey2-14.1tmp.5 {
        !          1034:     catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
        !          1035:   } {1 {Cannot add a REFERENCES column with non-NULL default value}}
        !          1036:   do_test fkey2-14.1tmp.6 {
        !          1037:     execsql { 
        !          1038:       PRAGMA foreign_keys = off;
        !          1039:       ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
        !          1040:       PRAGMA foreign_keys = on;
        !          1041:       SELECT sql FROM sqlite_temp_master WHERE name='t2';
        !          1042:     }
        !          1043:   } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
        !          1044: 
        !          1045:   do_test fkey2-14.2tmp.1.1 {
        !          1046:     test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
        !          1047:   } {{CREATE TABLE t1(a REFERENCES "t3")}}
        !          1048:   do_test fkey2-14.2tmp.1.2 {
        !          1049:     test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
        !          1050:   } {{CREATE TABLE t1(a REFERENCES t2)}}
        !          1051:   do_test fkey2-14.2tmp.1.3 {
        !          1052:     test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
        !          1053:   } {{CREATE TABLE t1(a REFERENCES "t3")}}
        !          1054:   
        !          1055:   # Test ALTER TABLE RENAME TABLE a bit.
        !          1056:   #
        !          1057:   do_test fkey2-14.2tmp.2.1 {
        !          1058:     drop_all_tables
        !          1059:     execsql {
        !          1060:       CREATE TEMP TABLE t1(a PRIMARY KEY, b REFERENCES t1);
        !          1061:       CREATE TEMP TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
        !          1062:       CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
        !          1063:     }
        !          1064:     execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'}
        !          1065:   } [list \
        !          1066:     {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)}                     \
        !          1067:     {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)}    \
        !          1068:     {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)}  \
        !          1069:   ]
        !          1070:   do_test fkey2-14.2tmp.2.2 {
        !          1071:     execsql { ALTER TABLE t1 RENAME TO t4 }
        !          1072:     execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'}
        !          1073:   } [list \
        !          1074:     {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")}                    \
        !          1075:     {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)}     \
        !          1076:     {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
        !          1077:   ]
        !          1078:   do_test fkey2-14.2tmp.2.3 {
        !          1079:     catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
        !          1080:   } {1 {foreign key constraint failed}}
        !          1081:   do_test fkey2-14.2tmp.2.4 {
        !          1082:     execsql { INSERT INTO t4 VALUES(1, NULL) }
        !          1083:   } {}
        !          1084:   do_test fkey2-14.2tmp.2.5 {
        !          1085:     catchsql { UPDATE t4 SET b = 5 }
        !          1086:   } {1 {foreign key constraint failed}}
        !          1087:   do_test fkey2-14.2tmp.2.6 {
        !          1088:     catchsql { UPDATE t4 SET b = 1 }
        !          1089:   } {0 {}}
        !          1090:   do_test fkey2-14.2tmp.2.7 {
        !          1091:     execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
        !          1092:   } {}
        !          1093: 
        !          1094:   # Repeat for ATTACH-ed tables
        !          1095:   #
        !          1096:   drop_all_tables
        !          1097:   do_test fkey2-14.1aux.1 {
        !          1098:     # Adding a column with a REFERENCES clause is not supported.
        !          1099:     execsql { 
        !          1100:       ATTACH ':memory:' AS aux;
        !          1101:       CREATE TABLE aux.t1(a PRIMARY KEY);
        !          1102:       CREATE TABLE aux.t2(a, b);
        !          1103:     }
        !          1104:     catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
        !          1105:   } {0 {}}
        !          1106:   do_test fkey2-14.1aux.2 {
        !          1107:     catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
        !          1108:   } {0 {}}
        !          1109:   do_test fkey2-14.1aux.3 {
        !          1110:     catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
        !          1111:   } {0 {}}
        !          1112:   do_test fkey2-14.1aux.4 {
        !          1113:     catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
        !          1114:   } {1 {Cannot add a REFERENCES column with non-NULL default value}}
        !          1115:   do_test fkey2-14.1aux.5 {
        !          1116:     catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
        !          1117:   } {1 {Cannot add a REFERENCES column with non-NULL default value}}
        !          1118:   do_test fkey2-14.1aux.6 {
        !          1119:     execsql { 
        !          1120:       PRAGMA foreign_keys = off;
        !          1121:       ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
        !          1122:       PRAGMA foreign_keys = on;
        !          1123:       SELECT sql FROM aux.sqlite_master WHERE name='t2';
        !          1124:     }
        !          1125:   } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
        !          1126: 
        !          1127:   do_test fkey2-14.2aux.1.1 {
        !          1128:     test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
        !          1129:   } {{CREATE TABLE t1(a REFERENCES "t3")}}
        !          1130:   do_test fkey2-14.2aux.1.2 {
        !          1131:     test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
        !          1132:   } {{CREATE TABLE t1(a REFERENCES t2)}}
        !          1133:   do_test fkey2-14.2aux.1.3 {
        !          1134:     test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
        !          1135:   } {{CREATE TABLE t1(a REFERENCES "t3")}}
        !          1136:   
        !          1137:   # Test ALTER TABLE RENAME TABLE a bit.
        !          1138:   #
        !          1139:   do_test fkey2-14.2aux.2.1 {
        !          1140:     drop_all_tables
        !          1141:     execsql {
        !          1142:       CREATE TABLE aux.t1(a PRIMARY KEY, b REFERENCES t1);
        !          1143:       CREATE TABLE aux.t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
        !          1144:       CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
        !          1145:     }
        !          1146:     execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
        !          1147:   } [list \
        !          1148:     {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)}                     \
        !          1149:     {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)}    \
        !          1150:     {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)}  \
        !          1151:   ]
        !          1152:   do_test fkey2-14.2aux.2.2 {
        !          1153:     execsql { ALTER TABLE t1 RENAME TO t4 }
        !          1154:     execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
        !          1155:   } [list \
        !          1156:     {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")}                    \
        !          1157:     {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)}     \
        !          1158:     {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
        !          1159:   ]
        !          1160:   do_test fkey2-14.2aux.2.3 {
        !          1161:     catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
        !          1162:   } {1 {foreign key constraint failed}}
        !          1163:   do_test fkey2-14.2aux.2.4 {
        !          1164:     execsql { INSERT INTO t4 VALUES(1, NULL) }
        !          1165:   } {}
        !          1166:   do_test fkey2-14.2aux.2.5 {
        !          1167:     catchsql { UPDATE t4 SET b = 5 }
        !          1168:   } {1 {foreign key constraint failed}}
        !          1169:   do_test fkey2-14.2aux.2.6 {
        !          1170:     catchsql { UPDATE t4 SET b = 1 }
        !          1171:   } {0 {}}
        !          1172:   do_test fkey2-14.2aux.2.7 {
        !          1173:     execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
        !          1174:   } {}
        !          1175: }
        !          1176: 
        !          1177: do_test fkey-2.14.3.1 {
        !          1178:   drop_all_tables
        !          1179:   execsql {
        !          1180:     CREATE TABLE t1(a, b REFERENCES nosuchtable);
        !          1181:     DROP TABLE t1;
        !          1182:   }
        !          1183: } {}
        !          1184: do_test fkey-2.14.3.2 {
        !          1185:   execsql {
        !          1186:     CREATE TABLE t1(a PRIMARY KEY, b);
        !          1187:     INSERT INTO t1 VALUES('a', 1);
        !          1188:     CREATE TABLE t2(x REFERENCES t1);
        !          1189:     INSERT INTO t2 VALUES('a');
        !          1190:   }
        !          1191: } {}
        !          1192: do_test fkey-2.14.3.3 {
        !          1193:   catchsql { DROP TABLE t1 }
        !          1194: } {1 {foreign key constraint failed}}
        !          1195: do_test fkey-2.14.3.4 {
        !          1196:   execsql {
        !          1197:     DELETE FROM t2;
        !          1198:     DROP TABLE t1;
        !          1199:   }
        !          1200: } {}
        !          1201: do_test fkey-2.14.3.4 {
        !          1202:   catchsql { INSERT INTO t2 VALUES('x') }
        !          1203: } {1 {no such table: main.t1}}
        !          1204: do_test fkey-2.14.3.5 {
        !          1205:   execsql {
        !          1206:     CREATE TABLE t1(x PRIMARY KEY);
        !          1207:     INSERT INTO t1 VALUES('x');
        !          1208:   }
        !          1209:   execsql { INSERT INTO t2 VALUES('x') }
        !          1210: } {}
        !          1211: do_test fkey-2.14.3.6 {
        !          1212:   catchsql { DROP TABLE t1 }
        !          1213: } {1 {foreign key constraint failed}}
        !          1214: do_test fkey-2.14.3.7 {
        !          1215:   execsql {
        !          1216:     DROP TABLE t2;
        !          1217:     DROP TABLE t1;
        !          1218:   }
        !          1219: } {}
        !          1220: do_test fkey-2.14.3.8 {
        !          1221:   execsql {
        !          1222:     CREATE TABLE pp(x, y, PRIMARY KEY(x, y));
        !          1223:     CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp(x, z));
        !          1224:   }
        !          1225:   catchsql { INSERT INTO cc VALUES(1, 2) }
        !          1226: } {1 {foreign key mismatch}}
        !          1227: do_test fkey-2.14.3.9 {
        !          1228:   execsql { DROP TABLE cc }
        !          1229: } {}
        !          1230: do_test fkey-2.14.3.10 {
        !          1231:   execsql {
        !          1232:     CREATE TABLE cc(a, b, 
        !          1233:       FOREIGN KEY(a, b) REFERENCES pp DEFERRABLE INITIALLY DEFERRED
        !          1234:     );
        !          1235:   }
        !          1236:   execsql {
        !          1237:     INSERT INTO pp VALUES('a', 'b');
        !          1238:     INSERT INTO cc VALUES('a', 'b');
        !          1239:     BEGIN;
        !          1240:       DROP TABLE pp;
        !          1241:       CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c));
        !          1242:       INSERT INTO pp VALUES(1, 'a', 'b');
        !          1243:     COMMIT;
        !          1244:   }
        !          1245: } {}
        !          1246: do_test fkey-2.14.3.11 {
        !          1247:   execsql { 
        !          1248:     BEGIN;
        !          1249:       DROP TABLE cc;
        !          1250:       DROP TABLE pp;
        !          1251:     COMMIT;
        !          1252:   }
        !          1253: } {}
        !          1254: do_test fkey-2.14.3.12 {
        !          1255:   execsql {
        !          1256:     CREATE TABLE b1(a, b);
        !          1257:     CREATE TABLE b2(a, b REFERENCES b1);
        !          1258:     DROP TABLE b1;
        !          1259:   }
        !          1260: } {}
        !          1261: do_test fkey-2.14.3.13 {
        !          1262:   execsql {
        !          1263:     CREATE TABLE b3(a, b REFERENCES b2 DEFERRABLE INITIALLY DEFERRED);
        !          1264:     DROP TABLE b2;
        !          1265:   }
        !          1266: } {}
        !          1267: 
        !          1268: # Test that nothing goes wrong when dropping a table that refers to a view.
        !          1269: # Or dropping a view that an existing FK (incorrectly) refers to. Or either
        !          1270: # of the above scenarios with a virtual table.
        !          1271: drop_all_tables
        !          1272: do_test fkey-2.14.4.1 {
        !          1273:   execsql {
        !          1274:     CREATE TABLE t1(x REFERENCES v); 
        !          1275:     CREATE VIEW v AS SELECT * FROM t1;
        !          1276:   }
        !          1277: } {}
        !          1278: do_test fkey-2.14.4.2 {
        !          1279:   execsql {
        !          1280:     DROP VIEW v;
        !          1281:   }
        !          1282: } {}
        !          1283: ifcapable vtab {
        !          1284:   register_echo_module db
        !          1285:   do_test fkey-2.14.4.3 {
        !          1286:     execsql { CREATE VIRTUAL TABLE v USING echo(t1) }
        !          1287:   } {}
        !          1288:   do_test fkey-2.14.4.2 {
        !          1289:     execsql {
        !          1290:       DROP TABLE v;
        !          1291:     }
        !          1292:   } {}
        !          1293: }
        !          1294: 
        !          1295: #-------------------------------------------------------------------------
        !          1296: # The following tests, fkey2-15.*, test that unnecessary FK related scans 
        !          1297: # and lookups are avoided when the constraint counters are zero.
        !          1298: #
        !          1299: drop_all_tables
        !          1300: proc execsqlS {zSql} {
        !          1301:   set ::sqlite_search_count 0
        !          1302:   set ::sqlite_found_count 0
        !          1303:   set res [uplevel [list execsql $zSql]]
        !          1304:   concat [expr $::sqlite_found_count + $::sqlite_search_count] $res
        !          1305: }
        !          1306: do_test fkey2-15.1.1 {
        !          1307:   execsql {
        !          1308:     CREATE TABLE pp(a PRIMARY KEY, b);
        !          1309:     CREATE TABLE cc(x, y REFERENCES pp DEFERRABLE INITIALLY DEFERRED);
        !          1310:     INSERT INTO pp VALUES(1, 'one');
        !          1311:     INSERT INTO pp VALUES(2, 'two');
        !          1312:     INSERT INTO cc VALUES('neung', 1);
        !          1313:     INSERT INTO cc VALUES('song', 2);
        !          1314:   }
        !          1315: } {}
        !          1316: do_test fkey2-15.1.2 {
        !          1317:   execsqlS { INSERT INTO pp VALUES(3, 'three') }
        !          1318: } {0}
        !          1319: do_test fkey2-15.1.3 {
        !          1320:   execsql {
        !          1321:     BEGIN;
        !          1322:       INSERT INTO cc VALUES('see', 4);    -- Violates deferred constraint
        !          1323:   }
        !          1324:   execsqlS { INSERT INTO pp VALUES(5, 'five') }
        !          1325: } {2}
        !          1326: do_test fkey2-15.1.4 {
        !          1327:   execsql { DELETE FROM cc WHERE x = 'see' }
        !          1328:   execsqlS { INSERT INTO pp VALUES(6, 'six') }
        !          1329: } {0}
        !          1330: do_test fkey2-15.1.5 {
        !          1331:   execsql COMMIT
        !          1332: } {}
        !          1333: do_test fkey2-15.1.6 {
        !          1334:   execsql BEGIN
        !          1335:   execsqlS {
        !          1336:     DELETE FROM cc WHERE x = 'neung';
        !          1337:     ROLLBACK;
        !          1338:   }
        !          1339: } {1}
        !          1340: do_test fkey2-15.1.7 {
        !          1341:   execsql { 
        !          1342:     BEGIN;
        !          1343:     DELETE FROM pp WHERE a = 2;
        !          1344:   }
        !          1345:   execsqlS {
        !          1346:     DELETE FROM cc WHERE x = 'neung';
        !          1347:     ROLLBACK;
        !          1348:   }
        !          1349: } {2}
        !          1350: 
        !          1351: #-------------------------------------------------------------------------
        !          1352: # This next block of tests, fkey2-16.*, test that rows that refer to
        !          1353: # themselves may be inserted and deleted.
        !          1354: #
        !          1355: foreach {tn zSchema} {
        !          1356:   1 { CREATE TABLE self(a INTEGER PRIMARY KEY, b REFERENCES self(a)) }
        !          1357:   2 { CREATE TABLE self(a PRIMARY KEY, b REFERENCES self(a)) }
        !          1358:   3 { CREATE TABLE self(a UNIQUE, b INTEGER PRIMARY KEY REFERENCES self(a)) }
        !          1359: } {
        !          1360:   drop_all_tables
        !          1361:   do_test fkey2-16.1.$tn.1 {
        !          1362:     execsql $zSchema
        !          1363:     execsql { INSERT INTO self VALUES(13, 13) }
        !          1364:   } {}
        !          1365:   do_test fkey2-16.1.$tn.2 {
        !          1366:     execsql { UPDATE self SET a = 14, b = 14 }
        !          1367:   } {}
        !          1368: 
        !          1369:   do_test fkey2-16.1.$tn.3 {
        !          1370:     catchsql { UPDATE self SET b = 15 }
        !          1371:   } {1 {foreign key constraint failed}}
        !          1372: 
        !          1373:   do_test fkey2-16.1.$tn.4 {
        !          1374:     catchsql { UPDATE self SET a = 15 }
        !          1375:   } {1 {foreign key constraint failed}}
        !          1376: 
        !          1377:   do_test fkey2-16.1.$tn.5 {
        !          1378:     catchsql { UPDATE self SET a = 15, b = 16 }
        !          1379:   } {1 {foreign key constraint failed}}
        !          1380: 
        !          1381:   do_test fkey2-16.1.$tn.6 {
        !          1382:     catchsql { UPDATE self SET a = 17, b = 17 }
        !          1383:   } {0 {}}
        !          1384: 
        !          1385:   do_test fkey2-16.1.$tn.7 {
        !          1386:     execsql { DELETE FROM self }
        !          1387:   } {}
        !          1388:   do_test fkey2-16.1.$tn.8 {
        !          1389:     catchsql { INSERT INTO self VALUES(20, 21) }
        !          1390:   } {1 {foreign key constraint failed}}
        !          1391: }
        !          1392: 
        !          1393: #-------------------------------------------------------------------------
        !          1394: # This next block of tests, fkey2-17.*, tests that if "PRAGMA count_changes"
        !          1395: # is turned on statements that violate immediate FK constraints return
        !          1396: # SQLITE_CONSTRAINT immediately, not after returning a number of rows.
        !          1397: # Whereas statements that violate deferred FK constraints return the number
        !          1398: # of rows before failing.
        !          1399: #
        !          1400: # Also test that rows modified by FK actions are not counted in either the
        !          1401: # returned row count or the values returned by sqlite3_changes(). Like
        !          1402: # trigger related changes, they are included in sqlite3_total_changes() though.
        !          1403: #
        !          1404: drop_all_tables
        !          1405: do_test fkey2-17.1.1 {
        !          1406:   execsql { PRAGMA count_changes = 1 }
        !          1407:   execsql { 
        !          1408:     CREATE TABLE one(a, b, c, UNIQUE(b, c));
        !          1409:     CREATE TABLE two(d, e, f, FOREIGN KEY(e, f) REFERENCES one(b, c));
        !          1410:     INSERT INTO one VALUES(1, 2, 3);
        !          1411:   }
        !          1412: } {1}
        !          1413: do_test fkey2-17.1.2 {
        !          1414:   set STMT [sqlite3_prepare_v2 db "INSERT INTO two VALUES(4, 5, 6)" -1 dummy]
        !          1415:   sqlite3_step $STMT
        !          1416: } {SQLITE_CONSTRAINT}
        !          1417: ifcapable autoreset {
        !          1418:   do_test fkey2-17.1.3 {
        !          1419:     sqlite3_step $STMT
        !          1420:   } {SQLITE_CONSTRAINT}
        !          1421: } else {
        !          1422:   do_test fkey2-17.1.3 {
        !          1423:     sqlite3_step $STMT
        !          1424:   } {SQLITE_MISUSE}
        !          1425: }
        !          1426: do_test fkey2-17.1.4 {
        !          1427:   sqlite3_finalize $STMT
        !          1428: } {SQLITE_CONSTRAINT}
        !          1429: do_test fkey2-17.1.5 {
        !          1430:   execsql {
        !          1431:     INSERT INTO one VALUES(2, 3, 4);
        !          1432:     INSERT INTO one VALUES(3, 4, 5);
        !          1433:     INSERT INTO two VALUES(1, 2, 3);
        !          1434:     INSERT INTO two VALUES(2, 3, 4);
        !          1435:     INSERT INTO two VALUES(3, 4, 5);
        !          1436:   }
        !          1437: } {1 1 1 1 1}
        !          1438: do_test fkey2-17.1.6 {
        !          1439:   catchsql {
        !          1440:     BEGIN;
        !          1441:       INSERT INTO one VALUES(0, 0, 0);
        !          1442:       UPDATE two SET e=e+1, f=f+1;
        !          1443:   }
        !          1444: } {1 {foreign key constraint failed}}
        !          1445: do_test fkey2-17.1.7 {
        !          1446:   execsql { SELECT * FROM one }
        !          1447: } {1 2 3 2 3 4 3 4 5 0 0 0}
        !          1448: do_test fkey2-17.1.8 {
        !          1449:   execsql { SELECT * FROM two }
        !          1450: } {1 2 3 2 3 4 3 4 5}
        !          1451: do_test fkey2-17.1.9 {
        !          1452:   execsql COMMIT
        !          1453: } {}
        !          1454: do_test fkey2-17.1.10 {
        !          1455:   execsql {
        !          1456:     CREATE TABLE three(
        !          1457:       g, h, i, 
        !          1458:       FOREIGN KEY(h, i) REFERENCES one(b, c) DEFERRABLE INITIALLY DEFERRED
        !          1459:     );
        !          1460:   }
        !          1461: } {}
        !          1462: do_test fkey2-17.1.11 {
        !          1463:   set STMT [sqlite3_prepare_v2 db "INSERT INTO three VALUES(7, 8, 9)" -1 dummy]
        !          1464:   sqlite3_step $STMT
        !          1465: } {SQLITE_ROW}
        !          1466: do_test fkey2-17.1.12 {
        !          1467:   sqlite3_column_text $STMT 0
        !          1468: } {1}
        !          1469: do_test fkey2-17.1.13 {
        !          1470:   sqlite3_step $STMT
        !          1471: } {SQLITE_CONSTRAINT}
        !          1472: do_test fkey2-17.1.14 {
        !          1473:   sqlite3_finalize $STMT
        !          1474: } {SQLITE_CONSTRAINT}
        !          1475: 
        !          1476: drop_all_tables
        !          1477: do_test fkey2-17.2.1 {
        !          1478:   execsql {
        !          1479:     CREATE TABLE high("a'b!" PRIMARY KEY, b);
        !          1480:     CREATE TABLE low(
        !          1481:       c, 
        !          1482:       "d&6" REFERENCES high ON UPDATE CASCADE ON DELETE CASCADE
        !          1483:     );
        !          1484:   }
        !          1485: } {}
        !          1486: do_test fkey2-17.2.2 {
        !          1487:   execsql {
        !          1488:     INSERT INTO high VALUES('a', 'b');
        !          1489:     INSERT INTO low VALUES('b', 'a');
        !          1490:   }
        !          1491:   db changes
        !          1492: } {1}
        !          1493: set nTotal [db total_changes]
        !          1494: do_test fkey2-17.2.3 {
        !          1495:   execsql { UPDATE high SET "a'b!" = 'c' }
        !          1496: } {1}
        !          1497: do_test fkey2-17.2.4 {
        !          1498:   db changes
        !          1499: } {1}
        !          1500: do_test fkey2-17.2.5 {
        !          1501:   expr [db total_changes] - $nTotal
        !          1502: } {2}
        !          1503: do_test fkey2-17.2.6 {
        !          1504:   execsql { SELECT * FROM high ; SELECT * FROM low }
        !          1505: } {c b b c}
        !          1506: do_test fkey2-17.2.7 {
        !          1507:   execsql { DELETE FROM high }
        !          1508: } {1}
        !          1509: do_test fkey2-17.2.8 {
        !          1510:   db changes
        !          1511: } {1}
        !          1512: do_test fkey2-17.2.9 {
        !          1513:   expr [db total_changes] - $nTotal
        !          1514: } {4}
        !          1515: do_test fkey2-17.2.10 {
        !          1516:   execsql { SELECT * FROM high ; SELECT * FROM low }
        !          1517: } {}
        !          1518: execsql { PRAGMA count_changes = 0 }
        !          1519: 
        !          1520: #-------------------------------------------------------------------------
        !          1521: # Test that the authorization callback works.
        !          1522: #
        !          1523: 
        !          1524: ifcapable auth {
        !          1525:   do_test fkey2-18.1 {
        !          1526:     execsql {
        !          1527:       CREATE TABLE long(a, b PRIMARY KEY, c);
        !          1528:       CREATE TABLE short(d, e, f REFERENCES long);
        !          1529:       CREATE TABLE mid(g, h, i REFERENCES long DEFERRABLE INITIALLY DEFERRED);
        !          1530:     }
        !          1531:   } {}
        !          1532: 
        !          1533:   proc auth {args} {eval lappend ::authargs $args ; return SQLITE_OK}
        !          1534:   db auth auth
        !          1535: 
        !          1536:   # An insert on the parent table must read the child key of any deferred
        !          1537:   # foreign key constraints. But not the child key of immediate constraints.
        !          1538:   set authargs {}
        !          1539:   do_test fkey2-18.2 {
        !          1540:     execsql { INSERT INTO long VALUES(1, 2, 3) }
        !          1541:     set authargs
        !          1542:   } {SQLITE_INSERT long {} main {} SQLITE_READ mid i main {}}
        !          1543: 
        !          1544:   # An insert on the child table of an immediate constraint must read the
        !          1545:   # parent key columns (to see if it is a violation or not).
        !          1546:   set authargs {}
        !          1547:   do_test fkey2-18.3 {
        !          1548:     execsql { INSERT INTO short VALUES(1, 3, 2) }
        !          1549:     set authargs
        !          1550:   } {SQLITE_INSERT short {} main {} SQLITE_READ long b main {}}
        !          1551:   
        !          1552:   # As must an insert on the child table of a deferred constraint.
        !          1553:   set authargs {}
        !          1554:   do_test fkey2-18.4 {
        !          1555:     execsql { INSERT INTO mid VALUES(1, 3, 2) }
        !          1556:     set authargs
        !          1557:   } {SQLITE_INSERT mid {} main {} SQLITE_READ long b main {}}
        !          1558: 
        !          1559:   do_test fkey2-18.5 {
        !          1560:     execsql {
        !          1561:       CREATE TABLE nought(a, b PRIMARY KEY, c);
        !          1562:       CREATE TABLE cross(d, e, f,
        !          1563:         FOREIGN KEY(e) REFERENCES nought(b) ON UPDATE CASCADE
        !          1564:       );
        !          1565:     }
        !          1566:     execsql { INSERT INTO nought VALUES(2, 1, 2) }
        !          1567:     execsql { INSERT INTO cross VALUES(0, 1, 0) }
        !          1568:     set authargs [list]
        !          1569:     execsql { UPDATE nought SET b = 5 }
        !          1570:     set authargs
        !          1571:   } {SQLITE_UPDATE nought b main {} SQLITE_READ cross e main {} SQLITE_READ cross e main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {} SQLITE_UPDATE cross e main {} SQLITE_READ nought b main {} SQLITE_READ cross e main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {}}
        !          1572: 
        !          1573:   do_test fkey2-18.6 {
        !          1574:     execsql {SELECT * FROM cross}
        !          1575:   } {0 5 0}
        !          1576: 
        !          1577:   do_test fkey2-18.7 {
        !          1578:     execsql {
        !          1579:       CREATE TABLE one(a INTEGER PRIMARY KEY, b);
        !          1580:       CREATE TABLE two(b, c REFERENCES one);
        !          1581:       INSERT INTO one VALUES(101, 102);
        !          1582:     }
        !          1583:     set authargs [list]
        !          1584:     execsql { INSERT INTO two VALUES(100, 101); }
        !          1585:     set authargs
        !          1586:   } {SQLITE_INSERT two {} main {} SQLITE_READ one a main {}}
        !          1587: 
        !          1588:   # Return SQLITE_IGNORE to requests to read from the parent table. This
        !          1589:   # causes inserts of non-NULL keys into the child table to fail.
        !          1590:   #
        !          1591:   rename auth {}
        !          1592:   proc auth {args} {
        !          1593:     if {[lindex $args 1] == "long"} {return SQLITE_IGNORE}
        !          1594:     return SQLITE_OK
        !          1595:   }
        !          1596:   do_test fkey2-18.8 {
        !          1597:     catchsql { INSERT INTO short VALUES(1, 3, 2) }
        !          1598:   } {1 {foreign key constraint failed}}
        !          1599:   do_test fkey2-18.9 {
        !          1600:     execsql { INSERT INTO short VALUES(1, 3, NULL) }
        !          1601:   } {}
        !          1602:   do_test fkey2-18.10 {
        !          1603:     execsql { SELECT * FROM short }
        !          1604:   } {1 3 2 1 3 {}}
        !          1605:   do_test fkey2-18.11 {
        !          1606:     catchsql { UPDATE short SET f = 2 WHERE f IS NULL }
        !          1607:   } {1 {foreign key constraint failed}}
        !          1608: 
        !          1609:   db auth {}
        !          1610:   unset authargs
        !          1611: }
        !          1612: 
        !          1613: 
        !          1614: do_test fkey2-19.1 {
        !          1615:   execsql {
        !          1616:     CREATE TABLE main(id INTEGER PRIMARY KEY);
        !          1617:     CREATE TABLE sub(id INT REFERENCES main(id));
        !          1618:     INSERT INTO main VALUES(1);
        !          1619:     INSERT INTO main VALUES(2);
        !          1620:     INSERT INTO sub VALUES(2);
        !          1621:   }
        !          1622: } {}
        !          1623: do_test fkey2-19.2 {
        !          1624:   set S [sqlite3_prepare_v2 db "DELETE FROM main WHERE id = ?" -1 dummy]
        !          1625:   sqlite3_bind_int $S 1 2
        !          1626:   sqlite3_step $S
        !          1627: } {SQLITE_CONSTRAINT}
        !          1628: do_test fkey2-19.3 {
        !          1629:   sqlite3_reset $S
        !          1630: } {SQLITE_CONSTRAINT}
        !          1631: do_test fkey2-19.4 {
        !          1632:   sqlite3_bind_int $S 1 1
        !          1633:   sqlite3_step $S
        !          1634: } {SQLITE_DONE}
        !          1635: do_test fkey2-19.4 {
        !          1636:   sqlite3_finalize $S
        !          1637: } {SQLITE_OK}
        !          1638: 
        !          1639: drop_all_tables
        !          1640: do_test fkey2-20.1 {
        !          1641:   execsql {
        !          1642:     CREATE TABLE pp(a PRIMARY KEY, b);
        !          1643:     CREATE TABLE cc(c PRIMARY KEY, d REFERENCES pp);
        !          1644:   }
        !          1645: } {}
        !          1646: 
        !          1647: foreach {tn insert} {
        !          1648:   1 "INSERT"
        !          1649:   2 "INSERT OR IGNORE"
        !          1650:   3 "INSERT OR ABORT"
        !          1651:   4 "INSERT OR ROLLBACK"
        !          1652:   5 "INSERT OR REPLACE"
        !          1653:   6 "INSERT OR FAIL"
        !          1654: } {
        !          1655:   do_test fkey2-20.2.$tn.1 {
        !          1656:     catchsql "$insert INTO cc VALUES(1, 2)"
        !          1657:   } {1 {foreign key constraint failed}}
        !          1658:   do_test fkey2-20.2.$tn.2 {
        !          1659:     execsql { SELECT * FROM cc }
        !          1660:   } {}
        !          1661:   do_test fkey2-20.2.$tn.3 {
        !          1662:     execsql {
        !          1663:       BEGIN;
        !          1664:         INSERT INTO pp VALUES(2, 'two');
        !          1665:         INSERT INTO cc VALUES(1, 2);
        !          1666:     }
        !          1667:     catchsql "$insert INTO cc VALUES(3, 4)"
        !          1668:   } {1 {foreign key constraint failed}}
        !          1669:   do_test fkey2-20.2.$tn.4 {
        !          1670:     execsql { COMMIT ; SELECT * FROM cc }
        !          1671:   } {1 2}
        !          1672:   do_test fkey2-20.2.$tn.5 {
        !          1673:     execsql { DELETE FROM cc ; DELETE FROM pp }
        !          1674:   } {}
        !          1675: }
        !          1676: 
        !          1677: foreach {tn update} {
        !          1678:   1 "UPDATE"
        !          1679:   2 "UPDATE OR IGNORE"
        !          1680:   3 "UPDATE OR ABORT"
        !          1681:   4 "UPDATE OR ROLLBACK"
        !          1682:   5 "UPDATE OR REPLACE"
        !          1683:   6 "UPDATE OR FAIL"
        !          1684: } {
        !          1685:   do_test fkey2-20.3.$tn.1 {
        !          1686:     execsql {
        !          1687:       INSERT INTO pp VALUES(2, 'two');
        !          1688:       INSERT INTO cc VALUES(1, 2);
        !          1689:     }
        !          1690:   } {}
        !          1691:   do_test fkey2-20.3.$tn.2 {
        !          1692:     catchsql "$update pp SET a = 1"
        !          1693:   } {1 {foreign key constraint failed}}
        !          1694:   do_test fkey2-20.3.$tn.3 {
        !          1695:     execsql { SELECT * FROM pp }
        !          1696:   } {2 two}
        !          1697:   do_test fkey2-20.3.$tn.4 {
        !          1698:     catchsql "$update cc SET d = 1"
        !          1699:   } {1 {foreign key constraint failed}}
        !          1700:   do_test fkey2-20.3.$tn.5 {
        !          1701:     execsql { SELECT * FROM cc }
        !          1702:   } {1 2}
        !          1703:   do_test fkey2-20.3.$tn.6 {
        !          1704:     execsql {
        !          1705:       BEGIN;
        !          1706:         INSERT INTO pp VALUES(3, 'three');
        !          1707:     }
        !          1708:     catchsql "$update pp SET a = 1 WHERE a = 2"
        !          1709:   } {1 {foreign key constraint failed}}
        !          1710:   do_test fkey2-20.3.$tn.7 {
        !          1711:     execsql { COMMIT ; SELECT * FROM pp }
        !          1712:   } {2 two 3 three}
        !          1713:   do_test fkey2-20.3.$tn.8 {
        !          1714:     execsql {
        !          1715:       BEGIN;
        !          1716:         INSERT INTO cc VALUES(2, 2);
        !          1717:     }
        !          1718:     catchsql "$update cc SET d = 1 WHERE c = 1"
        !          1719:   } {1 {foreign key constraint failed}}
        !          1720:   do_test fkey2-20.3.$tn.9 {
        !          1721:     execsql { COMMIT ; SELECT * FROM cc }
        !          1722:   } {1 2 2 2}
        !          1723:   do_test fkey2-20.3.$tn.10 {
        !          1724:     execsql { DELETE FROM cc ; DELETE FROM pp }
        !          1725:   } {}
        !          1726: }
        !          1727: 
        !          1728: #-------------------------------------------------------------------------
        !          1729: # The following block of tests, those prefixed with "fkey2-genfkey.", are 
        !          1730: # the same tests that were used to test the ".genfkey" command provided 
        !          1731: # by the shell tool. So these tests show that the built-in foreign key 
        !          1732: # implementation is more or less compatible with the triggers generated 
        !          1733: # by genfkey.
        !          1734: #
        !          1735: drop_all_tables
        !          1736: do_test fkey2-genfkey.1.1 {
        !          1737:   execsql {
        !          1738:     CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
        !          1739:     CREATE TABLE t2(e REFERENCES t1, f);
        !          1740:     CREATE TABLE t3(g, h, i, FOREIGN KEY (h, i) REFERENCES t1(b, c));
        !          1741:   }
        !          1742: } {}
        !          1743: do_test fkey2-genfkey.1.2 {
        !          1744:   catchsql { INSERT INTO t2 VALUES(1, 2) }
        !          1745: } {1 {foreign key constraint failed}}
        !          1746: do_test fkey2-genfkey.1.3 {
        !          1747:   execsql {
        !          1748:     INSERT INTO t1 VALUES(1, 2, 3);
        !          1749:     INSERT INTO t2 VALUES(1, 2);
        !          1750:   }
        !          1751: } {}
        !          1752: do_test fkey2-genfkey.1.4 {
        !          1753:   execsql { INSERT INTO t2 VALUES(NULL, 3) }
        !          1754: } {}
        !          1755: do_test fkey2-genfkey.1.5 {
        !          1756:   catchsql { UPDATE t2 SET e = 5 WHERE e IS NULL }
        !          1757: } {1 {foreign key constraint failed}}
        !          1758: do_test fkey2-genfkey.1.6 {
        !          1759:   execsql { UPDATE t2 SET e = 1 WHERE e IS NULL }
        !          1760: } {}
        !          1761: do_test fkey2-genfkey.1.7 {
        !          1762:   execsql { UPDATE t2 SET e = NULL WHERE f = 3 }
        !          1763: } {}
        !          1764: do_test fkey2-genfkey.1.8 {
        !          1765:   catchsql { UPDATE t1 SET a = 10 }
        !          1766: } {1 {foreign key constraint failed}}
        !          1767: do_test fkey2-genfkey.1.9 {
        !          1768:   catchsql { UPDATE t1 SET a = NULL }
        !          1769: } {1 {datatype mismatch}}
        !          1770: do_test fkey2-genfkey.1.10 {
        !          1771:   catchsql { DELETE FROM t1 }
        !          1772: } {1 {foreign key constraint failed}}
        !          1773: do_test fkey2-genfkey.1.11 {
        !          1774:   execsql { UPDATE t2 SET e = NULL }
        !          1775: } {}
        !          1776: do_test fkey2-genfkey.1.12 {
        !          1777:   execsql { 
        !          1778:     UPDATE t1 SET a = 10;
        !          1779:     DELETE FROM t1;
        !          1780:     DELETE FROM t2;
        !          1781:   }
        !          1782: } {}
        !          1783: do_test fkey2-genfkey.1.13 {
        !          1784:   execsql {
        !          1785:     INSERT INTO t3 VALUES(1, NULL, NULL);
        !          1786:     INSERT INTO t3 VALUES(1, 2, NULL);
        !          1787:     INSERT INTO t3 VALUES(1, NULL, 3);
        !          1788:   }
        !          1789: } {}
        !          1790: do_test fkey2-genfkey.1.14 {
        !          1791:   catchsql { INSERT INTO t3 VALUES(3, 1, 4) }
        !          1792: } {1 {foreign key constraint failed}}
        !          1793: do_test fkey2-genfkey.1.15 {
        !          1794:   execsql { 
        !          1795:     INSERT INTO t1 VALUES(1, 1, 4);
        !          1796:     INSERT INTO t3 VALUES(3, 1, 4);
        !          1797:   }
        !          1798: } {}
        !          1799: do_test fkey2-genfkey.1.16 {
        !          1800:   catchsql { DELETE FROM t1 }
        !          1801: } {1 {foreign key constraint failed}}
        !          1802: do_test fkey2-genfkey.1.17 {
        !          1803:   catchsql { UPDATE t1 SET b = 10}
        !          1804: } {1 {foreign key constraint failed}}
        !          1805: do_test fkey2-genfkey.1.18 {
        !          1806:   execsql { UPDATE t1 SET a = 10}
        !          1807: } {}
        !          1808: do_test fkey2-genfkey.1.19 {
        !          1809:   catchsql { UPDATE t3 SET h = 'hello' WHERE i = 3}
        !          1810: } {1 {foreign key constraint failed}}
        !          1811: 
        !          1812: drop_all_tables
        !          1813: do_test fkey2-genfkey.2.1 {
        !          1814:   execsql {
        !          1815:     CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
        !          1816:     CREATE TABLE t2(e REFERENCES t1 ON UPDATE CASCADE ON DELETE CASCADE, f);
        !          1817:     CREATE TABLE t3(g, h, i, 
        !          1818:         FOREIGN KEY (h, i) 
        !          1819:         REFERENCES t1(b, c) ON UPDATE CASCADE ON DELETE CASCADE
        !          1820:     );
        !          1821:   }
        !          1822: } {}
        !          1823: do_test fkey2-genfkey.2.2 {
        !          1824:   execsql {
        !          1825:     INSERT INTO t1 VALUES(1, 2, 3);
        !          1826:     INSERT INTO t1 VALUES(4, 5, 6);
        !          1827:     INSERT INTO t2 VALUES(1, 'one');
        !          1828:     INSERT INTO t2 VALUES(4, 'four');
        !          1829:   }
        !          1830: } {}
        !          1831: do_test fkey2-genfkey.2.3 {
        !          1832:   execsql {
        !          1833:     UPDATE t1 SET a = 2 WHERE a = 1;
        !          1834:     SELECT * FROM t2;
        !          1835:   }
        !          1836: } {2 one 4 four}
        !          1837: do_test fkey2-genfkey.2.4 {
        !          1838:   execsql {
        !          1839:     DELETE FROM t1 WHERE a = 4;
        !          1840:     SELECT * FROM t2;
        !          1841:   }
        !          1842: } {2 one}
        !          1843: 
        !          1844: do_test fkey2-genfkey.2.5 {
        !          1845:   execsql {
        !          1846:     INSERT INTO t3 VALUES('hello', 2, 3);
        !          1847:     UPDATE t1 SET c = 2;
        !          1848:     SELECT * FROM t3;
        !          1849:   }
        !          1850: } {hello 2 2}
        !          1851: do_test fkey2-genfkey.2.6 {
        !          1852:   execsql {
        !          1853:     DELETE FROM t1;
        !          1854:     SELECT * FROM t3;
        !          1855:   }
        !          1856: } {}
        !          1857: 
        !          1858: drop_all_tables
        !          1859: do_test fkey2-genfkey.3.1 {
        !          1860:   execsql {
        !          1861:     CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(c, b));
        !          1862:     CREATE TABLE t2(e REFERENCES t1 ON UPDATE SET NULL ON DELETE SET NULL, f);
        !          1863:     CREATE TABLE t3(g, h, i, 
        !          1864:         FOREIGN KEY (h, i) 
        !          1865:         REFERENCES t1(b, c) ON UPDATE SET NULL ON DELETE SET NULL
        !          1866:     );
        !          1867:   }
        !          1868: } {}
        !          1869: do_test fkey2-genfkey.3.2 {
        !          1870:   execsql {
        !          1871:     INSERT INTO t1 VALUES(1, 2, 3);
        !          1872:     INSERT INTO t1 VALUES(4, 5, 6);
        !          1873:     INSERT INTO t2 VALUES(1, 'one');
        !          1874:     INSERT INTO t2 VALUES(4, 'four');
        !          1875:   }
        !          1876: } {}
        !          1877: do_test fkey2-genfkey.3.3 {
        !          1878:   execsql {
        !          1879:     UPDATE t1 SET a = 2 WHERE a = 1;
        !          1880:     SELECT * FROM t2;
        !          1881:   }
        !          1882: } {{} one 4 four}
        !          1883: do_test fkey2-genfkey.3.4 {
        !          1884:   execsql {
        !          1885:     DELETE FROM t1 WHERE a = 4;
        !          1886:     SELECT * FROM t2;
        !          1887:   }
        !          1888: } {{} one {} four}
        !          1889: do_test fkey2-genfkey.3.5 {
        !          1890:   execsql {
        !          1891:     INSERT INTO t3 VALUES('hello', 2, 3);
        !          1892:     UPDATE t1 SET c = 2;
        !          1893:     SELECT * FROM t3;
        !          1894:   }
        !          1895: } {hello {} {}}
        !          1896: do_test fkey2-genfkey.3.6 {
        !          1897:   execsql {
        !          1898:     UPDATE t3 SET h = 2, i = 2;
        !          1899:     DELETE FROM t1;
        !          1900:     SELECT * FROM t3;
        !          1901:   }
        !          1902: } {hello {} {}}
        !          1903: 
        !          1904: #-------------------------------------------------------------------------
        !          1905: # Verify that ticket dd08e5a988d00decc4a543daa8dbbfab9c577ad8 has been
        !          1906: # fixed.
        !          1907: #
        !          1908: do_test fkey2-dd08e5.1.1 {
        !          1909:   execsql {
        !          1910:     PRAGMA foreign_keys=ON;
        !          1911:     CREATE TABLE tdd08(a INTEGER PRIMARY KEY, b);
        !          1912:     CREATE UNIQUE INDEX idd08 ON tdd08(a,b);
        !          1913:     INSERT INTO tdd08 VALUES(200,300);
        !          1914: 
        !          1915:     CREATE TABLE tdd08_b(w,x,y, FOREIGN KEY(x,y) REFERENCES tdd08(a,b));
        !          1916:     INSERT INTO tdd08_b VALUES(100,200,300);
        !          1917:   }
        !          1918: } {}
        !          1919: do_test fkey2-dd08e5.1.2 {
        !          1920:   catchsql {
        !          1921:     DELETE FROM tdd08;
        !          1922:   }
        !          1923: } {1 {foreign key constraint failed}}
        !          1924: do_test fkey2-dd08e5.1.3 {
        !          1925:   execsql {
        !          1926:     SELECT * FROM tdd08;
        !          1927:   }
        !          1928: } {200 300}
        !          1929: do_test fkey2-dd08e5.1.4 {
        !          1930:   catchsql {
        !          1931:     INSERT INTO tdd08_b VALUES(400,500,300);
        !          1932:   }
        !          1933: } {1 {foreign key constraint failed}}
        !          1934: do_test fkey2-dd08e5.1.5 {
        !          1935:   catchsql {
        !          1936:     UPDATE tdd08_b SET x=x+1;
        !          1937:   }
        !          1938: } {1 {foreign key constraint failed}}
        !          1939: do_test fkey2-dd08e5.1.6 {
        !          1940:   catchsql {
        !          1941:     UPDATE tdd08 SET a=a+1;
        !          1942:   }
        !          1943: } {1 {foreign key constraint failed}}
        !          1944: 
        !          1945: #-------------------------------------------------------------------------
        !          1946: # Verify that ticket ce7c133ea6cc9ccdc1a60d80441f80b6180f5eba
        !          1947: # fixed.
        !          1948: #
        !          1949: do_test fkey2-ce7c13.1.1 {
        !          1950:   execsql {
        !          1951:     CREATE TABLE tce71(a INTEGER PRIMARY KEY, b);
        !          1952:     CREATE UNIQUE INDEX ice71 ON tce71(a,b);
        !          1953:     INSERT INTO tce71 VALUES(100,200);
        !          1954:     CREATE TABLE tce72(w, x, y, FOREIGN KEY(x,y) REFERENCES tce71(a,b));
        !          1955:     INSERT INTO tce72 VALUES(300,100,200);
        !          1956:     UPDATE tce71 set b = 200 where a = 100;
        !          1957:     SELECT * FROM tce71, tce72;
        !          1958:   }
        !          1959: } {100 200 300 100 200}
        !          1960: do_test fkey2-ce7c13.1.2 {
        !          1961:   catchsql {
        !          1962:     UPDATE tce71 set b = 201 where a = 100;
        !          1963:   }
        !          1964: } {1 {foreign key constraint failed}}
        !          1965: do_test fkey2-ce7c13.1.3 {
        !          1966:   catchsql {
        !          1967:     UPDATE tce71 set a = 101 where a = 100;
        !          1968:   }
        !          1969: } {1 {foreign key constraint failed}}
        !          1970: do_test fkey2-ce7c13.1.4 {
        !          1971:   execsql {
        !          1972:     CREATE TABLE tce73(a INTEGER PRIMARY KEY, b, UNIQUE(a,b));
        !          1973:     INSERT INTO tce73 VALUES(100,200);
        !          1974:     CREATE TABLE tce74(w, x, y, FOREIGN KEY(x,y) REFERENCES tce73(a,b));
        !          1975:     INSERT INTO tce74 VALUES(300,100,200);
        !          1976:     UPDATE tce73 set b = 200 where a = 100;
        !          1977:     SELECT * FROM tce73, tce74;
        !          1978:   }
        !          1979: } {100 200 300 100 200}
        !          1980: do_test fkey2-ce7c13.1.5 {
        !          1981:   catchsql {
        !          1982:     UPDATE tce73 set b = 201 where a = 100;
        !          1983:   }
        !          1984: } {1 {foreign key constraint failed}}
        !          1985: do_test fkey2-ce7c13.1.6 {
        !          1986:   catchsql {
        !          1987:     UPDATE tce73 set a = 101 where a = 100;
        !          1988:   }
        !          1989: } {1 {foreign key constraint failed}}
        !          1990: 
        !          1991: finish_test

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>