xref: /sqlite-3.40.0/test/fkey2.test (revision 92e21ef0)
11da40a38Sdan# 2009 September 15
21da40a38Sdan#
31da40a38Sdan# The author disclaims copyright to this source code.  In place of
41da40a38Sdan# a legal notice, here is a blessing:
51da40a38Sdan#
61da40a38Sdan#    May you do good and not evil.
71da40a38Sdan#    May you find forgiveness for yourself and forgive others.
81da40a38Sdan#    May you share freely, never taking more than you give.
91da40a38Sdan#
101da40a38Sdan#***********************************************************************
111da40a38Sdan# This file implements regression tests for SQLite library.
121da40a38Sdan#
131da40a38Sdan# This file implements tests for foreign keys.
141da40a38Sdan#
151da40a38Sdan
161da40a38Sdanset testdir [file dirname $argv0]
171da40a38Sdansource $testdir/tester.tcl
181da40a38Sdan
1975cbd984Sdanifcapable {!foreignkey||!trigger} {
2075cbd984Sdan  finish_test
2175cbd984Sdan  return
2275cbd984Sdan}
2375cbd984Sdan
241da40a38Sdan#-------------------------------------------------------------------------
251da40a38Sdan# Test structure:
261da40a38Sdan#
271da40a38Sdan# fkey2-1.*: Simple tests to check that immediate and deferred foreign key
281da40a38Sdan#            constraints work when not inside a transaction.
291da40a38Sdan#
301da40a38Sdan# fkey2-2.*: Tests to verify that deferred foreign keys work inside
311da40a38Sdan#            explicit transactions (i.e that processing really is deferred).
321da40a38Sdan#
331da40a38Sdan# fkey2-3.*: Tests that a statement transaction is rolled back if an
341da40a38Sdan#            immediate foreign key constraint is violated.
351da40a38Sdan#
361da40a38Sdan# fkey2-4.*: Test that FK actions may recurse even when recursive triggers
371da40a38Sdan#            are disabled.
381da40a38Sdan#
391da40a38Sdan# fkey2-5.*: Check that if foreign-keys are enabled, it is not possible
401da40a38Sdan#            to write to an FK column using the incremental blob API.
411da40a38Sdan#
4275cbd984Sdan# fkey2-6.*: Test that FK processing is automatically disabled when
4375cbd984Sdan#            running VACUUM.
4475cbd984Sdan#
453606264bSdan# fkey2-7.*: Test using an IPK as the key in the child (referencing) table.
463606264bSdan#
4729c7f9caSdan# fkey2-8.*: Test that enabling/disabling foreign key support while a
4829c7f9caSdan#            transaction is active is not possible.
4929c7f9caSdan#
50934ce300Sdan# fkey2-9.*: Test SET DEFAULT actions.
51934ce300Sdan#
52a8f0bf64Sdan# fkey2-10.*: Test errors.
53a8f0bf64Sdan#
54a8f0bf64Sdan# fkey2-11.*: Test CASCADE actions.
55a8f0bf64Sdan#
56a8f0bf64Sdan# fkey2-12.*: Test RESTRICT actions.
57a8f0bf64Sdan#
581bea559aSdan# fkey2-13.*: Test that FK processing is performed when a row is REPLACED by
591bea559aSdan#             an UPDATE or INSERT statement.
601bea559aSdan#
6153c3fa8dSdan# fkey2-14.*: Test the ALTER TABLE and DROP TABLE commands.
6253c3fa8dSdan#
630ff297eaSdan# fkey2-15.*: Test that if there are no (known) outstanding foreign key
640ff297eaSdan#             constraint violations in the database, inserting into a parent
650ff297eaSdan#             table or deleting from a child table does not cause SQLite
660ff297eaSdan#             to check if this has repaired an outstanding violation.
670ff297eaSdan#
689277efa3Sdan# fkey2-16.*: Test that rows that refer to themselves may be inserted,
699277efa3Sdan#             updated and deleted.
709277efa3Sdan#
71d583502eSdan# fkey2-17.*: Test that the "count_changes" pragma does not interfere with
72d583502eSdan#             FK constraint processing.
73d583502eSdan#
74e7a94d81Sdan# fkey2-18.*: Test that the authorization callback is invoked when processing
75e7a94d81Sdan#             FK constraints.
76e7a94d81Sdan#
77a7a0c615Sdan# fkey2-20.*: Test that ON CONFLICT clauses specified as part of statements
78a7a0c615Sdan#             do not affect the operation of FK constraints.
79a7a0c615Sdan#
801da40a38Sdan# fkey2-genfkey.*: Tests that were used with the shell tool .genfkey
811da40a38Sdan#            command. Recycled to test the built-in implementation.
821da40a38Sdan#
835c092e8aSdrh# fkey2-dd08e5.*:  Tests to verify that ticket dd08e5a988d00decc4a543daa8d
845c092e8aSdrh#                  has been fixed.
855c092e8aSdrh#
861da40a38Sdan
871da40a38Sdan
881da40a38Sdanexecsql { PRAGMA foreign_keys = on }
891da40a38Sdan
901da40a38Sdanset FkeySimpleSchema {
911da40a38Sdan  PRAGMA foreign_keys = on;
921da40a38Sdan  CREATE TABLE t1(a PRIMARY KEY, b);
931da40a38Sdan  CREATE TABLE t2(c REFERENCES t1(a) /D/ , d);
941da40a38Sdan
951da40a38Sdan  CREATE TABLE t3(a PRIMARY KEY, b);
961da40a38Sdan  CREATE TABLE t4(c REFERENCES t3 /D/, d);
971da40a38Sdan
981da40a38Sdan  CREATE TABLE t7(a, b INTEGER PRIMARY KEY);
991da40a38Sdan  CREATE TABLE t8(c REFERENCES t7 /D/, d);
1001da40a38Sdan
1011da40a38Sdan  CREATE TABLE t9(a REFERENCES nosuchtable, b);
1021da40a38Sdan  CREATE TABLE t10(a REFERENCES t9(c) /D/, b);
1031da40a38Sdan}
1040ff297eaSdan
1050ff297eaSdan
1061da40a38Sdanset FkeySimpleTests {
107f9c8ce3cSdrh  1.1  "INSERT INTO t2 VALUES(1, 3)"      {1 {FOREIGN KEY constraint failed}}
1081da40a38Sdan  1.2  "INSERT INTO t1 VALUES(1, 2)"      {0 {}}
1091da40a38Sdan  1.3  "INSERT INTO t2 VALUES(1, 3)"      {0 {}}
110f9c8ce3cSdrh  1.4  "INSERT INTO t2 VALUES(2, 4)"      {1 {FOREIGN KEY constraint failed}}
1111da40a38Sdan  1.5  "INSERT INTO t2 VALUES(NULL, 4)"   {0 {}}
112f9c8ce3cSdrh  1.6  "UPDATE t2 SET c=2 WHERE d=4"      {1 {FOREIGN KEY constraint failed}}
1131da40a38Sdan  1.7  "UPDATE t2 SET c=1 WHERE d=4"      {0 {}}
1141da40a38Sdan  1.9  "UPDATE t2 SET c=1 WHERE d=4"      {0 {}}
1151da40a38Sdan  1.10 "UPDATE t2 SET c=NULL WHERE d=4"   {0 {}}
116f9c8ce3cSdrh  1.11 "DELETE FROM t1 WHERE a=1"         {1 {FOREIGN KEY constraint failed}}
117f9c8ce3cSdrh  1.12 "UPDATE t1 SET a = 2"              {1 {FOREIGN KEY constraint failed}}
1181da40a38Sdan  1.13 "UPDATE t1 SET a = 1"              {0 {}}
1191da40a38Sdan
120f9c8ce3cSdrh  2.1  "INSERT INTO t4 VALUES(1, 3)"      {1 {FOREIGN KEY constraint failed}}
1211da40a38Sdan  2.2  "INSERT INTO t3 VALUES(1, 2)"      {0 {}}
1221da40a38Sdan  2.3  "INSERT INTO t4 VALUES(1, 3)"      {0 {}}
1231da40a38Sdan
124f9c8ce3cSdrh  4.1  "INSERT INTO t8 VALUES(1, 3)"      {1 {FOREIGN KEY constraint failed}}
1251da40a38Sdan  4.2  "INSERT INTO t7 VALUES(2, 1)"      {0 {}}
1261da40a38Sdan  4.3  "INSERT INTO t8 VALUES(1, 3)"      {0 {}}
127f9c8ce3cSdrh  4.4  "INSERT INTO t8 VALUES(2, 4)"      {1 {FOREIGN KEY constraint failed}}
1281da40a38Sdan  4.5  "INSERT INTO t8 VALUES(NULL, 4)"   {0 {}}
129f9c8ce3cSdrh  4.6  "UPDATE t8 SET c=2 WHERE d=4"      {1 {FOREIGN KEY constraint failed}}
1301da40a38Sdan  4.7  "UPDATE t8 SET c=1 WHERE d=4"      {0 {}}
1311da40a38Sdan  4.9  "UPDATE t8 SET c=1 WHERE d=4"      {0 {}}
1321da40a38Sdan  4.10 "UPDATE t8 SET c=NULL WHERE d=4"   {0 {}}
133f9c8ce3cSdrh  4.11 "DELETE FROM t7 WHERE b=1"         {1 {FOREIGN KEY constraint failed}}
134f9c8ce3cSdrh  4.12 "UPDATE t7 SET b = 2"              {1 {FOREIGN KEY constraint failed}}
1351da40a38Sdan  4.13 "UPDATE t7 SET b = 1"              {0 {}}
136f9c8ce3cSdrh  4.14 "INSERT INTO t8 VALUES('a', 'b')"  {1 {FOREIGN KEY constraint failed}}
137f9c8ce3cSdrh  4.15 "UPDATE t7 SET b = 5"              {1 {FOREIGN KEY constraint failed}}
138f9c8ce3cSdrh  4.16 "UPDATE t7 SET rowid = 5"          {1 {FOREIGN KEY constraint failed}}
1393d7b0469Sdan  4.17 "UPDATE t7 SET a = 10"             {0 {}}
1401da40a38Sdan
1411da40a38Sdan  5.1  "INSERT INTO t9 VALUES(1, 3)"      {1 {no such table: main.nosuchtable}}
1429148defaSdrh  5.2  "INSERT INTO t10 VALUES(1, 3)"
1439148defaSdrh                            {1 {foreign key mismatch - "t10" referencing "t9"}}
1441da40a38Sdan}
1451da40a38Sdan
1461da40a38Sdando_test fkey2-1.1.0 {
1471da40a38Sdan  execsql [string map {/D/ {}} $FkeySimpleSchema]
1481da40a38Sdan} {}
1491da40a38Sdanforeach {tn zSql res} $FkeySimpleTests {
1509148defaSdrh  do_test fkey2-1.1.$tn.1 { catchsql $zSql } $res
1519148defaSdrh  do_test fkey2-1.1.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {}
1529148defaSdrh  do_test fkey2-1.1.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {}
1539148defaSdrh  do_test fkey2-1.1.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {}
1549148defaSdrh  do_test fkey2-1.1.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {}
1559148defaSdrh  do_test fkey2-1.1.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {}
1569148defaSdrh  do_test fkey2-1.1.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {}
1571da40a38Sdan}
1581da40a38Sdandrop_all_tables
1591da40a38Sdan
1601da40a38Sdando_test fkey2-1.2.0 {
16132b09f29Sdan  execsql [string map {/D/ {DEFERRABLE INITIALLY DEFERRED}} $FkeySimpleSchema]
1621da40a38Sdan} {}
1631da40a38Sdanforeach {tn zSql res} $FkeySimpleTests {
1641da40a38Sdan  do_test fkey2-1.2.$tn { catchsql $zSql } $res
1659148defaSdrh  do_test fkey2-1.2.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {}
1669148defaSdrh  do_test fkey2-1.2.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {}
1679148defaSdrh  do_test fkey2-1.2.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {}
1689148defaSdrh  do_test fkey2-1.2.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {}
1699148defaSdrh  do_test fkey2-1.2.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {}
1709148defaSdrh  do_test fkey2-1.2.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {}
1711da40a38Sdan}
1721da40a38Sdandrop_all_tables
1731da40a38Sdan
17432b09f29Sdando_test fkey2-1.3.0 {
17532b09f29Sdan  execsql [string map {/D/ {}} $FkeySimpleSchema]
17632b09f29Sdan  execsql { PRAGMA count_changes = 1 }
17732b09f29Sdan} {}
17832b09f29Sdanforeach {tn zSql res} $FkeySimpleTests {
17932b09f29Sdan  if {$res == "0 {}"} { set res {0 1} }
18032b09f29Sdan  do_test fkey2-1.3.$tn { catchsql $zSql } $res
1819148defaSdrh  do_test fkey2-1.3.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {}
1829148defaSdrh  do_test fkey2-1.3.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {}
1839148defaSdrh  do_test fkey2-1.3.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {}
1849148defaSdrh  do_test fkey2-1.3.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {}
1859148defaSdrh  do_test fkey2-1.3.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {}
1869148defaSdrh  do_test fkey2-1.3.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {}
18732b09f29Sdan}
18832b09f29Sdanexecsql { PRAGMA count_changes = 0 }
18932b09f29Sdandrop_all_tables
19032b09f29Sdan
1919707c7b1Sdando_test fkey2-1.4.0 {
1929707c7b1Sdan  execsql [string map {/D/ {}} $FkeySimpleSchema]
1939707c7b1Sdan  execsql { PRAGMA count_changes = 1 }
1949707c7b1Sdan} {}
1959707c7b1Sdanforeach {tn zSql res} $FkeySimpleTests {
1969707c7b1Sdan  if {$res == "0 {}"} { set res {0 1} }
1979707c7b1Sdan  execsql BEGIN
1989707c7b1Sdan  do_test fkey2-1.4.$tn { catchsql $zSql } $res
1999707c7b1Sdan  execsql COMMIT
2009707c7b1Sdan}
2019707c7b1Sdanexecsql { PRAGMA count_changes = 0 }
2029707c7b1Sdandrop_all_tables
2039707c7b1Sdan
204140026bdSdan# Special test: When the parent key is an IPK, make sure the affinity of
205140026bdSdan# the IPK is not applied to the child key value before it is inserted
206140026bdSdan# into the child table.
2079707c7b1Sdando_test fkey2-1.5.1 {
208140026bdSdan  execsql {
209140026bdSdan    CREATE TABLE i(i INTEGER PRIMARY KEY);
210140026bdSdan    CREATE TABLE j(j REFERENCES i);
211140026bdSdan    INSERT INTO i VALUES(35);
212140026bdSdan    INSERT INTO j VALUES('35.0');
213140026bdSdan    SELECT j, typeof(j) FROM j;
214140026bdSdan  }
215140026bdSdan} {35.0 text}
2169707c7b1Sdando_test fkey2-1.5.2 {
217140026bdSdan  catchsql { DELETE FROM i }
218f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
219140026bdSdan
220140026bdSdan# Same test using a regular primary key with integer affinity.
221140026bdSdandrop_all_tables
2229707c7b1Sdando_test fkey2-1.6.1 {
223140026bdSdan  execsql {
224140026bdSdan    CREATE TABLE i(i INT UNIQUE);
225140026bdSdan    CREATE TABLE j(j REFERENCES i(i));
226140026bdSdan    INSERT INTO i VALUES('35.0');
227140026bdSdan    INSERT INTO j VALUES('35.0');
228140026bdSdan    SELECT j, typeof(j) FROM j;
229140026bdSdan    SELECT i, typeof(i) FROM i;
230140026bdSdan  }
231140026bdSdan} {35.0 text 35 integer}
2329707c7b1Sdando_test fkey2-1.6.2 {
233140026bdSdan  catchsql { DELETE FROM i }
234f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
235140026bdSdan
236140026bdSdan# Use a collation sequence on the parent key.
237140026bdSdandrop_all_tables
2389707c7b1Sdando_test fkey2-1.7.1 {
239140026bdSdan  execsql {
240140026bdSdan    CREATE TABLE i(i TEXT COLLATE nocase PRIMARY KEY);
241140026bdSdan    CREATE TABLE j(j TEXT COLLATE binary REFERENCES i(i));
242140026bdSdan    INSERT INTO i VALUES('SQLite');
243140026bdSdan    INSERT INTO j VALUES('sqlite');
244140026bdSdan  }
245140026bdSdan  catchsql { DELETE FROM i }
246f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
247140026bdSdan
248bd747832Sdan# Use the parent key collation even if it is default and the child key
249bd747832Sdan# has an explicit value.
250bd747832Sdandrop_all_tables
2519707c7b1Sdando_test fkey2-1.7.2 {
252bd747832Sdan  execsql {
253bd747832Sdan    CREATE TABLE i(i TEXT PRIMARY KEY);        -- Colseq is "BINARY"
254bd747832Sdan    CREATE TABLE j(j TEXT COLLATE nocase REFERENCES i(i));
255bd747832Sdan    INSERT INTO i VALUES('SQLite');
256bd747832Sdan  }
257bd747832Sdan  catchsql { INSERT INTO j VALUES('sqlite') }
258f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
2599707c7b1Sdando_test fkey2-1.7.3 {
260bd747832Sdan  execsql {
261bd747832Sdan    INSERT INTO i VALUES('sqlite');
262bd747832Sdan    INSERT INTO j VALUES('sqlite');
263bd747832Sdan    DELETE FROM i WHERE i = 'SQLite';
264bd747832Sdan  }
265bd747832Sdan  catchsql { DELETE FROM i WHERE i = 'sqlite' }
266f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
267bd747832Sdan
2681da40a38Sdan#-------------------------------------------------------------------------
2691da40a38Sdan# This section (test cases fkey2-2.*) contains tests to check that the
2701da40a38Sdan# deferred foreign key constraint logic works.
2711da40a38Sdan#
2721da40a38Sdanproc fkey2-2-test {tn nocommit sql {res {}}} {
2731da40a38Sdan  if {$res eq "FKV"} {
274f9c8ce3cSdrh    set expected {1 {FOREIGN KEY constraint failed}}
2751da40a38Sdan  } else {
2761da40a38Sdan    set expected [list 0 $res]
2771da40a38Sdan  }
2781da40a38Sdan  do_test fkey2-2.$tn [list catchsql $sql] $expected
2791da40a38Sdan  if {$nocommit} {
2801da40a38Sdan    do_test fkey2-2.${tn}c {
2811da40a38Sdan      catchsql COMMIT
282f9c8ce3cSdrh    } {1 {FOREIGN KEY constraint failed}}
2831da40a38Sdan  }
2841da40a38Sdan}
2851da40a38Sdan
2861da40a38Sdanfkey2-2-test 1 0 {
2871da40a38Sdan  CREATE TABLE node(
2881da40a38Sdan    nodeid PRIMARY KEY,
2891da40a38Sdan    parent REFERENCES node DEFERRABLE INITIALLY DEFERRED
2901da40a38Sdan  );
2911da40a38Sdan  CREATE TABLE leaf(
2921da40a38Sdan    cellid PRIMARY KEY,
2931da40a38Sdan    parent REFERENCES node DEFERRABLE INITIALLY DEFERRED
2941da40a38Sdan  );
2951da40a38Sdan}
2961da40a38Sdan
2971da40a38Sdanfkey2-2-test 1  0 "INSERT INTO node VALUES(1, 0)"       FKV
2981da40a38Sdanfkey2-2-test 2  0 "BEGIN"
2991da40a38Sdanfkey2-2-test 3  1   "INSERT INTO node VALUES(1, 0)"
3001da40a38Sdanfkey2-2-test 4  0   "UPDATE node SET parent = NULL"
3011da40a38Sdanfkey2-2-test 5  0 "COMMIT"
3021da40a38Sdanfkey2-2-test 6  0 "SELECT * FROM node" {1 {}}
3031da40a38Sdan
3041da40a38Sdanfkey2-2-test 7  0 "BEGIN"
3051da40a38Sdanfkey2-2-test 8  1   "INSERT INTO leaf VALUES('a', 2)"
3061da40a38Sdanfkey2-2-test 9  1   "INSERT INTO node VALUES(2, 0)"
3071da40a38Sdanfkey2-2-test 10 0   "UPDATE node SET parent = 1 WHERE nodeid = 2"
3081da40a38Sdanfkey2-2-test 11 0 "COMMIT"
3091da40a38Sdanfkey2-2-test 12 0 "SELECT * FROM node" {1 {} 2 1}
3101da40a38Sdanfkey2-2-test 13 0 "SELECT * FROM leaf" {a 2}
3111da40a38Sdan
3121da40a38Sdanfkey2-2-test 14 0 "BEGIN"
3131da40a38Sdanfkey2-2-test 15 1   "DELETE FROM node WHERE nodeid = 2"
3141da40a38Sdanfkey2-2-test 16 0   "INSERT INTO node VALUES(2, NULL)"
3151da40a38Sdanfkey2-2-test 17 0 "COMMIT"
3161da40a38Sdanfkey2-2-test 18 0 "SELECT * FROM node" {1 {} 2 {}}
3171da40a38Sdanfkey2-2-test 19 0 "SELECT * FROM leaf" {a 2}
3181da40a38Sdan
3191da40a38Sdanfkey2-2-test 20 0 "BEGIN"
3201da40a38Sdanfkey2-2-test 21 0   "INSERT INTO leaf VALUES('b', 1)"
3211da40a38Sdanfkey2-2-test 22 0   "SAVEPOINT save"
3221da40a38Sdanfkey2-2-test 23 0     "DELETE FROM node WHERE nodeid = 1"
3231da40a38Sdanfkey2-2-test 24 0   "ROLLBACK TO save"
3241da40a38Sdanfkey2-2-test 25 0 "COMMIT"
3251da40a38Sdanfkey2-2-test 26 0 "SELECT * FROM node" {1 {} 2 {}}
3261da40a38Sdanfkey2-2-test 27 0 "SELECT * FROM leaf" {a 2 b 1}
3271da40a38Sdan
3281da40a38Sdanfkey2-2-test 28 0 "BEGIN"
3291da40a38Sdanfkey2-2-test 29 0   "INSERT INTO leaf VALUES('c', 1)"
3301da40a38Sdanfkey2-2-test 30 0   "SAVEPOINT save"
3311da40a38Sdanfkey2-2-test 31 0     "DELETE FROM node WHERE nodeid = 1"
3321da40a38Sdanfkey2-2-test 32 1   "RELEASE save"
3331da40a38Sdanfkey2-2-test 33 1   "DELETE FROM leaf WHERE cellid = 'b'"
3341da40a38Sdanfkey2-2-test 34 0   "DELETE FROM leaf WHERE cellid = 'c'"
3351da40a38Sdanfkey2-2-test 35 0 "COMMIT"
3361da40a38Sdanfkey2-2-test 36 0 "SELECT * FROM node" {2 {}}
3371da40a38Sdanfkey2-2-test 37 0 "SELECT * FROM leaf" {a 2}
3381da40a38Sdan
3391da40a38Sdanfkey2-2-test 38 0 "SAVEPOINT outer"
3401da40a38Sdanfkey2-2-test 39 1   "INSERT INTO leaf VALUES('d', 3)"
3411da40a38Sdanfkey2-2-test 40 1 "RELEASE outer"    FKV
3421da40a38Sdanfkey2-2-test 41 1   "INSERT INTO leaf VALUES('e', 3)"
3431da40a38Sdanfkey2-2-test 42 0   "INSERT INTO node VALUES(3, 2)"
3441da40a38Sdanfkey2-2-test 43 0 "RELEASE outer"
3451da40a38Sdan
3461da40a38Sdanfkey2-2-test 44 0 "SAVEPOINT outer"
3471da40a38Sdanfkey2-2-test 45 1   "DELETE FROM node WHERE nodeid=3"
3481da40a38Sdanfkey2-2-test 47 0   "INSERT INTO node VALUES(3, 2)"
3491da40a38Sdanfkey2-2-test 48 0 "ROLLBACK TO outer"
3501da40a38Sdanfkey2-2-test 49 0 "RELEASE outer"
3511da40a38Sdan
3521da40a38Sdanfkey2-2-test 50 0 "SAVEPOINT outer"
3531da40a38Sdanfkey2-2-test 51 1   "INSERT INTO leaf VALUES('f', 4)"
3541da40a38Sdanfkey2-2-test 52 1   "SAVEPOINT inner"
3551da40a38Sdanfkey2-2-test 53 1     "INSERT INTO leaf VALUES('g', 4)"
3561da40a38Sdanfkey2-2-test 54 1  "RELEASE outer"   FKV
3571da40a38Sdanfkey2-2-test 55 1   "ROLLBACK TO inner"
3581da40a38Sdanfkey2-2-test 56 0  "COMMIT"          FKV
3591da40a38Sdanfkey2-2-test 57 0   "INSERT INTO node VALUES(4, NULL)"
3601da40a38Sdanfkey2-2-test 58 0 "RELEASE outer"
3611da40a38Sdanfkey2-2-test 59 0 "SELECT * FROM node" {2 {} 3 2 4 {}}
3621da40a38Sdanfkey2-2-test 60 0 "SELECT * FROM leaf" {a 2 d 3 e 3 f 4}
3631da40a38Sdan
3641da40a38Sdan# The following set of tests check that if a statement that affects
3651da40a38Sdan# multiple rows violates some foreign key constraints, then strikes a
3661da40a38Sdan# constraint that causes the statement-transaction to be rolled back,
3671da40a38Sdan# the deferred constraint counter is correctly reset to the value it
3681da40a38Sdan# had before the statement-transaction was opened.
3691da40a38Sdan#
3701da40a38Sdanfkey2-2-test 61 0 "BEGIN"
3711da40a38Sdanfkey2-2-test 62 0   "DELETE FROM leaf"
3721da40a38Sdanfkey2-2-test 63 0   "DELETE FROM node"
3731da40a38Sdanfkey2-2-test 64 1   "INSERT INTO leaf VALUES('a', 1)"
3741da40a38Sdanfkey2-2-test 65 1   "INSERT INTO leaf VALUES('b', 2)"
3751da40a38Sdanfkey2-2-test 66 1   "INSERT INTO leaf VALUES('c', 1)"
3761da40a38Sdando_test fkey2-2-test-67 {
3771da40a38Sdan  catchsql          "INSERT INTO node SELECT parent, 3 FROM leaf"
378f9c8ce3cSdrh} {1 {UNIQUE constraint failed: node.nodeid}}
3791da40a38Sdanfkey2-2-test 68 0 "COMMIT"           FKV
3801da40a38Sdanfkey2-2-test 69 1   "INSERT INTO node VALUES(1, NULL)"
3811da40a38Sdanfkey2-2-test 70 0   "INSERT INTO node VALUES(2, NULL)"
3821da40a38Sdanfkey2-2-test 71 0 "COMMIT"
3831da40a38Sdan
3841da40a38Sdanfkey2-2-test 72 0 "BEGIN"
3851da40a38Sdanfkey2-2-test 73 1   "DELETE FROM node"
3861da40a38Sdanfkey2-2-test 74 0   "INSERT INTO node(nodeid) SELECT DISTINCT parent FROM leaf"
3871da40a38Sdanfkey2-2-test 75 0 "COMMIT"
3881da40a38Sdan
3891da40a38Sdan#-------------------------------------------------------------------------
3901da40a38Sdan# Test cases fkey2-3.* test that a program that executes foreign key
3911da40a38Sdan# actions (CASCADE, SET DEFAULT, SET NULL etc.) or tests FK constraints
3921da40a38Sdan# opens a statement transaction if required.
3931da40a38Sdan#
3941da40a38Sdan# fkey2-3.1.*: Test UPDATE statements.
3951da40a38Sdan# fkey2-3.2.*: Test DELETE statements.
3961da40a38Sdan#
3971da40a38Sdandrop_all_tables
3981da40a38Sdando_test fkey2-3.1.1 {
3991da40a38Sdan  execsql {
4001da40a38Sdan    CREATE TABLE ab(a PRIMARY KEY, b);
4011da40a38Sdan    CREATE TABLE cd(
4021da40a38Sdan      c PRIMARY KEY REFERENCES ab ON UPDATE CASCADE ON DELETE CASCADE,
4031da40a38Sdan      d
4041da40a38Sdan    );
4051da40a38Sdan    CREATE TABLE ef(
4061da40a38Sdan      e REFERENCES cd ON UPDATE CASCADE,
4071da40a38Sdan      f, CHECK (e!=5)
4081da40a38Sdan    );
4091da40a38Sdan  }
4101da40a38Sdan} {}
4111da40a38Sdando_test fkey2-3.1.2 {
4121da40a38Sdan  execsql {
4131da40a38Sdan    INSERT INTO ab VALUES(1, 'b');
4141da40a38Sdan    INSERT INTO cd VALUES(1, 'd');
4151da40a38Sdan    INSERT INTO ef VALUES(1, 'e');
4161da40a38Sdan  }
4171da40a38Sdan} {}
4181da40a38Sdando_test fkey2-3.1.3 {
4191da40a38Sdan  catchsql { UPDATE ab SET a = 5 }
420*92e21ef0Sdrh} {1 {CHECK constraint failed: e!=5}}
4211da40a38Sdando_test fkey2-3.1.4 {
4221da40a38Sdan  execsql { SELECT * FROM ab }
4231da40a38Sdan} {1 b}
4241da40a38Sdando_test fkey2-3.1.4 {
4251da40a38Sdan  execsql BEGIN;
4261da40a38Sdan  catchsql { UPDATE ab SET a = 5 }
427*92e21ef0Sdrh} {1 {CHECK constraint failed: e!=5}}
4281da40a38Sdando_test fkey2-3.1.5 {
4291da40a38Sdan  execsql COMMIT;
4301da40a38Sdan  execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef }
4311da40a38Sdan} {1 b 1 d 1 e}
4329707c7b1Sdan
4331da40a38Sdando_test fkey2-3.2.1 {
4341da40a38Sdan  execsql BEGIN;
4351da40a38Sdan  catchsql { DELETE FROM ab }
436f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
4371da40a38Sdando_test fkey2-3.2.2 {
4381da40a38Sdan  execsql COMMIT
4391da40a38Sdan  execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef }
4401da40a38Sdan} {1 b 1 d 1 e}
4411da40a38Sdan
4421da40a38Sdan#-------------------------------------------------------------------------
4431da40a38Sdan# Test cases fkey2-4.* test that recursive foreign key actions
4441da40a38Sdan# (i.e. CASCADE) are allowed even if recursive triggers are disabled.
4451da40a38Sdan#
4461da40a38Sdandrop_all_tables
4471da40a38Sdando_test fkey2-4.1 {
4481da40a38Sdan  execsql {
4491da40a38Sdan    CREATE TABLE t1(
4501da40a38Sdan      node PRIMARY KEY,
4511da40a38Sdan      parent REFERENCES t1 ON DELETE CASCADE
4521da40a38Sdan    );
4531da40a38Sdan    CREATE TABLE t2(node PRIMARY KEY, parent);
4541da40a38Sdan    CREATE TRIGGER t2t AFTER DELETE ON t2 BEGIN
4551da40a38Sdan      DELETE FROM t2 WHERE parent = old.node;
4561da40a38Sdan    END;
4571da40a38Sdan    INSERT INTO t1 VALUES(1, NULL);
4581da40a38Sdan    INSERT INTO t1 VALUES(2, 1);
4591da40a38Sdan    INSERT INTO t1 VALUES(3, 1);
4601da40a38Sdan    INSERT INTO t1 VALUES(4, 2);
4611da40a38Sdan    INSERT INTO t1 VALUES(5, 2);
4621da40a38Sdan    INSERT INTO t1 VALUES(6, 3);
4631da40a38Sdan    INSERT INTO t1 VALUES(7, 3);
4641da40a38Sdan    INSERT INTO t2 SELECT * FROM t1;
4651da40a38Sdan  }
4661da40a38Sdan} {}
4671da40a38Sdando_test fkey2-4.2 {
4681da40a38Sdan  execsql { PRAGMA recursive_triggers = off }
4691da40a38Sdan  execsql {
4701da40a38Sdan    BEGIN;
4711da40a38Sdan      DELETE FROM t1 WHERE node = 1;
4721da40a38Sdan      SELECT node FROM t1;
4731da40a38Sdan  }
4741da40a38Sdan} {}
4751da40a38Sdando_test fkey2-4.3 {
4761da40a38Sdan  execsql {
4771da40a38Sdan      DELETE FROM t2 WHERE node = 1;
4781da40a38Sdan      SELECT node FROM t2;
4791da40a38Sdan    ROLLBACK;
4801da40a38Sdan  }
4811da40a38Sdan} {4 5 6 7}
4821da40a38Sdando_test fkey2-4.4 {
4831da40a38Sdan  execsql { PRAGMA recursive_triggers = on }
4841da40a38Sdan  execsql {
4851da40a38Sdan    BEGIN;
4861da40a38Sdan      DELETE FROM t1 WHERE node = 1;
4871da40a38Sdan      SELECT node FROM t1;
4881da40a38Sdan  }
4891da40a38Sdan} {}
4901da40a38Sdando_test fkey2-4.3 {
4911da40a38Sdan  execsql {
4921da40a38Sdan      DELETE FROM t2 WHERE node = 1;
4931da40a38Sdan      SELECT node FROM t2;
4941da40a38Sdan    ROLLBACK;
4951da40a38Sdan  }
4961da40a38Sdan} {}
4971da40a38Sdan
4981da40a38Sdan#-------------------------------------------------------------------------
4991da40a38Sdan# Test cases fkey2-5.* verify that the incremental blob API may not
5001da40a38Sdan# write to a foreign key column while foreign-keys are enabled.
5011da40a38Sdan#
5021da40a38Sdandrop_all_tables
50375cbd984Sdanifcapable incrblob {
5041da40a38Sdan  do_test fkey2-5.1 {
5051da40a38Sdan    execsql {
5061da40a38Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
5071da40a38Sdan      CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1(a));
5081da40a38Sdan      INSERT INTO t1 VALUES('hello', 'world');
5091da40a38Sdan      INSERT INTO t2 VALUES('key', 'hello');
5101da40a38Sdan    }
5111da40a38Sdan  } {}
5121da40a38Sdan  do_test fkey2-5.2 {
5131da40a38Sdan    set rc [catch { set fd [db incrblob t2 b 1] } msg]
5141da40a38Sdan    list $rc $msg
5151da40a38Sdan  } {1 {cannot open foreign key column for writing}}
5161da40a38Sdan  do_test fkey2-5.3 {
5171da40a38Sdan    set rc [catch { set fd [db incrblob -readonly t2 b 1] } msg]
5181da40a38Sdan    close $fd
5191da40a38Sdan    set rc
5201da40a38Sdan  } {0}
5211da40a38Sdan  do_test fkey2-5.4 {
5221da40a38Sdan    execsql { PRAGMA foreign_keys = off }
5231da40a38Sdan    set rc [catch { set fd [db incrblob t2 b 1] } msg]
5241da40a38Sdan    close $fd
5251da40a38Sdan    set rc
5261da40a38Sdan  } {0}
5271da40a38Sdan  do_test fkey2-5.5 {
5281da40a38Sdan    execsql { PRAGMA foreign_keys = on }
5291da40a38Sdan  } {}
53075cbd984Sdan}
53175cbd984Sdan
53275cbd984Sdandrop_all_tables
53375cbd984Sdanifcapable vacuum {
53475cbd984Sdan  do_test fkey2-6.1 {
53575cbd984Sdan    execsql {
53675cbd984Sdan      CREATE TABLE t1(a REFERENCES t2(c), b);
53775cbd984Sdan      CREATE TABLE t2(c UNIQUE, b);
53875cbd984Sdan      INSERT INTO t2 VALUES(1, 2);
53975cbd984Sdan      INSERT INTO t1 VALUES(1, 2);
54075cbd984Sdan      VACUUM;
54175cbd984Sdan    }
54275cbd984Sdan  } {}
54375cbd984Sdan}
5441da40a38Sdan
5451da40a38Sdan#-------------------------------------------------------------------------
5463606264bSdan# Test that it is possible to use an INTEGER PRIMARY KEY as the child key
5473606264bSdan# of a foreign constraint.
54829c7f9caSdan#
5493606264bSdandrop_all_tables
5503606264bSdando_test fkey2-7.1 {
5513606264bSdan  execsql {
5523606264bSdan    CREATE TABLE t1(a PRIMARY KEY, b);
5533606264bSdan    CREATE TABLE t2(c INTEGER PRIMARY KEY REFERENCES t1, b);
5543606264bSdan  }
5553606264bSdan} {}
5563606264bSdando_test fkey2-7.2 {
5573606264bSdan  catchsql { INSERT INTO t2 VALUES(1, 'A'); }
558f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
5593606264bSdando_test fkey2-7.3 {
5603606264bSdan  execsql {
5613606264bSdan    INSERT INTO t1 VALUES(1, 2);
5623606264bSdan    INSERT INTO t1 VALUES(2, 3);
5633606264bSdan    INSERT INTO t2 VALUES(1, 'A');
5643606264bSdan  }
5653606264bSdan} {}
5663606264bSdando_test fkey2-7.4 {
5673606264bSdan  execsql { UPDATE t2 SET c = 2 }
5683606264bSdan} {}
5693606264bSdando_test fkey2-7.5 {
5703606264bSdan  catchsql { UPDATE t2 SET c = 3 }
571f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
5723606264bSdando_test fkey2-7.6 {
5733606264bSdan  catchsql { DELETE FROM t1 WHERE a = 2 }
574f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
5753606264bSdando_test fkey2-7.7 {
5763606264bSdan  execsql { DELETE FROM t1 WHERE a = 1 }
5773606264bSdan} {}
5783606264bSdando_test fkey2-7.8 {
5793606264bSdan  catchsql { UPDATE t1 SET a = 3 }
580f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
5813d7b0469Sdando_test fkey2-7.9 {
5823d7b0469Sdan  catchsql { UPDATE t2 SET rowid = 3 }
583f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
5843606264bSdan
5853606264bSdan#-------------------------------------------------------------------------
58629c7f9caSdan# Test that it is not possible to enable/disable FK support while a
58729c7f9caSdan# transaction is open.
58829c7f9caSdan#
58929c7f9caSdandrop_all_tables
59029c7f9caSdanproc fkey2-8-test {tn zSql value} {
59129c7f9caSdan  do_test fkey-2.8.$tn.1 [list execsql $zSql] {}
59229c7f9caSdan  do_test fkey-2.8.$tn.2 { execsql "PRAGMA foreign_keys" } $value
59329c7f9caSdan}
59429c7f9caSdanfkey2-8-test  1 { PRAGMA foreign_keys = 0     } 0
59529c7f9caSdanfkey2-8-test  2 { PRAGMA foreign_keys = 1     } 1
59629c7f9caSdanfkey2-8-test  3 { BEGIN                       } 1
59729c7f9caSdanfkey2-8-test  4 { PRAGMA foreign_keys = 0     } 1
59829c7f9caSdanfkey2-8-test  5 { COMMIT                      } 1
59929c7f9caSdanfkey2-8-test  6 { PRAGMA foreign_keys = 0     } 0
60029c7f9caSdanfkey2-8-test  7 { BEGIN                       } 0
60129c7f9caSdanfkey2-8-test  8 { PRAGMA foreign_keys = 1     } 0
60229c7f9caSdanfkey2-8-test  9 { COMMIT                      } 0
60329c7f9caSdanfkey2-8-test 10 { PRAGMA foreign_keys = 1     } 1
60429c7f9caSdanfkey2-8-test 11 { PRAGMA foreign_keys = off   } 0
60529c7f9caSdanfkey2-8-test 12 { PRAGMA foreign_keys = on    } 1
60629c7f9caSdanfkey2-8-test 13 { PRAGMA foreign_keys = no    } 0
60729c7f9caSdanfkey2-8-test 14 { PRAGMA foreign_keys = yes   } 1
60829c7f9caSdanfkey2-8-test 15 { PRAGMA foreign_keys = false } 0
60929c7f9caSdanfkey2-8-test 16 { PRAGMA foreign_keys = true  } 1
61029c7f9caSdan
61129c7f9caSdan#-------------------------------------------------------------------------
612934ce300Sdan# The following tests, fkey2-9.*, test SET DEFAULT actions.
613934ce300Sdan#
614934ce300Sdandrop_all_tables
615934ce300Sdando_test fkey2-9.1.1 {
616934ce300Sdan  execsql {
617934ce300Sdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
618934ce300Sdan    CREATE TABLE t2(
619934ce300Sdan      c INTEGER PRIMARY KEY,
620934ce300Sdan      d INTEGER DEFAULT 1 REFERENCES t1 ON DELETE SET DEFAULT
621934ce300Sdan    );
622934ce300Sdan    DELETE FROM t1;
623934ce300Sdan  }
624934ce300Sdan} {}
625934ce300Sdando_test fkey2-9.1.2 {
626934ce300Sdan  execsql {
627934ce300Sdan    INSERT INTO t1 VALUES(1, 'one');
628934ce300Sdan    INSERT INTO t1 VALUES(2, 'two');
629934ce300Sdan    INSERT INTO t2 VALUES(1, 2);
630934ce300Sdan    SELECT * FROM t2;
631934ce300Sdan    DELETE FROM t1 WHERE a = 2;
632934ce300Sdan    SELECT * FROM t2;
633934ce300Sdan  }
634934ce300Sdan} {1 2 1 1}
635934ce300Sdando_test fkey2-9.1.3 {
636934ce300Sdan  execsql {
637934ce300Sdan    INSERT INTO t1 VALUES(2, 'two');
638934ce300Sdan    UPDATE t2 SET d = 2;
639934ce300Sdan    DELETE FROM t1 WHERE a = 1;
640934ce300Sdan    SELECT * FROM t2;
641934ce300Sdan  }
642934ce300Sdan} {1 2}
643934ce300Sdando_test fkey2-9.1.4 {
644934ce300Sdan  execsql { SELECT * FROM t1 }
645934ce300Sdan} {2 two}
646934ce300Sdando_test fkey2-9.1.5 {
647934ce300Sdan  catchsql { DELETE FROM t1 }
648f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
649934ce300Sdan
6509707c7b1Sdando_test fkey2-9.2.1 {
6519707c7b1Sdan  execsql {
6529707c7b1Sdan    CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c));
6539707c7b1Sdan    CREATE TABLE cc(d DEFAULT 3, e DEFAULT 1, f DEFAULT 2,
6549707c7b1Sdan        FOREIGN KEY(f, d) REFERENCES pp
6559707c7b1Sdan        ON UPDATE SET DEFAULT
6569707c7b1Sdan        ON DELETE SET NULL
6579707c7b1Sdan    );
6589707c7b1Sdan    INSERT INTO pp VALUES(1, 2, 3);
6599707c7b1Sdan    INSERT INTO pp VALUES(4, 5, 6);
6609707c7b1Sdan    INSERT INTO pp VALUES(7, 8, 9);
6619707c7b1Sdan  }
6629707c7b1Sdan} {}
6639707c7b1Sdando_test fkey2-9.2.2 {
6649707c7b1Sdan  execsql {
6659707c7b1Sdan    INSERT INTO cc VALUES(6, 'A', 5);
6669707c7b1Sdan    INSERT INTO cc VALUES(6, 'B', 5);
6679707c7b1Sdan    INSERT INTO cc VALUES(9, 'A', 8);
6689707c7b1Sdan    INSERT INTO cc VALUES(9, 'B', 8);
6699707c7b1Sdan    UPDATE pp SET b = 1 WHERE a = 7;
6709707c7b1Sdan    SELECT * FROM cc;
6719707c7b1Sdan  }
6729707c7b1Sdan} {6 A 5 6 B 5 3 A 2 3 B 2}
6739707c7b1Sdando_test fkey2-9.2.3 {
6749707c7b1Sdan  execsql {
6759707c7b1Sdan    DELETE FROM pp WHERE a = 4;
6769707c7b1Sdan    SELECT * FROM cc;
6779707c7b1Sdan  }
6789707c7b1Sdan} {{} A {} {} B {} 3 A 2 3 B 2}
679ab4e7f33Sdrhdo_execsql_test fkey2-9.3.0 {
680ab4e7f33Sdrh  CREATE TABLE t3(x PRIMARY KEY REFERENCES t3 ON DELETE SET NULL);
681ab4e7f33Sdrh  INSERT INTO t3(x) VALUES(12345);
682ab4e7f33Sdrh  DROP TABLE t3;
683ab4e7f33Sdrh} {}
6849707c7b1Sdan
685934ce300Sdan#-------------------------------------------------------------------------
686a8f0bf64Sdan# The following tests, fkey2-10.*, test "foreign key mismatch" and
687a8f0bf64Sdan# other errors.
688a8f0bf64Sdan#
689652ac1d0Sdanset tn 0
690a8f0bf64Sdanforeach zSql [list {
691a8f0bf64Sdan  CREATE TABLE p(a PRIMARY KEY, b);
692a8f0bf64Sdan  CREATE TABLE c(x REFERENCES p(c));
693792e9201Sdan} {
694792e9201Sdan  CREATE TABLE c(x REFERENCES v(y));
695792e9201Sdan  CREATE VIEW v AS SELECT x AS y FROM c;
696792e9201Sdan} {
697792e9201Sdan  CREATE TABLE p(a, b, PRIMARY KEY(a, b));
698792e9201Sdan  CREATE TABLE c(x REFERENCES p);
6999707c7b1Sdan} {
7009707c7b1Sdan  CREATE TABLE p(a COLLATE binary, b);
7019707c7b1Sdan  CREATE UNIQUE INDEX i ON p(a COLLATE nocase);
7029707c7b1Sdan  CREATE TABLE c(x REFERENCES p(a));
703a8f0bf64Sdan}] {
704a8f0bf64Sdan  drop_all_tables
705652ac1d0Sdan  do_test fkey2-10.1.[incr tn] {
706a8f0bf64Sdan    execsql $zSql
707a8f0bf64Sdan    catchsql { INSERT INTO c DEFAULT VALUES }
7089148defaSdrh  } {/1 {foreign key mismatch - "c" referencing "."}/}
709a8f0bf64Sdan}
710a8f0bf64Sdan
711d981d447Sdan# "rowid" cannot be used as part of a child or parent key definition
712d981d447Sdan# unless it happens to be the name of an explicitly declared column.
713a8f0bf64Sdan#
714a8f0bf64Sdando_test fkey2-10.2.1 {
715a8f0bf64Sdan  drop_all_tables
716a8f0bf64Sdan  catchsql {
717a8f0bf64Sdan    CREATE TABLE t1(a PRIMARY KEY, b);
718a8f0bf64Sdan    CREATE TABLE t2(c, d, FOREIGN KEY(rowid) REFERENCES t1(a));
719a8f0bf64Sdan  }
720a8f0bf64Sdan} {1 {unknown column "rowid" in foreign key definition}}
721a8f0bf64Sdando_test fkey2-10.2.2 {
722a8f0bf64Sdan  drop_all_tables
723a8f0bf64Sdan  catchsql {
724a8f0bf64Sdan    CREATE TABLE t1(a PRIMARY KEY, b);
725a8f0bf64Sdan    CREATE TABLE t2(rowid, d, FOREIGN KEY(rowid) REFERENCES t1(a));
726a8f0bf64Sdan  }
727a8f0bf64Sdan} {0 {}}
728d981d447Sdando_test fkey2-10.2.1 {
729d981d447Sdan  drop_all_tables
730d981d447Sdan  catchsql {
731d981d447Sdan    CREATE TABLE t1(a, b);
732d981d447Sdan    CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid));
733d981d447Sdan    INSERT INTO t1(rowid, a, b) VALUES(1, 1, 1);
734d981d447Sdan    INSERT INTO t2 VALUES(1, 1);
735d981d447Sdan  }
7369148defaSdrh} {1 {foreign key mismatch - "t2" referencing "t1"}}
737d981d447Sdando_test fkey2-10.2.2 {
738d981d447Sdan  drop_all_tables
739d981d447Sdan  catchsql {
740d981d447Sdan    CREATE TABLE t1(rowid PRIMARY KEY, b);
741d981d447Sdan    CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid));
742d981d447Sdan    INSERT INTO t1(rowid, b) VALUES(1, 1);
743d981d447Sdan    INSERT INTO t2 VALUES(1, 1);
744d981d447Sdan  }
745d981d447Sdan} {0 {}}
746a8f0bf64Sdan
747a8f0bf64Sdan
748a8f0bf64Sdan#-------------------------------------------------------------------------
749a8f0bf64Sdan# The following tests, fkey2-11.*, test CASCADE actions.
750a8f0bf64Sdan#
751a8f0bf64Sdandrop_all_tables
752a8f0bf64Sdando_test fkey2-11.1.1 {
753a8f0bf64Sdan  execsql {
754e918aabaSdrh    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, rowid, _rowid_, oid);
755a8f0bf64Sdan    CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(a) ON UPDATE CASCADE);
756a8f0bf64Sdan
757e918aabaSdrh    INSERT INTO t1 VALUES(10, 100, 'abc', 'def', 'ghi');
758a8f0bf64Sdan    INSERT INTO t2 VALUES(10, 100);
759a8f0bf64Sdan    UPDATE t1 SET a = 15;
760a8f0bf64Sdan    SELECT * FROM t2;
761a8f0bf64Sdan  }
762a8f0bf64Sdan} {15 100}
763a8f0bf64Sdan
764a8f0bf64Sdan#-------------------------------------------------------------------------
765a8f0bf64Sdan# The following tests, fkey2-12.*, test RESTRICT actions.
766a8f0bf64Sdan#
767a8f0bf64Sdandrop_all_tables
768a8f0bf64Sdando_test fkey2-12.1.1 {
769a8f0bf64Sdan  execsql {
770a8f0bf64Sdan    CREATE TABLE t1(a, b PRIMARY KEY);
771a8f0bf64Sdan    CREATE TABLE t2(
772a8f0bf64Sdan      x REFERENCES t1 ON UPDATE RESTRICT DEFERRABLE INITIALLY DEFERRED
773a8f0bf64Sdan    );
774a8f0bf64Sdan    INSERT INTO t1 VALUES(1, 'one');
775a8f0bf64Sdan    INSERT INTO t1 VALUES(2, 'two');
776a8f0bf64Sdan    INSERT INTO t1 VALUES(3, 'three');
777a8f0bf64Sdan  }
778a8f0bf64Sdan} {}
779a8f0bf64Sdando_test fkey2-12.1.2 {
780a8f0bf64Sdan  execsql "BEGIN"
781a8f0bf64Sdan  execsql "INSERT INTO t2 VALUES('two')"
782a8f0bf64Sdan} {}
783a8f0bf64Sdando_test fkey2-12.1.3 {
784a8f0bf64Sdan  execsql "UPDATE t1 SET b = 'four' WHERE b = 'one'"
785a8f0bf64Sdan} {}
786a8f0bf64Sdando_test fkey2-12.1.4 {
787a8f0bf64Sdan  catchsql "UPDATE t1 SET b = 'five' WHERE b = 'two'"
788f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
789a8f0bf64Sdando_test fkey2-12.1.5 {
790a8f0bf64Sdan  execsql "DELETE FROM t1 WHERE b = 'two'"
791a8f0bf64Sdan} {}
792a8f0bf64Sdando_test fkey2-12.1.6 {
793a8f0bf64Sdan  catchsql "COMMIT"
794f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
795a8f0bf64Sdando_test fkey2-12.1.7 {
796a8f0bf64Sdan  execsql {
797a8f0bf64Sdan    INSERT INTO t1 VALUES(2, 'two');
798a8f0bf64Sdan    COMMIT;
799a8f0bf64Sdan  }
800a8f0bf64Sdan} {}
801a8f0bf64Sdan
802652ac1d0Sdandrop_all_tables
803652ac1d0Sdando_test fkey2-12.2.1 {
804652ac1d0Sdan  execsql {
805652ac1d0Sdan    CREATE TABLE t1(x COLLATE NOCASE PRIMARY KEY);
806652ac1d0Sdan    CREATE TRIGGER tt1 AFTER DELETE ON t1
807652ac1d0Sdan      WHEN EXISTS ( SELECT 1 FROM t2 WHERE old.x = y )
808652ac1d0Sdan    BEGIN
809652ac1d0Sdan      INSERT INTO t1 VALUES(old.x);
810652ac1d0Sdan    END;
811652ac1d0Sdan    CREATE TABLE t2(y REFERENCES t1);
812652ac1d0Sdan    INSERT INTO t1 VALUES('A');
813652ac1d0Sdan    INSERT INTO t1 VALUES('B');
814652ac1d0Sdan    INSERT INTO t2 VALUES('a');
815652ac1d0Sdan    INSERT INTO t2 VALUES('b');
816652ac1d0Sdan
817652ac1d0Sdan    SELECT * FROM t1;
818652ac1d0Sdan    SELECT * FROM t2;
819652ac1d0Sdan  }
820652ac1d0Sdan} {A B a b}
821652ac1d0Sdando_test fkey2-12.2.2 {
822652ac1d0Sdan  execsql { DELETE FROM t1 }
823652ac1d0Sdan  execsql {
824652ac1d0Sdan    SELECT * FROM t1;
825652ac1d0Sdan    SELECT * FROM t2;
826652ac1d0Sdan  }
827652ac1d0Sdan} {A B a b}
828652ac1d0Sdando_test fkey2-12.2.3 {
829652ac1d0Sdan  execsql {
830652ac1d0Sdan    DROP TABLE t2;
831652ac1d0Sdan    CREATE TABLE t2(y REFERENCES t1 ON DELETE RESTRICT);
832652ac1d0Sdan    INSERT INTO t2 VALUES('a');
833652ac1d0Sdan    INSERT INTO t2 VALUES('b');
834652ac1d0Sdan  }
835652ac1d0Sdan  catchsql { DELETE FROM t1 }
836f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
837652ac1d0Sdando_test fkey2-12.2.4 {
838652ac1d0Sdan  execsql {
839652ac1d0Sdan    SELECT * FROM t1;
840652ac1d0Sdan    SELECT * FROM t2;
841652ac1d0Sdan  }
842652ac1d0Sdan} {A B a b}
843652ac1d0Sdan
844f7a94543Sdandrop_all_tables
845f7a94543Sdando_test fkey2-12.3.1 {
846f7a94543Sdan  execsql {
847f7a94543Sdan    CREATE TABLE up(
848f7a94543Sdan      c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
849f7a94543Sdan      c10, c11, c12, c13, c14, c15, c16, c17, c18, c19,
850f7a94543Sdan      c20, c21, c22, c23, c24, c25, c26, c27, c28, c29,
851f7a94543Sdan      c30, c31, c32, c33, c34, c35, c36, c37, c38, c39,
852f7a94543Sdan      PRIMARY KEY(c34, c35)
853f7a94543Sdan    );
854f7a94543Sdan    CREATE TABLE down(
855f7a94543Sdan      c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
856f7a94543Sdan      c10, c11, c12, c13, c14, c15, c16, c17, c18, c19,
857f7a94543Sdan      c20, c21, c22, c23, c24, c25, c26, c27, c28, c29,
858f7a94543Sdan      c30, c31, c32, c33, c34, c35, c36, c37, c38, c39,
859f7a94543Sdan      FOREIGN KEY(c39, c38) REFERENCES up ON UPDATE CASCADE
860f7a94543Sdan    );
861f7a94543Sdan  }
862f7a94543Sdan} {}
863f7a94543Sdando_test fkey2-12.3.2 {
864f7a94543Sdan  execsql {
865f7a94543Sdan    INSERT INTO up(c34, c35) VALUES('yes', 'no');
866f7a94543Sdan    INSERT INTO down(c39, c38) VALUES('yes', 'no');
867f7a94543Sdan    UPDATE up SET c34 = 'possibly';
868f7a94543Sdan    SELECT c38, c39 FROM down;
869f7a94543Sdan    DELETE FROM down;
870f7a94543Sdan  }
871f7a94543Sdan} {no possibly}
872f7a94543Sdando_test fkey2-12.3.3 {
873f7a94543Sdan  catchsql { INSERT INTO down(c39, c38) VALUES('yes', 'no') }
874f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
875f7a94543Sdando_test fkey2-12.3.4 {
876f7a94543Sdan  execsql {
877f7a94543Sdan    INSERT INTO up(c34, c35) VALUES('yes', 'no');
878f7a94543Sdan    INSERT INTO down(c39, c38) VALUES('yes', 'no');
879f7a94543Sdan  }
880f7a94543Sdan  catchsql { DELETE FROM up WHERE c34 = 'yes' }
881f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
882f7a94543Sdando_test fkey2-12.3.5 {
883f7a94543Sdan  execsql {
884f7a94543Sdan    DELETE FROM up WHERE c34 = 'possibly';
885f7a94543Sdan    SELECT c34, c35 FROM up;
886f7a94543Sdan    SELECT c39, c38 FROM down;
887f7a94543Sdan  }
888f7a94543Sdan} {yes no yes no}
889f7a94543Sdan
8901bea559aSdan#-------------------------------------------------------------------------
8911bea559aSdan# The following tests, fkey2-13.*, test that FK processing is performed
8921bea559aSdan# when rows are REPLACEd.
8931bea559aSdan#
8941bea559aSdandrop_all_tables
8951bea559aSdando_test fkey2-13.1.1 {
8961bea559aSdan  execsql {
8971bea559aSdan    CREATE TABLE pp(a UNIQUE, b, c, PRIMARY KEY(b, c));
8981bea559aSdan    CREATE TABLE cc(d, e, f UNIQUE, FOREIGN KEY(d, e) REFERENCES pp);
8991bea559aSdan    INSERT INTO pp VALUES(1, 2, 3);
9001bea559aSdan    INSERT INTO cc VALUES(2, 3, 1);
9011bea559aSdan  }
9021bea559aSdan} {}
9031bea559aSdanforeach {tn stmt} {
9041bea559aSdan  1   "REPLACE INTO pp VALUES(1, 4, 5)"
9051bea559aSdan  2   "REPLACE INTO pp(rowid, a, b, c) VALUES(1, 2, 3, 4)"
9061bea559aSdan} {
9071bea559aSdan  do_test fkey2-13.1.$tn.1 {
9081bea559aSdan    catchsql $stmt
909f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
9101bea559aSdan  do_test fkey2-13.1.$tn.2 {
9111bea559aSdan    execsql {
9121bea559aSdan      SELECT * FROM pp;
9131bea559aSdan      SELECT * FROM cc;
9141bea559aSdan    }
9151bea559aSdan  } {1 2 3 2 3 1}
9161bea559aSdan  do_test fkey2-13.1.$tn.3 {
9171bea559aSdan    execsql BEGIN;
9181bea559aSdan    catchsql $stmt
919f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
9201bea559aSdan  do_test fkey2-13.1.$tn.4 {
9211bea559aSdan    execsql {
9221bea559aSdan      COMMIT;
9231bea559aSdan      SELECT * FROM pp;
9241bea559aSdan      SELECT * FROM cc;
9251bea559aSdan    }
9261bea559aSdan  } {1 2 3 2 3 1}
9271bea559aSdan}
9281bea559aSdando_test fkey2-13.1.3 {
9291bea559aSdan  execsql {
9301bea559aSdan    REPLACE INTO pp(rowid, a, b, c) VALUES(1, 2, 2, 3);
9311bea559aSdan    SELECT rowid, * FROM pp;
9321bea559aSdan    SELECT * FROM cc;
9331bea559aSdan  }
9341bea559aSdan} {1 2 2 3 2 3 1}
9351bea559aSdando_test fkey2-13.1.4 {
9361bea559aSdan  execsql {
9371bea559aSdan    REPLACE INTO pp(rowid, a, b, c) VALUES(2, 2, 2, 3);
9381bea559aSdan    SELECT rowid, * FROM pp;
9391bea559aSdan    SELECT * FROM cc;
9401bea559aSdan  }
9411bea559aSdan} {2 2 2 3 2 3 1}
942a8f0bf64Sdan
943a8f0bf64Sdan#-------------------------------------------------------------------------
94453c3fa8dSdan# The following tests, fkey2-14.*, test that the "DROP TABLE" and "ALTER
94553c3fa8dSdan# TABLE" commands work as expected wrt foreign key constraints.
94653c3fa8dSdan#
94753c3fa8dSdan# fkey2-14.1*: ALTER TABLE ADD COLUMN
94853c3fa8dSdan# fkey2-14.2*: ALTER TABLE RENAME TABLE
94953c3fa8dSdan# fkey2-14.3*: DROP TABLE
95053c3fa8dSdan#
95153c3fa8dSdandrop_all_tables
952856ef1a5Sdanifcapable altertable {
9530ff297eaSdan  do_test fkey2-14.1.1 {
95453c3fa8dSdan    # Adding a column with a REFERENCES clause is not supported.
95553c3fa8dSdan    execsql {
95653c3fa8dSdan      CREATE TABLE t1(a PRIMARY KEY);
95753c3fa8dSdan      CREATE TABLE t2(a, b);
9589e5fdc41Sdrh      INSERT INTO t2 VALUES(1,2);
95953c3fa8dSdan    }
96053c3fa8dSdan    catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
96153c3fa8dSdan  } {0 {}}
9620ff297eaSdan  do_test fkey2-14.1.2 {
96353c3fa8dSdan    catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
96453c3fa8dSdan  } {0 {}}
9650ff297eaSdan  do_test fkey2-14.1.3 {
96653c3fa8dSdan    catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
96753c3fa8dSdan  } {0 {}}
9680ff297eaSdan  do_test fkey2-14.1.4 {
96953c3fa8dSdan    catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
97053c3fa8dSdan  } {1 {Cannot add a REFERENCES column with non-NULL default value}}
9710ff297eaSdan  do_test fkey2-14.1.5 {
97253c3fa8dSdan    catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
97353c3fa8dSdan  } {1 {Cannot add a REFERENCES column with non-NULL default value}}
9740ff297eaSdan  do_test fkey2-14.1.6 {
97553c3fa8dSdan    execsql {
97653c3fa8dSdan      PRAGMA foreign_keys = off;
97753c3fa8dSdan      ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
97853c3fa8dSdan      PRAGMA foreign_keys = on;
97953c3fa8dSdan      SELECT sql FROM sqlite_master WHERE name='t2';
98053c3fa8dSdan    }
98153c3fa8dSdan  } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
98253c3fa8dSdan
983432cc5b9Sdan
984432cc5b9Sdan  # Test the sqlite_rename_parent() function directly.
985432cc5b9Sdan  #
986432cc5b9Sdan  proc test_rename_parent {zCreate zOld zNew} {
9875921f2b9Sdan    db eval {SELECT sqlite_rename_table(
9885921f2b9Sdan        'main', 'table', 't1', $zCreate, $zOld, $zNew, 0
9895921f2b9Sdan    )}
990432cc5b9Sdan  }
991171c50ecSdrh  sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
992432cc5b9Sdan  do_test fkey2-14.2.1.1 {
993432cc5b9Sdan    test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
994432cc5b9Sdan  } {{CREATE TABLE t1(a REFERENCES "t3")}}
995432cc5b9Sdan  do_test fkey2-14.2.1.2 {
996432cc5b9Sdan    test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
997432cc5b9Sdan  } {{CREATE TABLE t1(a REFERENCES t2)}}
998432cc5b9Sdan  do_test fkey2-14.2.1.3 {
999432cc5b9Sdan    test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
1000432cc5b9Sdan  } {{CREATE TABLE t1(a REFERENCES "t3")}}
1001171c50ecSdrh  sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
1002432cc5b9Sdan
1003432cc5b9Sdan  # Test ALTER TABLE RENAME TABLE a bit.
1004432cc5b9Sdan  #
1005432cc5b9Sdan  do_test fkey2-14.2.2.1 {
1006432cc5b9Sdan    drop_all_tables
1007432cc5b9Sdan    execsql {
1008432cc5b9Sdan      CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1);
1009432cc5b9Sdan      CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
1010432cc5b9Sdan      CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
1011432cc5b9Sdan    }
1012432cc5b9Sdan    execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
1013432cc5b9Sdan  } [list \
1014432cc5b9Sdan    {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)}                     \
1015432cc5b9Sdan    {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)}    \
1016432cc5b9Sdan    {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)}  \
1017432cc5b9Sdan  ]
1018432cc5b9Sdan  do_test fkey2-14.2.2.2 {
1019432cc5b9Sdan    execsql { ALTER TABLE t1 RENAME TO t4 }
1020432cc5b9Sdan    execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
1021432cc5b9Sdan  } [list \
1022432cc5b9Sdan    {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")}                    \
1023432cc5b9Sdan    {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)}     \
1024432cc5b9Sdan    {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
1025432cc5b9Sdan  ]
1026432cc5b9Sdan  do_test fkey2-14.2.2.3 {
1027432cc5b9Sdan    catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
1028f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1029432cc5b9Sdan  do_test fkey2-14.2.2.4 {
1030432cc5b9Sdan    execsql { INSERT INTO t4 VALUES(1, NULL) }
1031432cc5b9Sdan  } {}
1032432cc5b9Sdan  do_test fkey2-14.2.2.5 {
1033432cc5b9Sdan    catchsql { UPDATE t4 SET b = 5 }
1034f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1035432cc5b9Sdan  do_test fkey2-14.2.2.6 {
1036432cc5b9Sdan    catchsql { UPDATE t4 SET b = 1 }
1037432cc5b9Sdan  } {0 {}}
1038432cc5b9Sdan  do_test fkey2-14.2.2.7 {
1039432cc5b9Sdan    execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
1040432cc5b9Sdan  } {}
10419a6ffc84Sdrh
10429a6ffc84Sdrh  # Repeat for TEMP tables
10439a6ffc84Sdrh  #
10449a6ffc84Sdrh  drop_all_tables
10459a6ffc84Sdrh  do_test fkey2-14.1tmp.1 {
10469a6ffc84Sdrh    # Adding a column with a REFERENCES clause is not supported.
10479a6ffc84Sdrh    execsql {
10489a6ffc84Sdrh      CREATE TEMP TABLE t1(a PRIMARY KEY);
10499a6ffc84Sdrh      CREATE TEMP TABLE t2(a, b);
10509e5fdc41Sdrh      INSERT INTO temp.t2 VALUES(1,2);
10519a6ffc84Sdrh    }
10529a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
10539a6ffc84Sdrh  } {0 {}}
10549a6ffc84Sdrh  do_test fkey2-14.1tmp.2 {
10559a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
10569a6ffc84Sdrh  } {0 {}}
10579a6ffc84Sdrh  do_test fkey2-14.1tmp.3 {
10589a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
10599a6ffc84Sdrh  } {0 {}}
10609a6ffc84Sdrh  do_test fkey2-14.1tmp.4 {
10619a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
10629a6ffc84Sdrh  } {1 {Cannot add a REFERENCES column with non-NULL default value}}
10639a6ffc84Sdrh  do_test fkey2-14.1tmp.5 {
10649a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
10659a6ffc84Sdrh  } {1 {Cannot add a REFERENCES column with non-NULL default value}}
10669a6ffc84Sdrh  do_test fkey2-14.1tmp.6 {
10679a6ffc84Sdrh    execsql {
10689a6ffc84Sdrh      PRAGMA foreign_keys = off;
10699a6ffc84Sdrh      ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
10709a6ffc84Sdrh      PRAGMA foreign_keys = on;
1071e0a04a36Sdrh      SELECT sql FROM temp.sqlite_master WHERE name='t2';
10729a6ffc84Sdrh    }
10739a6ffc84Sdrh  } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
10749a6ffc84Sdrh
1075171c50ecSdrh  sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
10769a6ffc84Sdrh  do_test fkey2-14.2tmp.1.1 {
10779a6ffc84Sdrh    test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
10789a6ffc84Sdrh  } {{CREATE TABLE t1(a REFERENCES "t3")}}
10799a6ffc84Sdrh  do_test fkey2-14.2tmp.1.2 {
10809a6ffc84Sdrh    test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
10819a6ffc84Sdrh  } {{CREATE TABLE t1(a REFERENCES t2)}}
10829a6ffc84Sdrh  do_test fkey2-14.2tmp.1.3 {
10839a6ffc84Sdrh    test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
10849a6ffc84Sdrh  } {{CREATE TABLE t1(a REFERENCES "t3")}}
1085171c50ecSdrh  sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
10869a6ffc84Sdrh
10879a6ffc84Sdrh  # Test ALTER TABLE RENAME TABLE a bit.
10889a6ffc84Sdrh  #
10899a6ffc84Sdrh  do_test fkey2-14.2tmp.2.1 {
10909a6ffc84Sdrh    drop_all_tables
10919a6ffc84Sdrh    execsql {
10929a6ffc84Sdrh      CREATE TEMP TABLE t1(a PRIMARY KEY, b REFERENCES t1);
10939a6ffc84Sdrh      CREATE TEMP TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
10949a6ffc84Sdrh      CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
10959a6ffc84Sdrh    }
10969a6ffc84Sdrh    execsql { SELECT sql FROM sqlite_temp_master WHERE type = 'table'}
10979a6ffc84Sdrh  } [list \
10989a6ffc84Sdrh    {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)}                     \
10999a6ffc84Sdrh    {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)}    \
11009a6ffc84Sdrh    {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)}  \
11019a6ffc84Sdrh  ]
11029a6ffc84Sdrh  do_test fkey2-14.2tmp.2.2 {
11039a6ffc84Sdrh    execsql { ALTER TABLE t1 RENAME TO t4 }
1104e0a04a36Sdrh    execsql { SELECT sql FROM temp.sqlite_master WHERE type = 'table'}
11059a6ffc84Sdrh  } [list \
11069a6ffc84Sdrh    {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")}                    \
11079a6ffc84Sdrh    {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)}     \
11089a6ffc84Sdrh    {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
11099a6ffc84Sdrh  ]
11109a6ffc84Sdrh  do_test fkey2-14.2tmp.2.3 {
11119a6ffc84Sdrh    catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
1112f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
11139a6ffc84Sdrh  do_test fkey2-14.2tmp.2.4 {
11149a6ffc84Sdrh    execsql { INSERT INTO t4 VALUES(1, NULL) }
11159a6ffc84Sdrh  } {}
11169a6ffc84Sdrh  do_test fkey2-14.2tmp.2.5 {
11179a6ffc84Sdrh    catchsql { UPDATE t4 SET b = 5 }
1118f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
11199a6ffc84Sdrh  do_test fkey2-14.2tmp.2.6 {
11209a6ffc84Sdrh    catchsql { UPDATE t4 SET b = 1 }
11219a6ffc84Sdrh  } {0 {}}
11229a6ffc84Sdrh  do_test fkey2-14.2tmp.2.7 {
11239a6ffc84Sdrh    execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
11249a6ffc84Sdrh  } {}
11259a6ffc84Sdrh
11269a6ffc84Sdrh  # Repeat for ATTACH-ed tables
11279a6ffc84Sdrh  #
11289a6ffc84Sdrh  drop_all_tables
11299a6ffc84Sdrh  do_test fkey2-14.1aux.1 {
11309a6ffc84Sdrh    # Adding a column with a REFERENCES clause is not supported.
11319a6ffc84Sdrh    execsql {
11329a6ffc84Sdrh      ATTACH ':memory:' AS aux;
11339a6ffc84Sdrh      CREATE TABLE aux.t1(a PRIMARY KEY);
11349a6ffc84Sdrh      CREATE TABLE aux.t2(a, b);
11359e5fdc41Sdrh      INSERT INTO aux.t2(a,b) VALUES(1,2);
11369a6ffc84Sdrh    }
11379a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
11389a6ffc84Sdrh  } {0 {}}
11399a6ffc84Sdrh  do_test fkey2-14.1aux.2 {
11409a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
11419a6ffc84Sdrh  } {0 {}}
11429a6ffc84Sdrh  do_test fkey2-14.1aux.3 {
11439a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
11449a6ffc84Sdrh  } {0 {}}
11459a6ffc84Sdrh  do_test fkey2-14.1aux.4 {
11469a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
11479a6ffc84Sdrh  } {1 {Cannot add a REFERENCES column with non-NULL default value}}
11489a6ffc84Sdrh  do_test fkey2-14.1aux.5 {
11499a6ffc84Sdrh    catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
11509a6ffc84Sdrh  } {1 {Cannot add a REFERENCES column with non-NULL default value}}
11519a6ffc84Sdrh  do_test fkey2-14.1aux.6 {
11529a6ffc84Sdrh    execsql {
11539a6ffc84Sdrh      PRAGMA foreign_keys = off;
11549a6ffc84Sdrh      ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
11559a6ffc84Sdrh      PRAGMA foreign_keys = on;
11569a6ffc84Sdrh      SELECT sql FROM aux.sqlite_master WHERE name='t2';
11579a6ffc84Sdrh    }
11589a6ffc84Sdrh  } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
11599a6ffc84Sdrh
1160171c50ecSdrh  sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
11619a6ffc84Sdrh  do_test fkey2-14.2aux.1.1 {
11629a6ffc84Sdrh    test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
11639a6ffc84Sdrh  } {{CREATE TABLE t1(a REFERENCES "t3")}}
11649a6ffc84Sdrh  do_test fkey2-14.2aux.1.2 {
11659a6ffc84Sdrh    test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
11669a6ffc84Sdrh  } {{CREATE TABLE t1(a REFERENCES t2)}}
11679a6ffc84Sdrh  do_test fkey2-14.2aux.1.3 {
11689a6ffc84Sdrh    test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
11699a6ffc84Sdrh  } {{CREATE TABLE t1(a REFERENCES "t3")}}
1170171c50ecSdrh  sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db
11719a6ffc84Sdrh
11729a6ffc84Sdrh  # Test ALTER TABLE RENAME TABLE a bit.
11739a6ffc84Sdrh  #
11749a6ffc84Sdrh  do_test fkey2-14.2aux.2.1 {
11759a6ffc84Sdrh    drop_all_tables
11769a6ffc84Sdrh    execsql {
11779a6ffc84Sdrh      CREATE TABLE aux.t1(a PRIMARY KEY, b REFERENCES t1);
11789a6ffc84Sdrh      CREATE TABLE aux.t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
11799a6ffc84Sdrh      CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
11809a6ffc84Sdrh    }
11819a6ffc84Sdrh    execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
11829a6ffc84Sdrh  } [list \
11839a6ffc84Sdrh    {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)}                     \
11849a6ffc84Sdrh    {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)}    \
11859a6ffc84Sdrh    {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)}  \
11869a6ffc84Sdrh  ]
11879a6ffc84Sdrh  do_test fkey2-14.2aux.2.2 {
11889a6ffc84Sdrh    execsql { ALTER TABLE t1 RENAME TO t4 }
11899a6ffc84Sdrh    execsql { SELECT sql FROM aux.sqlite_master WHERE type = 'table'}
11909a6ffc84Sdrh  } [list \
11919a6ffc84Sdrh    {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")}                    \
11929a6ffc84Sdrh    {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)}     \
11939a6ffc84Sdrh    {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
11949a6ffc84Sdrh  ]
11959a6ffc84Sdrh  do_test fkey2-14.2aux.2.3 {
11969a6ffc84Sdrh    catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
1197f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
11989a6ffc84Sdrh  do_test fkey2-14.2aux.2.4 {
11999a6ffc84Sdrh    execsql { INSERT INTO t4 VALUES(1, NULL) }
12009a6ffc84Sdrh  } {}
12019a6ffc84Sdrh  do_test fkey2-14.2aux.2.5 {
12029a6ffc84Sdrh    catchsql { UPDATE t4 SET b = 5 }
1203f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
12049a6ffc84Sdrh  do_test fkey2-14.2aux.2.6 {
12059a6ffc84Sdrh    catchsql { UPDATE t4 SET b = 1 }
12069a6ffc84Sdrh  } {0 {}}
12079a6ffc84Sdrh  do_test fkey2-14.2aux.2.7 {
12089a6ffc84Sdrh    execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
12099a6ffc84Sdrh  } {}
1210856ef1a5Sdan}
1211432cc5b9Sdan
1212f0662567Sdando_test fkey-2.14.3.1 {
1213f0662567Sdan  drop_all_tables
1214f0662567Sdan  execsql {
1215f0662567Sdan    CREATE TABLE t1(a, b REFERENCES nosuchtable);
1216f0662567Sdan    DROP TABLE t1;
1217f0662567Sdan  }
1218f0662567Sdan} {}
1219f0662567Sdando_test fkey-2.14.3.2 {
1220f0662567Sdan  execsql {
1221f0662567Sdan    CREATE TABLE t1(a PRIMARY KEY, b);
1222f0662567Sdan    INSERT INTO t1 VALUES('a', 1);
1223f0662567Sdan    CREATE TABLE t2(x REFERENCES t1);
1224f0662567Sdan    INSERT INTO t2 VALUES('a');
1225f0662567Sdan  }
1226f0662567Sdan} {}
1227f0662567Sdando_test fkey-2.14.3.3 {
1228f0662567Sdan  catchsql { DROP TABLE t1 }
1229f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
1230f0662567Sdando_test fkey-2.14.3.4 {
1231f0662567Sdan  execsql {
1232f0662567Sdan    DELETE FROM t2;
1233f0662567Sdan    DROP TABLE t1;
1234f0662567Sdan  }
1235f0662567Sdan} {}
1236f0662567Sdando_test fkey-2.14.3.4 {
1237f0662567Sdan  catchsql { INSERT INTO t2 VALUES('x') }
1238f0662567Sdan} {1 {no such table: main.t1}}
1239f0662567Sdando_test fkey-2.14.3.5 {
1240f0662567Sdan  execsql {
1241f0662567Sdan    CREATE TABLE t1(x PRIMARY KEY);
1242f0662567Sdan    INSERT INTO t1 VALUES('x');
1243f0662567Sdan  }
1244f0662567Sdan  execsql { INSERT INTO t2 VALUES('x') }
1245f0662567Sdan} {}
1246f0662567Sdando_test fkey-2.14.3.6 {
1247f0662567Sdan  catchsql { DROP TABLE t1 }
1248f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
1249f0662567Sdando_test fkey-2.14.3.7 {
1250f0662567Sdan  execsql {
1251f0662567Sdan    DROP TABLE t2;
1252f0662567Sdan    DROP TABLE t1;
1253f0662567Sdan  }
1254f0662567Sdan} {}
1255f0662567Sdando_test fkey-2.14.3.8 {
1256f0662567Sdan  execsql {
1257f0662567Sdan    CREATE TABLE pp(x, y, PRIMARY KEY(x, y));
1258f0662567Sdan    CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp(x, z));
1259f0662567Sdan  }
1260f0662567Sdan  catchsql { INSERT INTO cc VALUES(1, 2) }
12619148defaSdrh} {1 {foreign key mismatch - "cc" referencing "pp"}}
1262f0662567Sdando_test fkey-2.14.3.9 {
1263f0662567Sdan  execsql { DROP TABLE cc }
1264f0662567Sdan} {}
1265f7a94543Sdando_test fkey-2.14.3.10 {
1266f7a94543Sdan  execsql {
1267f7a94543Sdan    CREATE TABLE cc(a, b,
1268f7a94543Sdan      FOREIGN KEY(a, b) REFERENCES pp DEFERRABLE INITIALLY DEFERRED
1269f7a94543Sdan    );
1270f7a94543Sdan  }
1271f7a94543Sdan  execsql {
1272f7a94543Sdan    INSERT INTO pp VALUES('a', 'b');
1273f7a94543Sdan    INSERT INTO cc VALUES('a', 'b');
1274f7a94543Sdan    BEGIN;
1275f7a94543Sdan      DROP TABLE pp;
1276f7a94543Sdan      CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c));
1277f7a94543Sdan      INSERT INTO pp VALUES(1, 'a', 'b');
1278f7a94543Sdan    COMMIT;
1279f7a94543Sdan  }
1280f7a94543Sdan} {}
1281f7a94543Sdando_test fkey-2.14.3.11 {
1282f7a94543Sdan  execsql {
1283f7a94543Sdan    BEGIN;
1284f7a94543Sdan      DROP TABLE cc;
1285f7a94543Sdan      DROP TABLE pp;
1286f7a94543Sdan    COMMIT;
1287f7a94543Sdan  }
1288f7a94543Sdan} {}
1289f7a94543Sdando_test fkey-2.14.3.12 {
1290f7a94543Sdan  execsql {
1291f7a94543Sdan    CREATE TABLE b1(a, b);
1292f7a94543Sdan    CREATE TABLE b2(a, b REFERENCES b1);
1293f7a94543Sdan    DROP TABLE b1;
1294f7a94543Sdan  }
1295f7a94543Sdan} {}
1296f7a94543Sdando_test fkey-2.14.3.13 {
1297f7a94543Sdan  execsql {
1298f7a94543Sdan    CREATE TABLE b3(a, b REFERENCES b2 DEFERRABLE INITIALLY DEFERRED);
1299f7a94543Sdan    DROP TABLE b2;
1300f7a94543Sdan  }
1301f7a94543Sdan} {}
1302f7a94543Sdan
1303f7a94543Sdan# Test that nothing goes wrong when dropping a table that refers to a view.
1304f7a94543Sdan# Or dropping a view that an existing FK (incorrectly) refers to. Or either
1305f7a94543Sdan# of the above scenarios with a virtual table.
1306f7a94543Sdandrop_all_tables
1307f7a94543Sdando_test fkey-2.14.4.1 {
1308f7a94543Sdan  execsql {
1309f7a94543Sdan    CREATE TABLE t1(x REFERENCES v);
1310f7a94543Sdan    CREATE VIEW v AS SELECT * FROM t1;
1311f7a94543Sdan  }
1312f7a94543Sdan} {}
1313f7a94543Sdando_test fkey-2.14.4.2 {
1314f7a94543Sdan  execsql {
1315f7a94543Sdan    DROP VIEW v;
1316f7a94543Sdan  }
1317f7a94543Sdan} {}
1318f7a94543Sdanifcapable vtab {
1319f7a94543Sdan  register_echo_module db
1320f7a94543Sdan  do_test fkey-2.14.4.3 {
1321f7a94543Sdan    execsql { CREATE VIRTUAL TABLE v USING echo(t1) }
1322f7a94543Sdan  } {}
1323f7a94543Sdan  do_test fkey-2.14.4.2 {
1324f7a94543Sdan    execsql {
1325f7a94543Sdan      DROP TABLE v;
1326f7a94543Sdan    }
1327f7a94543Sdan  } {}
1328f7a94543Sdan}
1329f0662567Sdan
133053c3fa8dSdan#-------------------------------------------------------------------------
13310ff297eaSdan# The following tests, fkey2-15.*, test that unnecessary FK related scans
13320ff297eaSdan# and lookups are avoided when the constraint counters are zero.
13330ff297eaSdan#
13340ff297eaSdandrop_all_tables
13350ff297eaSdanproc execsqlS {zSql} {
13360ff297eaSdan  set ::sqlite_search_count 0
13370ff297eaSdan  set ::sqlite_found_count 0
13380ff297eaSdan  set res [uplevel [list execsql $zSql]]
13390ff297eaSdan  concat [expr $::sqlite_found_count + $::sqlite_search_count] $res
13400ff297eaSdan}
13410ff297eaSdando_test fkey2-15.1.1 {
13420ff297eaSdan  execsql {
13430ff297eaSdan    CREATE TABLE pp(a PRIMARY KEY, b);
13440ff297eaSdan    CREATE TABLE cc(x, y REFERENCES pp DEFERRABLE INITIALLY DEFERRED);
13450ff297eaSdan    INSERT INTO pp VALUES(1, 'one');
13460ff297eaSdan    INSERT INTO pp VALUES(2, 'two');
13470ff297eaSdan    INSERT INTO cc VALUES('neung', 1);
13480ff297eaSdan    INSERT INTO cc VALUES('song', 2);
13490ff297eaSdan  }
13500ff297eaSdan} {}
13510ff297eaSdando_test fkey2-15.1.2 {
13520ff297eaSdan  execsqlS { INSERT INTO pp VALUES(3, 'three') }
13530ff297eaSdan} {0}
13540ff297eaSdando_test fkey2-15.1.3 {
13550ff297eaSdan  execsql {
13560ff297eaSdan    BEGIN;
13570ff297eaSdan      INSERT INTO cc VALUES('see', 4);    -- Violates deferred constraint
13580ff297eaSdan  }
13590ff297eaSdan  execsqlS { INSERT INTO pp VALUES(5, 'five') }
13600ff297eaSdan} {2}
13610ff297eaSdando_test fkey2-15.1.4 {
13620ff297eaSdan  execsql { DELETE FROM cc WHERE x = 'see' }
13630ff297eaSdan  execsqlS { INSERT INTO pp VALUES(6, 'six') }
13640ff297eaSdan} {0}
13650ff297eaSdando_test fkey2-15.1.5 {
13660ff297eaSdan  execsql COMMIT
13670ff297eaSdan} {}
13680ff297eaSdando_test fkey2-15.1.6 {
13690ff297eaSdan  execsql BEGIN
13700ff297eaSdan  execsqlS {
13710ff297eaSdan    DELETE FROM cc WHERE x = 'neung';
13720ff297eaSdan    ROLLBACK;
13730ff297eaSdan  }
13740ff297eaSdan} {1}
13750ff297eaSdando_test fkey2-15.1.7 {
13760ff297eaSdan  execsql {
13770ff297eaSdan    BEGIN;
13780ff297eaSdan    DELETE FROM pp WHERE a = 2;
13790ff297eaSdan  }
13800ff297eaSdan  execsqlS {
13810ff297eaSdan    DELETE FROM cc WHERE x = 'neung';
13820ff297eaSdan    ROLLBACK;
13830ff297eaSdan  }
13840ff297eaSdan} {2}
13850ff297eaSdan
13869277efa3Sdan#-------------------------------------------------------------------------
13879277efa3Sdan# This next block of tests, fkey2-16.*, test that rows that refer to
13889277efa3Sdan# themselves may be inserted and deleted.
13899277efa3Sdan#
13909277efa3Sdanforeach {tn zSchema} {
13919277efa3Sdan  1 { CREATE TABLE self(a INTEGER PRIMARY KEY, b REFERENCES self(a)) }
13929277efa3Sdan  2 { CREATE TABLE self(a PRIMARY KEY, b REFERENCES self(a)) }
13939277efa3Sdan  3 { CREATE TABLE self(a UNIQUE, b INTEGER PRIMARY KEY REFERENCES self(a)) }
13949277efa3Sdan} {
13959277efa3Sdan  drop_all_tables
13969277efa3Sdan  do_test fkey2-16.1.$tn.1 {
13979277efa3Sdan    execsql $zSchema
13989277efa3Sdan    execsql { INSERT INTO self VALUES(13, 13) }
13999277efa3Sdan  } {}
14009277efa3Sdan  do_test fkey2-16.1.$tn.2 {
14019277efa3Sdan    execsql { UPDATE self SET a = 14, b = 14 }
14029277efa3Sdan  } {}
14039277efa3Sdan
14049277efa3Sdan  do_test fkey2-16.1.$tn.3 {
14059277efa3Sdan    catchsql { UPDATE self SET b = 15 }
1406f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
14079277efa3Sdan
14089277efa3Sdan  do_test fkey2-16.1.$tn.4 {
14099277efa3Sdan    catchsql { UPDATE self SET a = 15 }
1410f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
14119277efa3Sdan
14129277efa3Sdan  do_test fkey2-16.1.$tn.5 {
14139277efa3Sdan    catchsql { UPDATE self SET a = 15, b = 16 }
1414f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
14159277efa3Sdan
14169277efa3Sdan  do_test fkey2-16.1.$tn.6 {
14179277efa3Sdan    catchsql { UPDATE self SET a = 17, b = 17 }
14189277efa3Sdan  } {0 {}}
14199277efa3Sdan
14209277efa3Sdan  do_test fkey2-16.1.$tn.7 {
14219277efa3Sdan    execsql { DELETE FROM self }
14229277efa3Sdan  } {}
14239277efa3Sdan  do_test fkey2-16.1.$tn.8 {
14249277efa3Sdan    catchsql { INSERT INTO self VALUES(20, 21) }
1425f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
14269277efa3Sdan}
14279277efa3Sdan
1428d583502eSdan#-------------------------------------------------------------------------
1429d583502eSdan# This next block of tests, fkey2-17.*, tests that if "PRAGMA count_changes"
1430d583502eSdan# is turned on statements that violate immediate FK constraints return
1431d583502eSdan# SQLITE_CONSTRAINT immediately, not after returning a number of rows.
1432d583502eSdan# Whereas statements that violate deferred FK constraints return the number
1433d583502eSdan# of rows before failing.
1434d583502eSdan#
1435d583502eSdan# Also test that rows modified by FK actions are not counted in either the
1436d583502eSdan# returned row count or the values returned by sqlite3_changes(). Like
1437d583502eSdan# trigger related changes, they are included in sqlite3_total_changes() though.
1438d583502eSdan#
1439d583502eSdandrop_all_tables
1440d583502eSdando_test fkey2-17.1.1 {
1441d583502eSdan  execsql { PRAGMA count_changes = 1 }
1442d583502eSdan  execsql {
1443d583502eSdan    CREATE TABLE one(a, b, c, UNIQUE(b, c));
1444d583502eSdan    CREATE TABLE two(d, e, f, FOREIGN KEY(e, f) REFERENCES one(b, c));
1445d583502eSdan    INSERT INTO one VALUES(1, 2, 3);
1446d583502eSdan  }
1447d583502eSdan} {1}
1448d583502eSdando_test fkey2-17.1.2 {
1449d583502eSdan  set STMT [sqlite3_prepare_v2 db "INSERT INTO two VALUES(4, 5, 6)" -1 dummy]
1450d583502eSdan  sqlite3_step $STMT
1451d583502eSdan} {SQLITE_CONSTRAINT}
1452433dccfbSdrhverify_ex_errcode fkey2-17.1.2b SQLITE_CONSTRAINT_FOREIGNKEY
1453602acb48Sdrhifcapable autoreset {
1454d583502eSdan  do_test fkey2-17.1.3 {
1455d583502eSdan    sqlite3_step $STMT
14563674bfd1Sdrh  } {SQLITE_CONSTRAINT}
1457433dccfbSdrh  verify_ex_errcode fkey2-17.1.3b SQLITE_CONSTRAINT_FOREIGNKEY
1458602acb48Sdrh} else {
1459602acb48Sdrh  do_test fkey2-17.1.3 {
1460602acb48Sdrh    sqlite3_step $STMT
1461602acb48Sdrh  } {SQLITE_MISUSE}
1462602acb48Sdrh}
1463d583502eSdando_test fkey2-17.1.4 {
1464d583502eSdan  sqlite3_finalize $STMT
1465d583502eSdan} {SQLITE_CONSTRAINT}
1466433dccfbSdrhverify_ex_errcode fkey2-17.1.4b SQLITE_CONSTRAINT_FOREIGNKEY
1467d583502eSdando_test fkey2-17.1.5 {
1468d583502eSdan  execsql {
1469d583502eSdan    INSERT INTO one VALUES(2, 3, 4);
1470d583502eSdan    INSERT INTO one VALUES(3, 4, 5);
1471d583502eSdan    INSERT INTO two VALUES(1, 2, 3);
1472d583502eSdan    INSERT INTO two VALUES(2, 3, 4);
1473d583502eSdan    INSERT INTO two VALUES(3, 4, 5);
1474d583502eSdan  }
1475d583502eSdan} {1 1 1 1 1}
1476d583502eSdando_test fkey2-17.1.6 {
1477d583502eSdan  catchsql {
1478d583502eSdan    BEGIN;
1479d583502eSdan      INSERT INTO one VALUES(0, 0, 0);
1480d583502eSdan      UPDATE two SET e=e+1, f=f+1;
1481d583502eSdan  }
1482f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
1483d583502eSdando_test fkey2-17.1.7 {
1484d583502eSdan  execsql { SELECT * FROM one }
1485d583502eSdan} {1 2 3 2 3 4 3 4 5 0 0 0}
1486d583502eSdando_test fkey2-17.1.8 {
1487d583502eSdan  execsql { SELECT * FROM two }
1488d583502eSdan} {1 2 3 2 3 4 3 4 5}
1489d583502eSdando_test fkey2-17.1.9 {
1490d583502eSdan  execsql COMMIT
1491d583502eSdan} {}
1492d583502eSdando_test fkey2-17.1.10 {
1493d583502eSdan  execsql {
1494d583502eSdan    CREATE TABLE three(
1495d583502eSdan      g, h, i,
1496d583502eSdan      FOREIGN KEY(h, i) REFERENCES one(b, c) DEFERRABLE INITIALLY DEFERRED
1497d583502eSdan    );
1498d583502eSdan  }
1499d583502eSdan} {}
1500d583502eSdando_test fkey2-17.1.11 {
1501d583502eSdan  set STMT [sqlite3_prepare_v2 db "INSERT INTO three VALUES(7, 8, 9)" -1 dummy]
1502d583502eSdan  sqlite3_step $STMT
1503d583502eSdan} {SQLITE_ROW}
1504d583502eSdando_test fkey2-17.1.12 {
1505d583502eSdan  sqlite3_column_text $STMT 0
1506d583502eSdan} {1}
1507d583502eSdando_test fkey2-17.1.13 {
1508d583502eSdan  sqlite3_step $STMT
1509d583502eSdan} {SQLITE_CONSTRAINT}
1510433dccfbSdrhverify_ex_errcode fkey2-17.1.13b SQLITE_CONSTRAINT_FOREIGNKEY
1511d583502eSdando_test fkey2-17.1.14 {
1512d583502eSdan  sqlite3_finalize $STMT
1513d583502eSdan} {SQLITE_CONSTRAINT}
1514433dccfbSdrhverify_ex_errcode fkey2-17.1.14b SQLITE_CONSTRAINT_FOREIGNKEY
15150ff297eaSdan
1516d583502eSdandrop_all_tables
1517d583502eSdando_test fkey2-17.2.1 {
1518d583502eSdan  execsql {
1519d583502eSdan    CREATE TABLE high("a'b!" PRIMARY KEY, b);
1520d583502eSdan    CREATE TABLE low(
1521d583502eSdan      c,
1522d583502eSdan      "d&6" REFERENCES high ON UPDATE CASCADE ON DELETE CASCADE
1523d583502eSdan    );
1524d583502eSdan  }
1525d583502eSdan} {}
1526d583502eSdando_test fkey2-17.2.2 {
1527d583502eSdan  execsql {
1528d583502eSdan    INSERT INTO high VALUES('a', 'b');
1529d583502eSdan    INSERT INTO low VALUES('b', 'a');
1530d583502eSdan  }
1531d583502eSdan  db changes
1532d583502eSdan} {1}
1533d583502eSdanset nTotal [db total_changes]
1534d583502eSdando_test fkey2-17.2.3 {
1535d583502eSdan  execsql { UPDATE high SET "a'b!" = 'c' }
1536d583502eSdan} {1}
1537d583502eSdando_test fkey2-17.2.4 {
1538d583502eSdan  db changes
1539d583502eSdan} {1}
1540d583502eSdando_test fkey2-17.2.5 {
1541d583502eSdan  expr [db total_changes] - $nTotal
1542d583502eSdan} {2}
1543d583502eSdando_test fkey2-17.2.6 {
1544d583502eSdan  execsql { SELECT * FROM high ; SELECT * FROM low }
1545d583502eSdan} {c b b c}
1546d583502eSdando_test fkey2-17.2.7 {
1547d583502eSdan  execsql { DELETE FROM high }
1548d583502eSdan} {1}
1549d583502eSdando_test fkey2-17.2.8 {
1550d583502eSdan  db changes
1551d583502eSdan} {1}
1552d583502eSdando_test fkey2-17.2.9 {
1553d583502eSdan  expr [db total_changes] - $nTotal
1554d583502eSdan} {4}
1555d583502eSdando_test fkey2-17.2.10 {
1556d583502eSdan  execsql { SELECT * FROM high ; SELECT * FROM low }
1557d583502eSdan} {}
155847a06346Sdanexecsql { PRAGMA count_changes = 0 }
1559d583502eSdan
1560e7a94d81Sdan#-------------------------------------------------------------------------
1561e7a94d81Sdan# Test that the authorization callback works.
1562e7a94d81Sdan#
1563e7a94d81Sdan
156447a06346Sdanifcapable auth {
156547a06346Sdan  do_test fkey2-18.1 {
156647a06346Sdan    execsql {
156747a06346Sdan      CREATE TABLE long(a, b PRIMARY KEY, c);
156847a06346Sdan      CREATE TABLE short(d, e, f REFERENCES long);
156947a06346Sdan      CREATE TABLE mid(g, h, i REFERENCES long DEFERRABLE INITIALLY DEFERRED);
157047a06346Sdan    }
157147a06346Sdan  } {}
1572d583502eSdan
157332c6a48bSdrh  proc auth {args} {eval lappend ::authargs [lrange $args 0 4]; return SQLITE_OK}
157447a06346Sdan  db auth auth
157547a06346Sdan
157647a06346Sdan  # An insert on the parent table must read the child key of any deferred
157747a06346Sdan  # foreign key constraints. But not the child key of immediate constraints.
157847a06346Sdan  set authargs {}
157947a06346Sdan  do_test fkey2-18.2 {
158047a06346Sdan    execsql { INSERT INTO long VALUES(1, 2, 3) }
158147a06346Sdan    set authargs
158247a06346Sdan  } {SQLITE_INSERT long {} main {} SQLITE_READ mid i main {}}
158347a06346Sdan
158447a06346Sdan  # An insert on the child table of an immediate constraint must read the
158547a06346Sdan  # parent key columns (to see if it is a violation or not).
158647a06346Sdan  set authargs {}
158747a06346Sdan  do_test fkey2-18.3 {
158847a06346Sdan    execsql { INSERT INTO short VALUES(1, 3, 2) }
158947a06346Sdan    set authargs
159047a06346Sdan  } {SQLITE_INSERT short {} main {} SQLITE_READ long b main {}}
159147a06346Sdan
159247a06346Sdan  # As must an insert on the child table of a deferred constraint.
159347a06346Sdan  set authargs {}
159447a06346Sdan  do_test fkey2-18.4 {
159547a06346Sdan    execsql { INSERT INTO mid VALUES(1, 3, 2) }
159647a06346Sdan    set authargs
159747a06346Sdan  } {SQLITE_INSERT mid {} main {} SQLITE_READ long b main {}}
159847a06346Sdan
159947a06346Sdan  do_test fkey2-18.5 {
160047a06346Sdan    execsql {
160147a06346Sdan      CREATE TABLE nought(a, b PRIMARY KEY, c);
160247a06346Sdan      CREATE TABLE cross(d, e, f,
160347a06346Sdan        FOREIGN KEY(e) REFERENCES nought(b) ON UPDATE CASCADE
160447a06346Sdan      );
160547a06346Sdan    }
160647a06346Sdan    execsql { INSERT INTO nought VALUES(2, 1, 2) }
160747a06346Sdan    execsql { INSERT INTO cross VALUES(0, 1, 0) }
160847a06346Sdan    set authargs [list]
160947a06346Sdan    execsql { UPDATE nought SET b = 5 }
161047a06346Sdan    set authargs
161147a06346Sdan  } {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 {}}
161247a06346Sdan
161347a06346Sdan  do_test fkey2-18.6 {
161447a06346Sdan    execsql {SELECT * FROM cross}
161547a06346Sdan  } {0 5 0}
161647a06346Sdan
1617251ad6e1Sdan  do_test fkey2-18.7 {
1618251ad6e1Sdan    execsql {
1619251ad6e1Sdan      CREATE TABLE one(a INTEGER PRIMARY KEY, b);
1620251ad6e1Sdan      CREATE TABLE two(b, c REFERENCES one);
1621251ad6e1Sdan      INSERT INTO one VALUES(101, 102);
1622251ad6e1Sdan    }
1623251ad6e1Sdan    set authargs [list]
1624251ad6e1Sdan    execsql { INSERT INTO two VALUES(100, 101); }
1625251ad6e1Sdan    set authargs
1626251ad6e1Sdan  } {SQLITE_INSERT two {} main {} SQLITE_READ one a main {}}
1627251ad6e1Sdan
162802470b20Sdan  # Return SQLITE_IGNORE to requests to read from the parent table. This
162902470b20Sdan  # causes inserts of non-NULL keys into the child table to fail.
163002470b20Sdan  #
163147a06346Sdan  rename auth {}
163247a06346Sdan  proc auth {args} {
163347a06346Sdan    if {[lindex $args 1] == "long"} {return SQLITE_IGNORE}
163447a06346Sdan    return SQLITE_OK
163547a06346Sdan  }
1636251ad6e1Sdan  do_test fkey2-18.8 {
163747a06346Sdan    catchsql { INSERT INTO short VALUES(1, 3, 2) }
1638f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
163902470b20Sdan  do_test fkey2-18.9 {
164002470b20Sdan    execsql { INSERT INTO short VALUES(1, 3, NULL) }
164102470b20Sdan  } {}
164202470b20Sdan  do_test fkey2-18.10 {
164302470b20Sdan    execsql { SELECT * FROM short }
164402470b20Sdan  } {1 3 2 1 3 {}}
164502470b20Sdan  do_test fkey2-18.11 {
164602470b20Sdan    catchsql { UPDATE short SET f = 2 WHERE f IS NULL }
1647f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
164847a06346Sdan
164947a06346Sdan  db auth {}
165047a06346Sdan  unset authargs
165147a06346Sdan}
165247a06346Sdan
16536908343cSdan
16546908343cSdando_test fkey2-19.1 {
16556908343cSdan  execsql {
16566908343cSdan    CREATE TABLE main(id INTEGER PRIMARY KEY);
16576908343cSdan    CREATE TABLE sub(id INT REFERENCES main(id));
16586908343cSdan    INSERT INTO main VALUES(1);
16596908343cSdan    INSERT INTO main VALUES(2);
16606908343cSdan    INSERT INTO sub VALUES(2);
16616908343cSdan  }
16626908343cSdan} {}
16636908343cSdando_test fkey2-19.2 {
16646908343cSdan  set S [sqlite3_prepare_v2 db "DELETE FROM main WHERE id = ?" -1 dummy]
16656908343cSdan  sqlite3_bind_int $S 1 2
16666908343cSdan  sqlite3_step $S
16676908343cSdan} {SQLITE_CONSTRAINT}
1668433dccfbSdrhverify_ex_errcode fkey2-19.2b SQLITE_CONSTRAINT_FOREIGNKEY
16696908343cSdando_test fkey2-19.3 {
16706908343cSdan  sqlite3_reset $S
16716908343cSdan} {SQLITE_CONSTRAINT}
1672433dccfbSdrhverify_ex_errcode fkey2-19.3b SQLITE_CONSTRAINT_FOREIGNKEY
16736908343cSdando_test fkey2-19.4 {
16746908343cSdan  sqlite3_bind_int $S 1 1
16756908343cSdan  sqlite3_step $S
16766908343cSdan} {SQLITE_DONE}
16776908343cSdando_test fkey2-19.4 {
16786908343cSdan  sqlite3_finalize $S
16796908343cSdan} {SQLITE_OK}
16806908343cSdan
1681a7a0c615Sdandrop_all_tables
1682a7a0c615Sdando_test fkey2-20.1 {
1683a7a0c615Sdan  execsql {
1684a7a0c615Sdan    CREATE TABLE pp(a PRIMARY KEY, b);
1685a7a0c615Sdan    CREATE TABLE cc(c PRIMARY KEY, d REFERENCES pp);
1686a7a0c615Sdan  }
1687a7a0c615Sdan} {}
1688a7a0c615Sdan
1689a7a0c615Sdanforeach {tn insert} {
1690a7a0c615Sdan  1 "INSERT"
1691a7a0c615Sdan  2 "INSERT OR IGNORE"
1692a7a0c615Sdan  3 "INSERT OR ABORT"
1693a7a0c615Sdan  4 "INSERT OR ROLLBACK"
1694a7a0c615Sdan  5 "INSERT OR REPLACE"
1695a7a0c615Sdan  6 "INSERT OR FAIL"
1696a7a0c615Sdan} {
1697a7a0c615Sdan  do_test fkey2-20.2.$tn.1 {
1698a7a0c615Sdan    catchsql "$insert INTO cc VALUES(1, 2)"
1699f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1700a7a0c615Sdan  do_test fkey2-20.2.$tn.2 {
1701a7a0c615Sdan    execsql { SELECT * FROM cc }
1702a7a0c615Sdan  } {}
1703a7a0c615Sdan  do_test fkey2-20.2.$tn.3 {
1704a7a0c615Sdan    execsql {
1705a7a0c615Sdan      BEGIN;
1706a7a0c615Sdan        INSERT INTO pp VALUES(2, 'two');
1707a7a0c615Sdan        INSERT INTO cc VALUES(1, 2);
1708a7a0c615Sdan    }
1709a7a0c615Sdan    catchsql "$insert INTO cc VALUES(3, 4)"
1710f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1711a7a0c615Sdan  do_test fkey2-20.2.$tn.4 {
1712a7a0c615Sdan    execsql { COMMIT ; SELECT * FROM cc }
1713a7a0c615Sdan  } {1 2}
1714a7a0c615Sdan  do_test fkey2-20.2.$tn.5 {
1715a7a0c615Sdan    execsql { DELETE FROM cc ; DELETE FROM pp }
1716a7a0c615Sdan  } {}
1717a7a0c615Sdan}
1718a7a0c615Sdan
1719a7a0c615Sdanforeach {tn update} {
1720a7a0c615Sdan  1 "UPDATE"
1721a7a0c615Sdan  2 "UPDATE OR IGNORE"
1722a7a0c615Sdan  3 "UPDATE OR ABORT"
1723a7a0c615Sdan  4 "UPDATE OR ROLLBACK"
1724a7a0c615Sdan  5 "UPDATE OR REPLACE"
1725a7a0c615Sdan  6 "UPDATE OR FAIL"
1726a7a0c615Sdan} {
1727a7a0c615Sdan  do_test fkey2-20.3.$tn.1 {
1728a7a0c615Sdan    execsql {
1729a7a0c615Sdan      INSERT INTO pp VALUES(2, 'two');
1730a7a0c615Sdan      INSERT INTO cc VALUES(1, 2);
1731a7a0c615Sdan    }
1732a7a0c615Sdan  } {}
1733a7a0c615Sdan  do_test fkey2-20.3.$tn.2 {
1734a7a0c615Sdan    catchsql "$update pp SET a = 1"
1735f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1736a7a0c615Sdan  do_test fkey2-20.3.$tn.3 {
1737a7a0c615Sdan    execsql { SELECT * FROM pp }
1738a7a0c615Sdan  } {2 two}
1739a7a0c615Sdan  do_test fkey2-20.3.$tn.4 {
1740a7a0c615Sdan    catchsql "$update cc SET d = 1"
1741f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1742a7a0c615Sdan  do_test fkey2-20.3.$tn.5 {
1743a7a0c615Sdan    execsql { SELECT * FROM cc }
1744a7a0c615Sdan  } {1 2}
1745a7a0c615Sdan  do_test fkey2-20.3.$tn.6 {
1746a7a0c615Sdan    execsql {
1747a7a0c615Sdan      BEGIN;
1748a7a0c615Sdan        INSERT INTO pp VALUES(3, 'three');
1749a7a0c615Sdan    }
1750a7a0c615Sdan    catchsql "$update pp SET a = 1 WHERE a = 2"
1751f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1752a7a0c615Sdan  do_test fkey2-20.3.$tn.7 {
1753a7a0c615Sdan    execsql { COMMIT ; SELECT * FROM pp }
1754a7a0c615Sdan  } {2 two 3 three}
1755a7a0c615Sdan  do_test fkey2-20.3.$tn.8 {
1756a7a0c615Sdan    execsql {
1757a7a0c615Sdan      BEGIN;
1758a7a0c615Sdan        INSERT INTO cc VALUES(2, 2);
1759a7a0c615Sdan    }
1760a7a0c615Sdan    catchsql "$update cc SET d = 1 WHERE c = 1"
1761f9c8ce3cSdrh  } {1 {FOREIGN KEY constraint failed}}
1762a7a0c615Sdan  do_test fkey2-20.3.$tn.9 {
1763a7a0c615Sdan    execsql { COMMIT ; SELECT * FROM cc }
1764a7a0c615Sdan  } {1 2 2 2}
1765a7a0c615Sdan  do_test fkey2-20.3.$tn.10 {
1766a7a0c615Sdan    execsql { DELETE FROM cc ; DELETE FROM pp }
1767a7a0c615Sdan  } {}
1768a7a0c615Sdan}
1769a7a0c615Sdan
17700ff297eaSdan#-------------------------------------------------------------------------
17711da40a38Sdan# The following block of tests, those prefixed with "fkey2-genfkey.", are
17721da40a38Sdan# the same tests that were used to test the ".genfkey" command provided
17731da40a38Sdan# by the shell tool. So these tests show that the built-in foreign key
17741da40a38Sdan# implementation is more or less compatible with the triggers generated
17751da40a38Sdan# by genfkey.
17761da40a38Sdan#
17771da40a38Sdandrop_all_tables
17781da40a38Sdando_test fkey2-genfkey.1.1 {
17791da40a38Sdan  execsql {
17801da40a38Sdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
17811da40a38Sdan    CREATE TABLE t2(e REFERENCES t1, f);
17821da40a38Sdan    CREATE TABLE t3(g, h, i, FOREIGN KEY (h, i) REFERENCES t1(b, c));
17831da40a38Sdan  }
17841da40a38Sdan} {}
17851da40a38Sdando_test fkey2-genfkey.1.2 {
17861da40a38Sdan  catchsql { INSERT INTO t2 VALUES(1, 2) }
1787f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
17881da40a38Sdando_test fkey2-genfkey.1.3 {
17891da40a38Sdan  execsql {
17901da40a38Sdan    INSERT INTO t1 VALUES(1, 2, 3);
17911da40a38Sdan    INSERT INTO t2 VALUES(1, 2);
17921da40a38Sdan  }
17931da40a38Sdan} {}
17941da40a38Sdando_test fkey2-genfkey.1.4 {
17951da40a38Sdan  execsql { INSERT INTO t2 VALUES(NULL, 3) }
17961da40a38Sdan} {}
17971da40a38Sdando_test fkey2-genfkey.1.5 {
17981da40a38Sdan  catchsql { UPDATE t2 SET e = 5 WHERE e IS NULL }
1799f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
18001da40a38Sdando_test fkey2-genfkey.1.6 {
18011da40a38Sdan  execsql { UPDATE t2 SET e = 1 WHERE e IS NULL }
18021da40a38Sdan} {}
18031da40a38Sdando_test fkey2-genfkey.1.7 {
18041da40a38Sdan  execsql { UPDATE t2 SET e = NULL WHERE f = 3 }
18051da40a38Sdan} {}
18061da40a38Sdando_test fkey2-genfkey.1.8 {
18071da40a38Sdan  catchsql { UPDATE t1 SET a = 10 }
1808f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
18091da40a38Sdando_test fkey2-genfkey.1.9 {
18101da40a38Sdan  catchsql { UPDATE t1 SET a = NULL }
18111da40a38Sdan} {1 {datatype mismatch}}
18121da40a38Sdando_test fkey2-genfkey.1.10 {
18131da40a38Sdan  catchsql { DELETE FROM t1 }
1814f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
18151da40a38Sdando_test fkey2-genfkey.1.11 {
18161da40a38Sdan  execsql { UPDATE t2 SET e = NULL }
18171da40a38Sdan} {}
18181da40a38Sdando_test fkey2-genfkey.1.12 {
18191da40a38Sdan  execsql {
18201da40a38Sdan    UPDATE t1 SET a = 10;
18211da40a38Sdan    DELETE FROM t1;
18221da40a38Sdan    DELETE FROM t2;
18231da40a38Sdan  }
18241da40a38Sdan} {}
18251da40a38Sdando_test fkey2-genfkey.1.13 {
18261da40a38Sdan  execsql {
18271da40a38Sdan    INSERT INTO t3 VALUES(1, NULL, NULL);
18281da40a38Sdan    INSERT INTO t3 VALUES(1, 2, NULL);
18291da40a38Sdan    INSERT INTO t3 VALUES(1, NULL, 3);
18301da40a38Sdan  }
18311da40a38Sdan} {}
18321da40a38Sdando_test fkey2-genfkey.1.14 {
18331da40a38Sdan  catchsql { INSERT INTO t3 VALUES(3, 1, 4) }
1834f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
18351da40a38Sdando_test fkey2-genfkey.1.15 {
18361da40a38Sdan  execsql {
18371da40a38Sdan    INSERT INTO t1 VALUES(1, 1, 4);
18381da40a38Sdan    INSERT INTO t3 VALUES(3, 1, 4);
18391da40a38Sdan  }
18401da40a38Sdan} {}
18411da40a38Sdando_test fkey2-genfkey.1.16 {
18421da40a38Sdan  catchsql { DELETE FROM t1 }
1843f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
18441da40a38Sdando_test fkey2-genfkey.1.17 {
18451da40a38Sdan  catchsql { UPDATE t1 SET b = 10}
1846f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
18471da40a38Sdando_test fkey2-genfkey.1.18 {
18481da40a38Sdan  execsql { UPDATE t1 SET a = 10}
18491da40a38Sdan} {}
18501da40a38Sdando_test fkey2-genfkey.1.19 {
18511da40a38Sdan  catchsql { UPDATE t3 SET h = 'hello' WHERE i = 3}
1852f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
18531da40a38Sdan
18541da40a38Sdandrop_all_tables
18551da40a38Sdando_test fkey2-genfkey.2.1 {
18561da40a38Sdan  execsql {
18571da40a38Sdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
18581da40a38Sdan    CREATE TABLE t2(e REFERENCES t1 ON UPDATE CASCADE ON DELETE CASCADE, f);
18591da40a38Sdan    CREATE TABLE t3(g, h, i,
18601da40a38Sdan        FOREIGN KEY (h, i)
18611da40a38Sdan        REFERENCES t1(b, c) ON UPDATE CASCADE ON DELETE CASCADE
18621da40a38Sdan    );
18631da40a38Sdan  }
18641da40a38Sdan} {}
18651da40a38Sdando_test fkey2-genfkey.2.2 {
18661da40a38Sdan  execsql {
18671da40a38Sdan    INSERT INTO t1 VALUES(1, 2, 3);
18681da40a38Sdan    INSERT INTO t1 VALUES(4, 5, 6);
18691da40a38Sdan    INSERT INTO t2 VALUES(1, 'one');
18701da40a38Sdan    INSERT INTO t2 VALUES(4, 'four');
18711da40a38Sdan  }
18721da40a38Sdan} {}
18731da40a38Sdando_test fkey2-genfkey.2.3 {
18741da40a38Sdan  execsql {
18751da40a38Sdan    UPDATE t1 SET a = 2 WHERE a = 1;
18761da40a38Sdan    SELECT * FROM t2;
18771da40a38Sdan  }
18781da40a38Sdan} {2 one 4 four}
18791da40a38Sdando_test fkey2-genfkey.2.4 {
18801da40a38Sdan  execsql {
18811da40a38Sdan    DELETE FROM t1 WHERE a = 4;
18821da40a38Sdan    SELECT * FROM t2;
18831da40a38Sdan  }
18841da40a38Sdan} {2 one}
188532b09f29Sdan
18861da40a38Sdando_test fkey2-genfkey.2.5 {
18871da40a38Sdan  execsql {
18881da40a38Sdan    INSERT INTO t3 VALUES('hello', 2, 3);
18891da40a38Sdan    UPDATE t1 SET c = 2;
18901da40a38Sdan    SELECT * FROM t3;
18911da40a38Sdan  }
18921da40a38Sdan} {hello 2 2}
18931da40a38Sdando_test fkey2-genfkey.2.6 {
18941da40a38Sdan  execsql {
18951da40a38Sdan    DELETE FROM t1;
18961da40a38Sdan    SELECT * FROM t3;
18971da40a38Sdan  }
18981da40a38Sdan} {}
18991da40a38Sdan
19001da40a38Sdandrop_all_tables
19011da40a38Sdando_test fkey2-genfkey.3.1 {
19021da40a38Sdan  execsql {
19031da40a38Sdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(c, b));
19041da40a38Sdan    CREATE TABLE t2(e REFERENCES t1 ON UPDATE SET NULL ON DELETE SET NULL, f);
19051da40a38Sdan    CREATE TABLE t3(g, h, i,
19061da40a38Sdan        FOREIGN KEY (h, i)
19071da40a38Sdan        REFERENCES t1(b, c) ON UPDATE SET NULL ON DELETE SET NULL
19081da40a38Sdan    );
19091da40a38Sdan  }
19101da40a38Sdan} {}
19111da40a38Sdando_test fkey2-genfkey.3.2 {
19121da40a38Sdan  execsql {
19131da40a38Sdan    INSERT INTO t1 VALUES(1, 2, 3);
19141da40a38Sdan    INSERT INTO t1 VALUES(4, 5, 6);
19151da40a38Sdan    INSERT INTO t2 VALUES(1, 'one');
19161da40a38Sdan    INSERT INTO t2 VALUES(4, 'four');
19171da40a38Sdan  }
19181da40a38Sdan} {}
19191da40a38Sdando_test fkey2-genfkey.3.3 {
19201da40a38Sdan  execsql {
19211da40a38Sdan    UPDATE t1 SET a = 2 WHERE a = 1;
19221da40a38Sdan    SELECT * FROM t2;
19231da40a38Sdan  }
19241da40a38Sdan} {{} one 4 four}
19251da40a38Sdando_test fkey2-genfkey.3.4 {
19261da40a38Sdan  execsql {
19271da40a38Sdan    DELETE FROM t1 WHERE a = 4;
19281da40a38Sdan    SELECT * FROM t2;
19291da40a38Sdan  }
19301da40a38Sdan} {{} one {} four}
19311da40a38Sdando_test fkey2-genfkey.3.5 {
19321da40a38Sdan  execsql {
19331da40a38Sdan    INSERT INTO t3 VALUES('hello', 2, 3);
19341da40a38Sdan    UPDATE t1 SET c = 2;
19351da40a38Sdan    SELECT * FROM t3;
19361da40a38Sdan  }
19371da40a38Sdan} {hello {} {}}
19381da40a38Sdando_test fkey2-genfkey.3.6 {
19391da40a38Sdan  execsql {
19401da40a38Sdan    UPDATE t3 SET h = 2, i = 2;
19411da40a38Sdan    DELETE FROM t1;
19421da40a38Sdan    SELECT * FROM t3;
19431da40a38Sdan  }
19441da40a38Sdan} {hello {} {}}
19451da40a38Sdan
19465c092e8aSdrh#-------------------------------------------------------------------------
19475c092e8aSdrh# Verify that ticket dd08e5a988d00decc4a543daa8dbbfab9c577ad8 has been
19485c092e8aSdrh# fixed.
19495c092e8aSdrh#
19505c092e8aSdrhdo_test fkey2-dd08e5.1.1 {
19515c092e8aSdrh  execsql {
19525c092e8aSdrh    PRAGMA foreign_keys=ON;
19535c092e8aSdrh    CREATE TABLE tdd08(a INTEGER PRIMARY KEY, b);
19545c092e8aSdrh    CREATE UNIQUE INDEX idd08 ON tdd08(a,b);
19555c092e8aSdrh    INSERT INTO tdd08 VALUES(200,300);
19565c092e8aSdrh
19575c092e8aSdrh    CREATE TABLE tdd08_b(w,x,y, FOREIGN KEY(x,y) REFERENCES tdd08(a,b));
19585c092e8aSdrh    INSERT INTO tdd08_b VALUES(100,200,300);
19595c092e8aSdrh  }
19605c092e8aSdrh} {}
19615c092e8aSdrhdo_test fkey2-dd08e5.1.2 {
19625c092e8aSdrh  catchsql {
19635c092e8aSdrh    DELETE FROM tdd08;
19645c092e8aSdrh  }
1965f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
19665c092e8aSdrhdo_test fkey2-dd08e5.1.3 {
19675c092e8aSdrh  execsql {
19685c092e8aSdrh    SELECT * FROM tdd08;
19695c092e8aSdrh  }
19705c092e8aSdrh} {200 300}
19715c092e8aSdrhdo_test fkey2-dd08e5.1.4 {
19725c092e8aSdrh  catchsql {
19735c092e8aSdrh    INSERT INTO tdd08_b VALUES(400,500,300);
19745c092e8aSdrh  }
1975f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
19765c092e8aSdrhdo_test fkey2-dd08e5.1.5 {
19775c092e8aSdrh  catchsql {
19785c092e8aSdrh    UPDATE tdd08_b SET x=x+1;
19795c092e8aSdrh  }
1980f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
19815c092e8aSdrhdo_test fkey2-dd08e5.1.6 {
19825c092e8aSdrh  catchsql {
19835c092e8aSdrh    UPDATE tdd08 SET a=a+1;
19845c092e8aSdrh  }
1985f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
19865c092e8aSdrh
19876cbda64dSdrh#-------------------------------------------------------------------------
19886cbda64dSdrh# Verify that ticket ce7c133ea6cc9ccdc1a60d80441f80b6180f5eba
19896cbda64dSdrh# fixed.
19906cbda64dSdrh#
19916cbda64dSdrhdo_test fkey2-ce7c13.1.1 {
19926cbda64dSdrh  execsql {
19936cbda64dSdrh    CREATE TABLE tce71(a INTEGER PRIMARY KEY, b);
19946cbda64dSdrh    CREATE UNIQUE INDEX ice71 ON tce71(a,b);
19956cbda64dSdrh    INSERT INTO tce71 VALUES(100,200);
19966cbda64dSdrh    CREATE TABLE tce72(w, x, y, FOREIGN KEY(x,y) REFERENCES tce71(a,b));
19976cbda64dSdrh    INSERT INTO tce72 VALUES(300,100,200);
19986cbda64dSdrh    UPDATE tce71 set b = 200 where a = 100;
19996cbda64dSdrh    SELECT * FROM tce71, tce72;
20006cbda64dSdrh  }
20016cbda64dSdrh} {100 200 300 100 200}
20026cbda64dSdrhdo_test fkey2-ce7c13.1.2 {
20036cbda64dSdrh  catchsql {
20046cbda64dSdrh    UPDATE tce71 set b = 201 where a = 100;
20056cbda64dSdrh  }
2006f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
20076cbda64dSdrhdo_test fkey2-ce7c13.1.3 {
20086cbda64dSdrh  catchsql {
20096cbda64dSdrh    UPDATE tce71 set a = 101 where a = 100;
20106cbda64dSdrh  }
2011f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
20126cbda64dSdrhdo_test fkey2-ce7c13.1.4 {
20136cbda64dSdrh  execsql {
20146cbda64dSdrh    CREATE TABLE tce73(a INTEGER PRIMARY KEY, b, UNIQUE(a,b));
20156cbda64dSdrh    INSERT INTO tce73 VALUES(100,200);
20166cbda64dSdrh    CREATE TABLE tce74(w, x, y, FOREIGN KEY(x,y) REFERENCES tce73(a,b));
20176cbda64dSdrh    INSERT INTO tce74 VALUES(300,100,200);
20186cbda64dSdrh    UPDATE tce73 set b = 200 where a = 100;
20196cbda64dSdrh    SELECT * FROM tce73, tce74;
20206cbda64dSdrh  }
20216cbda64dSdrh} {100 200 300 100 200}
20226cbda64dSdrhdo_test fkey2-ce7c13.1.5 {
20236cbda64dSdrh  catchsql {
20246cbda64dSdrh    UPDATE tce73 set b = 201 where a = 100;
20256cbda64dSdrh  }
2026f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
20276cbda64dSdrhdo_test fkey2-ce7c13.1.6 {
20286cbda64dSdrh  catchsql {
20296cbda64dSdrh    UPDATE tce73 set a = 101 where a = 100;
20306cbda64dSdrh  }
2031f9c8ce3cSdrh} {1 {FOREIGN KEY constraint failed}}
20325c092e8aSdrh
2033e06874eaSdrh# 2015-04-16:  Foreign key errors propagate back up to the parser.
2034e06874eaSdrh#
2035e06874eaSdrhdo_test fkey2-20150416-100 {
2036e06874eaSdrh  db close
2037e06874eaSdrh  sqlite3 db :memory:
2038e06874eaSdrh  catchsql {
2039e06874eaSdrh    PRAGMA foreign_keys=1;
2040e06874eaSdrh    CREATE TABLE t1(x PRIMARY KEY);
2041e06874eaSdrh    CREATE TABLE t(y REFERENCES t0(x)ON DELETE SET DEFAULT);
2042e06874eaSdrh    CREATE TABLE t0(y REFERENCES t1 ON DELETE SET NULL);
2043e06874eaSdrh    REPLACE INTO t1 SELECT(0);CREATE TABLE t2(x);CREATE TABLE t3;
2044e06874eaSdrh  }
2045e06874eaSdrh} {1 {foreign key mismatch - "t" referencing "t0"}}
2046e06874eaSdrh
20471da40a38Sdanfinish_test
2048