]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add test cases to e_fkey.test.
authordan <dan@noemail.net>
Fri, 9 Oct 2009 18:16:55 +0000 (18:16 +0000)
committerdan <dan@noemail.net>
Fri, 9 Oct 2009 18:16:55 +0000 (18:16 +0000)
FossilOrigin-Name: e391dfe79d52e1de48688715d4a6707ffca214fd

manifest
manifest.uuid
test/e_fkey.test

index 31fbfd69e6b08e4e90f65008cb060b1062d77d6a..5ee1d26795cdbd02de674c66c8c86c85ef27b343 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Test\sa\scouple\sof\sthe\sexamples\sin\sforeignkeys.html.
-D 2009-10-08T19:02:51
+C Add\stest\scases\sto\se_fkey.test.
+D 2009-10-09T18:16:55
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -319,7 +319,7 @@ F test/descidx2.test 1310ed1326cdfed4ea2c55169631579f082d174f
 F test/descidx3.test 3394ad4d089335cac743c36a14129d6d931c316f
 F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
-F test/e_fkey.test 9ad5b376c95dfa60281b5931e6a99d446387446c
+F test/e_fkey.test 5106b8fb0832c9b6d90541c98577494b3057254f
 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
 F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
 F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
@@ -756,7 +756,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 23e0f61a4f24315bf31f632f43b60ec232f348fb
-R bf6536ce577073a4ab6551eb95f10373
+P a2fb7902c01f8b095b25d338fc2f23cb26c941d9
+R 915c62ba9334f3e6b47b204d14e080a3
 U dan
-Z baa870c437a97e37a52b46ca7fd8e861
+Z 7b2c0c612ba82ec335a32afc5fdab39c
index 77e45fb82af7a37dafc72df14ef367716d08679c..29a7922bf42c209b387a3ec5b601bde8e01ef75c 100644 (file)
@@ -1 +1 @@
-a2fb7902c01f8b095b25d338fc2f23cb26c941d9
\ No newline at end of file
+e391dfe79d52e1de48688715d4a6707ffca214fd
\ No newline at end of file
index cfa5fd4dce856daf53ec8ce4abf649ebb0d13314..cb4888bb07dc757e30d0d49f96de41f7bc5242e4 100644 (file)
@@ -19,39 +19,581 @@ ifcapable {!foreignkey} { finish_test ; return }
 
 execsql "PRAGMA foreign_keys = ON"
 
+###########################################################################
+### SECTION 4.3: ON DELETE and ON UPDATE Actions
+###########################################################################
+
 #-------------------------------------------------------------------------
