000001 # 2012 December 17
000002 #
000003 # The author disclaims copyright to this source code. In place of
000004 # a legal notice, here is a blessing:
000005 #
000006 # May you do good and not evil.
000007 # May you find forgiveness for yourself and forgive others.
000008 # May you share freely, never taking more than you give.
000009 #
000010 #***********************************************************************
000011 # This file implements regression tests for SQLite library.
000012 #
000013 # This file tests the PRAGMA defer_foreign_keys and
000014 # SQLITE_DBSTATUS_DEFERRED_FKS
000015 #
000016 # EVIDENCE-OF: R-18981-16292 When the defer_foreign_keys PRAGMA is on,
000017 # enforcement of all foreign key constraints is delayed until the
000018 # outermost transaction is committed.
000019 #
000020 # EVIDENCE-OF: R-28911-57501 The defer_foreign_keys pragma defaults to
000021 # OFF so that foreign key constraints are only deferred if they are
000022 # created as "DEFERRABLE INITIALLY DEFERRED".
000023
000024 set testdir [file dirname $argv0]
000025 source $testdir/tester.tcl
000026 set testprefix fkey6
000027
000028 ifcapable {!foreignkey} {
000029 finish_test
000030 return
000031 }
000032
000033 do_execsql_test fkey6-1.0 {
000034 PRAGMA defer_foreign_keys;
000035 } {0}
000036
000037 do_execsql_test fkey6-1.1 {
000038 PRAGMA foreign_keys=ON;
000039 CREATE TABLE t1(x INTEGER PRIMARY KEY);
000040 CREATE TABLE t2(y INTEGER PRIMARY KEY,
000041 z INTEGER REFERENCES t1(x) DEFERRABLE INITIALLY DEFERRED);
000042 CREATE INDEX t2z ON t2(z);
000043 CREATE TABLE t3(u INTEGER PRIMARY KEY, v INTEGER REFERENCES t1(x));
000044 CREATE INDEX t3v ON t3(v);
000045 INSERT INTO t1 VALUES(1),(2),(3),(4),(5);
000046 INSERT INTO t2 VALUES(1,1),(2,2);
000047 INSERT INTO t3 VALUES(3,3),(4,4);
000048 } {}
000049 do_test fkey6-1.2 {
000050 catchsql {DELETE FROM t1 WHERE x=2;}
000051 } {1 {FOREIGN KEY constraint failed}}
000052 do_test fkey6-1.3 {
000053 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
000054 } {0 0 0}
000055 do_test fkey6-1.4 {
000056 execsql {
000057 BEGIN;
000058 DELETE FROM t1 WHERE x=1;
000059 }
000060 } {}
000061 do_test fkey6-1.5.1 {
000062 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 1
000063 } {0 1 0}
000064 do_test fkey6-1.5.2 {
000065 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
000066 } {0 1 0}
000067 do_test fkey6-1.6 {
000068 execsql {
000069 ROLLBACK;
000070 }
000071 } {}
000072 do_test fkey6-1.7 {
000073 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
000074 } {0 0 0}
000075 do_test fkey6-1.8 {
000076 execsql {
000077 PRAGMA defer_foreign_keys=ON;
000078 BEGIN;
000079 DELETE FROM t1 WHERE x=3;
000080 }
000081 } {}
000082 do_test fkey6-1.9 {
000083 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
000084 } {0 1 0}
000085
000086 # EVIDENCE-OF: R-21752-26913 The defer_foreign_keys pragma is
000087 # automatically switched off at each COMMIT or ROLLBACK. Hence, the
000088 # defer_foreign_keys pragma must be separately enabled for each
000089 # transaction.
000090 do_execsql_test fkey6-1.10.1 {
000091 PRAGMA defer_foreign_keys;
000092 ROLLBACK;
000093 PRAGMA defer_foreign_keys;
000094 BEGIN;
000095 PRAGMA defer_foreign_keys=ON;
000096 PRAGMA defer_foreign_keys;
000097 COMMIT;
000098 PRAGMA defer_foreign_keys;
000099 BEGIN;
000100 } {1 0 1 0}
000101 do_test fkey6-1.10.2 {
000102 catchsql {DELETE FROM t1 WHERE x=3}
000103 } {1 {FOREIGN KEY constraint failed}}
000104 db eval {ROLLBACK}
000105
000106 do_test fkey6-1.20 {
000107 execsql {
000108 BEGIN;
000109 DELETE FROM t1 WHERE x=1;
000110 }
000111 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
000112 } {0 1 0}
000113 do_test fkey6-1.21 {
000114 execsql {
000115 DELETE FROM t2 WHERE y=1;
000116 }
000117 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
000118 } {0 0 0}
000119 do_test fkey6-1.22 {
000120 execsql {
000121 COMMIT;
000122 }
000123 } {}
000124
000125 do_execsql_test fkey6-2.1 {
000126 CREATE TABLE p1(a PRIMARY KEY);
000127 INSERT INTO p1 VALUES('one'), ('two');
000128 CREATE TABLE c1(x REFERENCES p1);
000129 INSERT INTO c1 VALUES('two'), ('one');
000130 }
000131
000132 do_execsql_test fkey6-2.2 {
000133 BEGIN;
000134 PRAGMA defer_foreign_keys = 1;
000135 DELETE FROM p1;
000136 ROLLBACK;
000137 PRAGMA defer_foreign_keys;
000138 } {0}
000139
000140 do_execsql_test fkey6-2.3 {
000141 BEGIN;
000142 PRAGMA defer_foreign_keys = 1;
000143 DROP TABLE p1;
000144 PRAGMA vdbe_trace = 0;
000145 ROLLBACK;
000146 PRAGMA defer_foreign_keys;
000147 } {0}
000148
000149 do_execsql_test fkey6-2.4 {
000150 BEGIN;
000151 PRAGMA defer_foreign_keys = 1;
000152 DELETE FROM p1;
000153 DROP TABLE c1;
000154 COMMIT;
000155 PRAGMA defer_foreign_keys;
000156 } {0}
000157
000158 do_execsql_test fkey6-2.5 {
000159 DROP TABLE p1;
000160 CREATE TABLE p1(a PRIMARY KEY);
000161 INSERT INTO p1 VALUES('one'), ('two');
000162 CREATE TABLE c1(x REFERENCES p1);
000163 INSERT INTO c1 VALUES('two'), ('one');
000164 }
000165
000166 do_execsql_test fkey6-2.6 {
000167 BEGIN;
000168 PRAGMA defer_foreign_keys = 1;
000169 INSERT INTO c1 VALUES('three');
000170 DROP TABLE c1;
000171 COMMIT;
000172 PRAGMA defer_foreign_keys;
000173 } {0}
000174
000175 #--------------------------------------------------------------------------
000176 # Test that defer_foreign_keys disables RESTRICT.
000177 #
000178 do_execsql_test 3.1 {
000179 CREATE TABLE p2(a PRIMARY KEY, b);
000180 CREATE TABLE c2(x, y REFERENCES p2 ON DELETE RESTRICT ON UPDATE RESTRICT);
000181 INSERT INTO p2 VALUES(1, 'one');
000182 INSERT INTO p2 VALUES(2, 'two');
000183 INSERT INTO c2 VALUES('i', 1);
000184 }
000185
000186 do_catchsql_test 3.2.1 {
000187 BEGIN;
000188 UPDATE p2 SET a=a-1;
000189 } {1 {FOREIGN KEY constraint failed}}
000190 do_execsql_test 3.2.2 { COMMIT }
000191
000192 do_execsql_test 3.2.3 {
000193 BEGIN;
000194 PRAGMA defer_foreign_keys = 1;
000195 UPDATE p2 SET a=a-1;
000196 COMMIT;
000197 }
000198
000199 do_execsql_test 3.2.4 {
000200 BEGIN;
000201 PRAGMA defer_foreign_keys = 1;
000202 UPDATE p2 SET a=a-1;
000203 }
000204 do_catchsql_test 3.2.5 {
000205 COMMIT;
000206 } {1 {FOREIGN KEY constraint failed}}
000207 do_execsql_test 3.2.6 { ROLLBACK }
000208
000209 do_execsql_test 3.3.1 {
000210 CREATE TRIGGER p2t AFTER DELETE ON p2 BEGIN
000211 INSERT INTO p2 VALUES(old.a, 'deleted!');
000212 END;
000213 }
000214 do_catchsql_test 3.3.2 {
000215 BEGIN;
000216 DELETE FROM p2 WHERE a=1;
000217 } {1 {FOREIGN KEY constraint failed}}
000218 do_execsql_test 3.3.3 { COMMIT }
000219
000220 do_execsql_test 3.3.4 {
000221 BEGIN;
000222 PRAGMA defer_foreign_keys = 1;
000223 DELETE FROM p2 WHERE a=1;
000224 COMMIT;
000225 SELECT * FROM p2;
000226 } {0 one 1 deleted!}
000227
000228 #-------------------------------------------------------------------------
000229 # Verify that, even with "PRAGMA defer_foreign_keys", a transaction cannot
000230 # be committed if there are outstanding foreign key violations.
000231 #
000232 reset_db
000233 do_execsql_test 4.0 {
000234 CREATE TABLE p1(a INTEGER PRIMARY KEY, b UNIQUE);
000235 CREATE TABLE c1(x REFERENCES p1(b));
000236
000237 INSERT INTO p1 VALUES(1, 'one'), (2, 'two'), (3, 'three');
000238 INSERT INTO c1 VALUES('two');
000239
000240 PRAGMA foreign_keys = 1;
000241 PRAGMA defer_foreign_keys = 1;
000242 }
000243
000244 do_execsql_test 4.1 {
000245 BEGIN;
000246 DELETE FROM p1 WHERE a=2;
000247 }
000248
000249 do_catchsql_test 4.2 {
000250 COMMIT;
000251 } {1 {FOREIGN KEY constraint failed}}
000252
000253 #-------------------------------------------------------------------------
000254 #
000255 reset_db
000256 do_execsql_test 5.0 {
000257 PRAGMA foreign_keys = 1;
000258 CREATE TABLE p1(a INTEGER PRIMARY KEY, b);
000259 CREATE TABLE c1(x REFERENCES p1 DEFERRABLE INITIALLY DEFERRED);
000260 }
000261
000262 do_execsql_test 5.1 {
000263 BEGIN;
000264 INSERT INTO c1 VALUES(123);
000265 PRAGMA defer_foreign_keys = 1;
000266 INSERT INTO p1 VALUES(123, 'one two three');
000267 COMMIT;
000268 }
000269
000270
000271 finish_test