-# /* EV: R-51437-39891 */
+# /* EV: R-48270-44282 */
+#
+# Test that configured ON DELETE and ON UPDATE actions take place when
+# deleting or modifying rows of the parent table, respectively.
+#
+# /* EV: R-48124-63225 */
+#
+# Test that a single FK constraint may have different actions configured
+# for ON DELETE and ON UPDATE.
+#
+do_test e_fkey-16.1 {
+  execsql {
+    CREATE TABLE p(a, b PRIMARY KEY, c);
+    CREATE TABLE c1(d, e, f DEFAULT 'k0' REFERENCES p 
+      ON UPDATE SET DEFAULT
+      ON DELETE SET NULL
+    );
+
+    INSERT INTO p VALUES(0, 'k0', '');
+    INSERT INTO p VALUES(1, 'k1', 'I');
+    INSERT INTO p VALUES(2, 'k2', 'II');
+    INSERT INTO p VALUES(3, 'k3', 'III');
+
+    INSERT INTO c1 VALUES(1, 'xx', 'k1');
+    INSERT INTO c1 VALUES(2, 'xx', 'k2');
+    INSERT INTO c1 VALUES(3, 'xx', 'k3');
+  }
+} {}
+do_test e_fkey-16.2 {
+  execsql {
+    UPDATE p SET b = 'k4' WHERE a = 1;
+    SELECT * FROM c1;
+  }
+} {1 xx k0 2 xx k2 3 xx k3}
+do_test e_fkey-16.3 {
+  execsql {
+    DELETE FROM p WHERE a = 2;
+    SELECT * FROM c1;
+  }
+} {1 xx k0 2 xx {} 3 xx k3}
+do_test e_fkey-16.4 {
+  execsql {
+    CREATE UNIQUE INDEX pi ON p(c);
+    REPLACE INTO p VALUES(5, 'k5', 'III');
+    SELECT * FROM c1;
+  }
+} {1 xx k0 2 xx {} 3 xx {}}
+
+#-------------------------------------------------------------------------
+# /* EV: R-33326-45252 */
+#
+# Each foreign key in the system has an ON UPDATE and ON DELETE action,
+# either "NO ACTION", "RESTRICT", "SET NULL", "SET DEFAULT" or "CASCADE".
+#
+# /* EV: R-19803-45884 */
+#
+# If none is specified explicitly, "NO ACTION" is the default.
+# 
+drop_all_tables
+do_test e_fkey-17.1 {
+  execsql {
+    CREATE TABLE parent(x PRIMARY KEY, y);
+    CREATE TABLE child1(a, 
+      b REFERENCES parent ON UPDATE NO ACTION ON DELETE RESTRICT
+    );
+    CREATE TABLE child2(a, 
+      b REFERENCES parent ON UPDATE RESTRICT ON DELETE SET NULL
+    );
+    CREATE TABLE child3(a, 
+      b REFERENCES parent ON UPDATE SET NULL ON DELETE SET DEFAULT
+    );
+    CREATE TABLE child4(a, 
+      b REFERENCES parent ON UPDATE SET DEFAULT ON DELETE CASCADE
+    );
+
+    -- Create some foreign keys that use the default action - "NO ACTION"
+    CREATE TABLE child5(a, b REFERENCES parent ON UPDATE CASCADE);
+    CREATE TABLE child6(a, b REFERENCES parent ON DELETE RESTRICT);
+    CREATE TABLE child7(a, b REFERENCES parent ON DELETE NO ACTION);
+    CREATE TABLE child8(a, b REFERENCES parent ON UPDATE NO ACTION);
+  }
+} {}
+
+foreach {tn zTab lRes} {
+  2 child1 {0 0 parent b {} {NO ACTION} RESTRICT NONE}
+  3 child2 {0 0 parent b {} RESTRICT {SET NULL} NONE}
+  4 child3 {0 0 parent b {} {SET NULL} {SET DEFAULT} NONE}
+  5 child4 {0 0 parent b {} {SET DEFAULT} CASCADE NONE}
+  6 child5 {0 0 parent b {} CASCADE {NO ACTION} NONE}
+  7 child6 {0 0 parent b {} {NO ACTION} RESTRICT NONE}
+  8 child7 {0 0 parent b {} {NO ACTION} {NO ACTION} NONE}
+  9 child8 {0 0 parent b {} {NO ACTION} {NO ACTION} NONE}
+} {
+  do_test e_fkey-17.$tn { execsql "PRAGMA foreign_key_list($zTab)" } $lRes
+}
+
+#-------------------------------------------------------------------------
+# /* EV: R-19971-54976 */
+#
+# Test that "NO ACTION" means that nothing happens to a child row when
+# it's parent row is updated or deleted.
+#
+drop_all_tables
+do_test e_fkey-18.1 {
+  execsql {
+    CREATE TABLE parent(p1, p2, PRIMARY KEY(p1, p2));
+    CREATE TABLE child(c1, c2, 
+      FOREIGN KEY(c1, c2) REFERENCES parent
+      ON UPDATE NO ACTION
+      ON DELETE NO ACTION
+      DEFERRABLE INITIALLY DEFERRED
+    );
+    INSERT INTO parent VALUES('j', 'k');
+    INSERT INTO parent VALUES('l', 'm');
+    INSERT INTO child VALUES('j', 'k');
+    INSERT INTO child VALUES('l', 'm');
+  }
+} {}
+do_test e_fkey-18.2 {
+  execsql {
+    BEGIN;
+      UPDATE parent SET p1='k' WHERE p1='j';
+      DELETE FROM parent WHERE p1='l';
+      SELECT * FROM child;
+  }
+} {j k l m}
+do_test e_fkey-18.3 {
+  catchsql COMMIT
+} {1 {foreign key constraint failed}}
+do_test e_fkey-18.4 {
+  execsql ROLLBACK
+} {}
+
+#-------------------------------------------------------------------------
+# /* EV: R-04272-38653 */
+#
+# Test that "RESTRICT" means the application is prohibited from deleting
+# or updating a parent table row when there exists one or more child keys
+# mapped to it.
+#
+drop_all_tables
+do_test e_fkey-18.1 {
+  execsql {
+    CREATE TABLE parent(p1, p2);
+    CREATE UNIQUE INDEX parent_i ON parent(p1, p2);
+    CREATE TABLE child1(c1, c2, 
+      FOREIGN KEY(c2, c1) REFERENCES parent(p1, p2) ON DELETE RESTRICT
+    );
+    CREATE TABLE child2(c1, c2, 
+      FOREIGN KEY(c2, c1) REFERENCES parent(p1, p2) ON UPDATE RESTRICT
+    );
+  }
+} {}
+do_test e_fkey-18.2 {
+  execsql {
+    INSERT INTO parent VALUES('a', 'b');
+    INSERT INTO parent VALUES('c', 'd');
+    INSERT INTO child1 VALUES('b', 'a');
+    INSERT INTO child2 VALUES('d', 'c');
+  }
+} {}
+do_test e_fkey-18.3 {
+  catchsql { DELETE FROM parent WHERE p1 = 'a' }
+} {1 {foreign key constraint failed}}
+do_test e_fkey-18.4 {
+  catchsql { UPDATE parent SET p2 = 'e' WHERE p1 = 'c' }
+} {1 {foreign key constraint failed}}
+
+#-------------------------------------------------------------------------
+# /* EV: R-37997-42187 */
+# 
+# Test that RESTRICT is slightly different from NO ACTION for IMMEDIATE
+# constraints, in that it is enforced immediately, not at the end of the 
+# statement.
+#
+drop_all_tables
+do_test e_fkey-19.1 {
+  execsql {
+    CREATE TABLE parent(x PRIMARY KEY);
+    CREATE TABLE child1(c REFERENCES parent ON UPDATE RESTRICT);
+    CREATE TABLE child2(c REFERENCES parent ON UPDATE NO ACTION);
+
+    INSERT INTO parent VALUES('key1');
+    INSERT INTO parent VALUES('key2');
+    INSERT INTO child1 VALUES('key1');
+    INSERT INTO child2 VALUES('key2');
+
+    CREATE TRIGGER parent_t AFTER UPDATE ON parent BEGIN
+      UPDATE child1 set c = new.x WHERE c = old.x;
+      UPDATE child2 set c = new.x WHERE c = old.x;
+    END;
+  }
+} {}
+do_test e_fkey-19.2 {
+  catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' }
+} {1 {foreign key constraint failed}}
+do_test e_fkey-19.3 {
+  execsql { 
+    UPDATE parent SET x = 'key two' WHERE x = 'key2';
+    SELECT * FROM child2;
+  }
+} {{key two}}
+
+drop_all_tables
+do_test e_fkey-19.4 {
+  execsql {
+    CREATE TABLE parent(x PRIMARY KEY);
+    CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT);
+    CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION);
+
+    INSERT INTO parent VALUES('key1');
+    INSERT INTO parent VALUES('key2');
+    INSERT INTO child1 VALUES('key1');
+    INSERT INTO child2 VALUES('key2');
+
+    CREATE TRIGGER parent_t AFTER DELETE ON parent BEGIN
+      UPDATE child1 SET c = NULL WHERE c = old.x;
+      UPDATE child2 SET c = NULL WHERE c = old.x;
+    END;
+  }
+} {}
+do_test e_fkey-19.5 {
+  catchsql { DELETE FROM parent WHERE x = 'key1' }
+} {1 {foreign key constraint failed}}
+do_test e_fkey-19.6 {
+  execsql { 
+    DELETE FROM parent WHERE x = 'key2';
+    SELECT * FROM child2;
+  }
+} {{}}
+
+drop_all_tables
+do_test e_fkey-19.7 {
+  execsql {
+    CREATE TABLE parent(x PRIMARY KEY);
+    CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT);
+    CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION);
+
+    INSERT INTO parent VALUES('key1');
+    INSERT INTO parent VALUES('key2');
+    INSERT INTO child1 VALUES('key1');
+    INSERT INTO child2 VALUES('key2');
+  }
+} {}
+do_test e_fkey-19.8 {
+  catchsql { REPLACE INTO parent VALUES('key1') }
+} {1 {foreign key constraint failed}}
+do_test e_fkey-19.9 {
+  execsql { 
+    REPLACE INTO parent VALUES('key2');
+    SELECT * FROM child2;
+  }
+} {key2}
+
+#-------------------------------------------------------------------------
+# /* EV: R-24179-60523 */
+# 
+# Test that RESTRICT is enforced immediately, even for a DEFERRED constraint.
+#
+drop_all_tables
+do_test e_fkey-20.1 {
+  execsql {
+    CREATE TABLE parent(x PRIMARY KEY);
+    CREATE TABLE child1(c REFERENCES parent ON UPDATE RESTRICT
+      DEFERRABLE INITIALLY DEFERRED
+    );
+    CREATE TABLE child2(c REFERENCES parent ON UPDATE NO ACTION
+      DEFERRABLE INITIALLY DEFERRED
+    );
+
+    INSERT INTO parent VALUES('key1');
+    INSERT INTO parent VALUES('key2');
+    INSERT INTO child1 VALUES('key1');
+    INSERT INTO child2 VALUES('key2');
+    BEGIN;
+  }
+} {}
+do_test e_fkey-20.2 {
+  catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' }
+} {1 {foreign key constraint failed}}
+do_test e_fkey-20.3 {
+  execsql { UPDATE parent SET x = 'key two' WHERE x = 'key2' }
+} {}
+do_test e_fkey-20.4 {
+  catchsql COMMIT
+} {1 {foreign key constraint failed}}
+do_test e_fkey-20.5 {
+  execsql {
+    UPDATE child2 SET c = 'key two';
+    COMMIT;
+  }
+} {}
+
+drop_all_tables
+do_test e_fkey-20.6 {
+  execsql {
+    CREATE TABLE parent(x PRIMARY KEY);
+    CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT
+      DEFERRABLE INITIALLY DEFERRED
+    );
+    CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION
+      DEFERRABLE INITIALLY DEFERRED
+    );
+
+    INSERT INTO parent VALUES('key1');
+    INSERT INTO parent VALUES('key2');
+    INSERT INTO child1 VALUES('key1');
+    INSERT INTO child2 VALUES('key2');
+    BEGIN;
+  }
+} {}
+do_test e_fkey-20.7 {
+  catchsql { DELETE FROM parent WHERE x = 'key1' }
+} {1 {foreign key constraint failed}}
+do_test e_fkey-20.8 {
+  execsql { DELETE FROM parent WHERE x = 'key2' }
+} {}
+do_test e_fkey-20.9 {
+  catchsql COMMIT
+} {1 {foreign key constraint failed}}
+do_test e_fkey-20.10 {
+  execsql {
+    UPDATE child2 SET c = NULL;
+    COMMIT;
+  }
+} {}
+
+#-------------------------------------------------------------------------
+# /* EV: R-03353-05327 */
+#
+# Test SET NULL actions.
+#
+drop_all_tables
+do_test e_fkey-21.1 {
+  execsql {
+    CREATE TABLE pA(x PRIMARY KEY);
+    CREATE TABLE cA(c REFERENCES pA ON DELETE SET NULL);
+    CREATE TABLE cB(c REFERENCES pA ON UPDATE SET NULL);
+
+    INSERT INTO pA VALUES(X'ABCD');
+    INSERT INTO pA VALUES(X'1234');
+    INSERT INTO cA VALUES(X'ABCD');
+    INSERT INTO cB VALUES(X'1234');
+  }
+} {}
+do_test e_fkey-21.2 {
+  execsql {
+    DELETE FROM pA WHERE rowid = 1;
+    SELECT quote(x) FROM pA;
+  }
+} {X'1234'}
+do_test e_fkey-21.3 {
+  execsql {
+    SELECT quote(c) FROM cA;
+  }
+} {NULL}
+do_test e_fkey-21.4 {
+  execsql {
+    UPDATE pA SET x = X'8765' WHERE rowid = 2;
+    SELECT quote(x) FROM pA;
+  }
+} {X'8765'}
+do_test e_fkey-21.5 {
+  execsql { SELECT quote(c) FROM cB }
+} {NULL}
+
+#-------------------------------------------------------------------------
+# /* EV: R-43054-54832 */
+#
+# Test SET DEFAULT actions.
+#
+drop_all_tables
+do_test e_fkey-22.1 {
+  execsql {
+    CREATE TABLE pA(x PRIMARY KEY);
+    CREATE TABLE cA(c DEFAULT X'0000' REFERENCES pA ON DELETE SET DEFAULT);
+    CREATE TABLE cB(c DEFAULT X'9999' REFERENCES pA ON UPDATE SET DEFAULT);
+
+    INSERT INTO pA(rowid, x) VALUES(1, X'0000');
+    INSERT INTO pA(rowid, x) VALUES(2, X'9999');
+    INSERT INTO pA(rowid, x) VALUES(3, X'ABCD');
+    INSERT INTO pA(rowid, x) VALUES(4, X'1234');
+
+    INSERT INTO cA VALUES(X'ABCD');
+    INSERT INTO cB VALUES(X'1234');
+  }
+} {}
+do_test e_fkey-22.2 {
+  execsql {
+    DELETE FROM pA WHERE rowid = 3;
+    SELECT quote(x) FROM pA;
+  }
+} {X'0000' X'9999' X'1234'}
+do_test e_fkey-22.3 {
+  execsql { SELECT quote(c) FROM cA }
+} {X'0000'}
+do_test e_fkey-22.4 {
+  execsql {
+    UPDATE pA SET x = X'8765' WHERE rowid = 4;
+    SELECT quote(x) FROM pA;
+  }
+} {X'0000' X'9999' X'8765'}
+do_test e_fkey-22.5 {
+  execsql { SELECT quote(c) FROM cB }
+} {X'9999'}
+
+#-------------------------------------------------------------------------
+# /* EV: R-61376-57267 */
+# /* EV: R-61809-62207 */
+#
+# Test ON DELETE CASCADE actions.
+#
+drop_all_tables
+do_test e_fkey-23.1 {
+  execsql {
+    CREATE TABLE p1(a, b UNIQUE);
+    CREATE TABLE c1(c REFERENCES p1(b) ON DELETE CASCADE, d);
+    INSERT INTO p1 VALUES(NULL, NULL);
+    INSERT INTO p1 VALUES(4, 4);
+    INSERT INTO p1 VALUES(5, 5);
+    INSERT INTO c1 VALUES(NULL, NULL);
+    INSERT INTO c1 VALUES(4, 4);
+    INSERT INTO c1 VALUES(5, 5);
+    SELECT count(*) FROM c1;
+  }
+} {3}
+do_test e_fkey-23.2 {
+  execsql {
+    DELETE FROM p1 WHERE a = 4;
+    SELECT d, c FROM c1;
+  }
+} {{} {} 5 5}
+do_test e_fkey-23.3 {
+  execsql {
+    DELETE FROM p1;
+    SELECT d, c FROM c1;
+  }
+} {{} {}}
+do_test e_fkey-23.4 {
+  execsql { SELECT * FROM p1 }
+} {}
+
+
+#-------------------------------------------------------------------------
+# /* EV: R-61376-57267 */
+# /* EV: R-13877-64542 */
+#
+# Test ON UPDATE CASCADE actions.
+#
+drop_all_tables
+do_test e_fkey-24.1 {
+  execsql {
+    CREATE TABLE p1(a, b UNIQUE);
+    CREATE TABLE c1(c REFERENCES p1(b) ON UPDATE CASCADE, d);
+    INSERT INTO p1 VALUES(NULL, NULL);
+    INSERT INTO p1 VALUES(4, 4);
+    INSERT INTO p1 VALUES(5, 5);
+    INSERT INTO c1 VALUES(NULL, NULL);
+    INSERT INTO c1 VALUES(4, 4);
+    INSERT INTO c1 VALUES(5, 5);
+    SELECT count(*) FROM c1;
+  }
+} {3}
+do_test e_fkey-24.2 {
+  execsql {
+    UPDATE p1 SET b = 10 WHERE b = 5;
+    SELECT d, c FROM c1;
+  }
+} {{} {} 4 4 5 10}
+do_test e_fkey-24.3 {
+  execsql {
+    UPDATE p1 SET b = 11 WHERE b = 4;
+    SELECT d, c FROM c1;
+  }
+} {{} {} 4 11 5 10}
+do_test e_fkey-24.4 {
+  execsql { 
+    UPDATE p1 SET b = 6 WHERE b IS NULL;
+    SELECT d, c FROM c1;
+  }
+} {{} {} 4 11 5 10}
+do_test e_fkey-23.5 {
+  execsql { SELECT * FROM p1 }
+} {{} 6 4 11 5 10}
+
+#-------------------------------------------------------------------------
+# /* EV: R-51329-33438 */
 #
 # Test an example from the "ON DELETE and ON UPDATE Actions" section 
 # of foreignkeys.html.
 #
 drop_all_tables
-do_test e_fkey-13.1 {
+do_test e_fkey-15.1 {
   execsql {
-    CREATE TABLE parent(x PRIMARY KEY);
-    CREATE TABLE child(y REFERENCES parent ON UPDATE SET NULL);
-    INSERT INTO parent VALUES('key');
-    INSERT INTO child VALUES('key');
+    CREATE TABLE artist(
+      artistid    INTEGER PRIMARY KEY, 
+      artistname  TEXT
+    );
+    CREATE TABLE track(
+      trackid     INTEGER,
+      trackname   TEXT, 
+      trackartist INTEGER REFERENCES artist(artistid) ON UPDATE CASCADE
+    );
+
+    INSERT INTO artist VALUES(1, 'Dean Martin');
+    INSERT INTO artist VALUES(2, 'Frank Sinatra');
+    INSERT INTO track VALUES(11, 'That''s Amore', 1);
+    INSERT INTO track VALUES(12, 'Christmas Blues', 1);
+    INSERT INTO track VALUES(13, 'My Way', 2);
   }
 } {}
-do_test e_fkey-13.2 {
+do_test e_fkey-15.2 {
   execsql {
-    UPDATE parent SET x = 'key';
-    SELECT IFNULL(y, 'null') FROM child;
+    UPDATE artist SET artistid = 100 WHERE artistname = 'Dean Martin';
   }
-} {key}
-do_test e_fkey-13.3 {
+} {}
+do_test e_fkey-15.3 {
+  execsql { SELECT * FROM artist }
+} {2 {Frank Sinatra} 100 {Dean Martin}}
+do_test e_fkey-15.4 {
+  execsql { SELECT * FROM track }
+} {11 {That's Amore} 100 12 {Christmas Blues} 100 13 {My Way} 2}
+
+
+#-------------------------------------------------------------------------
+# /* EV: R-53968-51642 */
+#
+# Verify that adding an FK action does not absolve the user of the 
+# requirement not to violate the foreign key constraint.
+#
+drop_all_tables
+do_test e_fkey-25.1 {
   execsql {
-    UPDATE parent SET x = 'key2';
-    SELECT IFNULL(y, 'null') FROM child;
+    CREATE TABLE parent(a COLLATE nocase, b, c, PRIMARY KEY(c, a));
+    CREATE TABLE child(d DEFAULT 'a', e, f DEFAULT 'c',
+      FOREIGN KEY(f, d) REFERENCES parent ON UPDATE SET DEFAULT
+    );
+
+    INSERT INTO parent VALUES('A', 'b', 'c');
+    INSERT INTO parent VALUES('ONE', 'two', 'three');
+    INSERT INTO child VALUES('one', 'two', 'three');
   }
-} {null}
+} {}
+do_test e_fkey-25.2 {
+  execsql {
+    BEGIN;
+      UPDATE parent SET a = '' WHERE a = 'oNe';
+      SELECT * FROM child;
+  }
+} {a two c}
+do_test e_fkey-25.3 {
+  execsql {
+    ROLLBACK;
+    DELETE FROM parent WHERE a = 'A';
+    SELECT * FROM parent;
+  }
+} {ONE two three}
+do_test e_fkey-25.4 {
+  catchsql { UPDATE parent SET a = '' WHERE a = 'oNe' }
+} {1 {foreign key constraint failed}}
+
 
 #-------------------------------------------------------------------------
 # /* EV: R-07065-59588 */
+# /* EV: R-28220-46694 */
 #
 # Test an example from the "ON DELETE and ON UPDATE Actions" section 
-# of foreignkeys.html.
+# of foreignkeys.html. This example shows that adding an "ON DELETE DEFAULT"
+# clause does not abrogate the need to satisfy the foreign key constraint
+# (R-28220-46694).
 #
 drop_all_tables
 do_test e_fkey-14.1 {
@@ -86,42 +628,144 @@ do_test e_fkey-14.5 {
 } {14 {Mr. Bojangles} 0}
 
 #-------------------------------------------------------------------------
-# /* EV: R-25213-27898 */
+# /* EV: R-35762-30306 */
 #
-# Test an example from the "ON DELETE and ON UPDATE Actions" section 
-# of foreignkeys.html.
+# Check that the order of steps in an UPDATE or DELETE on a parent 
+# table is as follows:
+#
+#   1. Execute applicable BEFORE trigger programs,
+#   2. Check local (non foreign key) constraints,
+#   3. Update or delete the row in the parent table,
+#   4. Perform any required foreign key actions,
+#   5. Execute applicable AFTER trigger programs. 
 #
 drop_all_tables
-do_test e_fkey-15.1 {
+do_test e_fkey-27.1 {
+  proc maxparent {args} { db one {SELECT max(x) FROM parent} }
+  db func maxparent maxparent
+
   execsql {
-    CREATE TABLE artist(
-      artistid    INTEGER PRIMARY KEY, 
-      artistname  TEXT
-    );
-    CREATE TABLE track(
-      trackid     INTEGER,
-      trackname   TEXT, 
-      trackartist INTEGER REFERENCES artist(artistid) ON UPDATE CASCADE
+    CREATE TABLE parent(x PRIMARY KEY);
+
+    CREATE TRIGGER bu BEFORE UPDATE ON parent BEGIN
+      INSERT INTO parent VALUES(new.x-old.x);
+    END;
+    CREATE TABLE child(
+      a DEFAULT (maxparent()) REFERENCES parent ON UPDATE SET DEFAULT
     );
+    CREATE TRIGGER au AFTER UPDATE ON parent BEGIN
+      INSERT INTO parent VALUES(new.x+old.x);
+    END;
 
-    INSERT INTO artist VALUES(1, 'Dean Martin');
-    INSERT INTO artist VALUES(2, 'Frank Sinatra');
-    INSERT INTO track VALUES(11, 'That''s Amore', 1);
-    INSERT INTO track VALUES(12, 'Christmas Blues', 1);
-    INSERT INTO track VALUES(13, 'My Way', 2);
+    INSERT INTO parent VALUES(1);
+    INSERT INTO child VALUES(1);
   }
 } {}
-do_test e_fkey-15.2 {
+do_test e_fkey-27.2 {
   execsql {
-    UPDATE artist SET artistid = 100 WHERE artistname = 'Dean Martin';
+    UPDATE parent SET x = 22;
+    SELECT * FROM parent UNION ALL SELECT 'xxx' UNION ALL SELECT a FROM child;
+  }
+} {22 21 23 xxx 22}
+do_test e_fkey-27.3 {
+  execsql {
+    DELETE FROM child;
+    DELETE FROM parent;
+    INSERT INTO parent VALUES(-1);
+    INSERT INTO child VALUES(-1);
+    UPDATE parent SET x = 22;
+    SELECT * FROM parent UNION ALL SELECT 'xxx' UNION ALL SELECT a FROM child;
+  }
+} {22 23 21 xxx 23}
+
+
+#-------------------------------------------------------------------------
+# /* EV: R-27383-10246 */
+#
+# Verify that ON UPDATE actions only actually take place if the parent key
+# is set to a new value that is distinct from the old value. The default
+# collation sequence and affinity are used to determine if the new value
+# is 'distinct' from the old or not.
+#
+drop_all_tables
+do_test e_fkey-26.1 {
+  execsql {
+    CREATE TABLE zeus(a INTEGER COLLATE NOCASE, b, PRIMARY KEY(a, b));
+    CREATE TABLE apollo(c, d, 
+      FOREIGN KEY(c, d) REFERENCES zeus ON UPDATE CASCADE
+    );
+    INSERT INTO zeus VALUES('abc', 'xyz');
+    INSERT INTO apollo VALUES('ABC', 'xyz');
+  }
+  execsql {
+    UPDATE zeus SET a = 'aBc';
+    SELECT * FROM apollo;
+  }
+} {ABC xyz}
+do_test e_fkey-26.2 {
+  execsql {
+    UPDATE zeus SET a = 1, b = 1;
+    SELECT * FROM apollo;
+  }
+} {1 1}
+do_test e_fkey-26.3 {
+  execsql {
+    UPDATE zeus SET a = 1, b = 1;
+    SELECT typeof(c), c, typeof(d), d FROM apollo;
+  }
+} {integer 1 integer 1}
+do_test e_fkey-26.4 {
+  execsql {
+    UPDATE zeus SET a = '1';
+    SELECT typeof(c), c, typeof(d), d FROM apollo;
+  }
+} {integer 1 integer 1}
+do_test e_fkey-26.5 {
+  execsql {
+    UPDATE zeus SET b = '1';
+    SELECT typeof(c), c, typeof(d), d FROM apollo;
+  }
+} {integer 1 text 1}
+do_test e_fkey-26.6 {
+  execsql {
+    UPDATE zeus SET b = NULL;
+    SELECT typeof(c), c, typeof(d), d FROM apollo;
+  }
+} {integer 1 null {}}
+
+#-------------------------------------------------------------------------
+# /* EV: R-51437-39891 */
+#
+# Test an example from the "ON DELETE and ON UPDATE Actions" section 
+# of foreignkeys.html. This example demonstrates that ON UPDATE actions
+# only take place if at least one parent key column is set to a value 
+# that is distinct from its previous value.
+#
+drop_all_tables
+do_test e_fkey-13.1 {
+  execsql {
+    CREATE TABLE parent(x PRIMARY KEY);
+    CREATE TABLE child(y REFERENCES parent ON UPDATE SET NULL);
+    INSERT INTO parent VALUES('key');
+    INSERT INTO child VALUES('key');
   }
 } {}
-do_test e_fkey-15.3 {
-  execsql { SELECT * FROM artist }
-} {2 {Frank Sinatra} 100 {Dean Martin}}
-do_test e_fkey-15.4 {
-  execsql { SELECT * FROM track }
-} {11 {That's Amore} 100 12 {Christmas Blues} 100 13 {My Way} 2}
+do_test e_fkey-13.2 {
+  execsql {
+    UPDATE parent SET x = 'key';
+    SELECT IFNULL(y, 'null') FROM child;
+  }
+} {key}
+do_test e_fkey-13.3 {
+  execsql {
+    UPDATE parent SET x = 'key2';
+    SELECT IFNULL(y, 'null') FROM child;
+  }
+} {null}
+
+###########################################################################
+### SECTION 5: CREATE, ALTER and DROP TABLE commands
+###########################################################################
 
 #-------------------------------------------------------------------------
 # /* EV: R-36018-21755 */
@@ -478,6 +1122,9 @@ do_test e_fkey-12.3.3 {
   execsql { PRAGMA foreign_keys = ON }
 } {}
 
+###########################################################################
+### SECTION 6: Limits and Unsupported Features
+###########################################################################
 
 #-------------------------------------------------------------------------
 # /* EV: R-24728-13230 */