1# 2012 December 17 2# 3# The author disclaims copyright to this source code. In place of 4# a legal notice, here is a blessing: 5# 6# May you do good and not evil. 7# May you find forgiveness for yourself and forgive others. 8# May you share freely, never taking more than you give. 9# 10#*********************************************************************** 11# This file implements regression tests for SQLite library. 12# 13# This file tests the PRAGMA defer_foreign_keys and 14# SQLITE_DBSTATUS_DEFERRED_FKS 15# 16# EVIDENCE-OF: R-18981-16292 When the defer_foreign_keys PRAGMA is on, 17# enforcement of all foreign key constraints is delayed until the 18# outermost transaction is committed. 19# 20# EVIDENCE-OF: R-28911-57501 The defer_foreign_keys pragma defaults to 21# OFF so that foreign key constraints are only deferred if they are 22# created as "DEFERRABLE INITIALLY DEFERRED". 23 24set testdir [file dirname $argv0] 25source $testdir/tester.tcl 26set testprefix fkey6 27 28ifcapable {!foreignkey} { 29 finish_test 30 return 31} 32 33do_execsql_test fkey6-1.0 { 34 PRAGMA defer_foreign_keys; 35} {0} 36 37do_execsql_test fkey6-1.1 { 38 PRAGMA foreign_keys=ON; 39 CREATE TABLE t1(x INTEGER PRIMARY KEY); 40 CREATE TABLE t2(y INTEGER PRIMARY KEY, 41 z INTEGER REFERENCES t1(x) DEFERRABLE INITIALLY DEFERRED); 42 CREATE INDEX t2z ON t2(z); 43 CREATE TABLE t3(u INTEGER PRIMARY KEY, v INTEGER REFERENCES t1(x)); 44 CREATE INDEX t3v ON t3(v); 45 INSERT INTO t1 VALUES(1),(2),(3),(4),(5); 46 INSERT INTO t2 VALUES(1,1),(2,2); 47 INSERT INTO t3 VALUES(3,3),(4,4); 48} {} 49do_test fkey6-1.2 { 50 catchsql {DELETE FROM t1 WHERE x=2;} 51} {1 {FOREIGN KEY constraint failed}} 52do_test fkey6-1.3 { 53 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 54} {0 0 0} 55do_test fkey6-1.4 { 56 execsql { 57 BEGIN; 58 DELETE FROM t1 WHERE x=1; 59 } 60} {} 61do_test fkey6-1.5.1 { 62 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 1 63} {0 1 0} 64do_test fkey6-1.5.2 { 65 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 66} {0 1 0} 67do_test fkey6-1.6 { 68 execsql { 69 ROLLBACK; 70 } 71} {} 72do_test fkey6-1.7 { 73 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 74} {0 0 0} 75do_test fkey6-1.8 { 76 execsql { 77 PRAGMA defer_foreign_keys=ON; 78 BEGIN; 79 DELETE FROM t1 WHERE x=3; 80 } 81} {} 82do_test fkey6-1.9 { 83 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 84} {0 1 0} 85 86# EVIDENCE-OF: R-21752-26913 The defer_foreign_keys pragma is 87# automatically switched off at each COMMIT or ROLLBACK. Hence, the 88# defer_foreign_keys pragma must be separately enabled for each 89# transaction. 90do_execsql_test fkey6-1.10.1 { 91 PRAGMA defer_foreign_keys; 92 ROLLBACK; 93 PRAGMA defer_foreign_keys; 94 BEGIN; 95 PRAGMA defer_foreign_keys=ON; 96 PRAGMA defer_foreign_keys; 97 COMMIT; 98 PRAGMA defer_foreign_keys; 99 BEGIN; 100} {1 0 1 0} 101do_test fkey6-1.10.2 { 102 catchsql {DELETE FROM t1 WHERE x=3} 103} {1 {FOREIGN KEY constraint failed}} 104db eval {ROLLBACK} 105 106do_test fkey6-1.20 { 107 execsql { 108 BEGIN; 109 DELETE FROM t1 WHERE x=1; 110 } 111 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 112} {0 1 0} 113do_test fkey6-1.21 { 114 execsql { 115 DELETE FROM t2 WHERE y=1; 116 } 117 sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 118} {0 0 0} 119do_test fkey6-1.22 { 120 execsql { 121 COMMIT; 122 } 123} {} 124 125do_execsql_test fkey6-2.1 { 126 CREATE TABLE p1(a PRIMARY KEY); 127 INSERT INTO p1 VALUES('one'), ('two'); 128 CREATE TABLE c1(x REFERENCES p1); 129 INSERT INTO c1 VALUES('two'), ('one'); 130} 131 132do_execsql_test fkey6-2.2 { 133 BEGIN; 134 PRAGMA defer_foreign_keys = 1; 135 DELETE FROM p1; 136 ROLLBACK; 137 PRAGMA defer_foreign_keys; 138} {0} 139 140do_execsql_test fkey6-2.3 { 141 BEGIN; 142 PRAGMA defer_foreign_keys = 1; 143 DROP TABLE p1; 144 PRAGMA vdbe_trace = 0; 145 ROLLBACK; 146 PRAGMA defer_foreign_keys; 147} {0} 148 149do_execsql_test fkey6-2.4 { 150 BEGIN; 151 PRAGMA defer_foreign_keys = 1; 152 DELETE FROM p1; 153 DROP TABLE c1; 154 COMMIT; 155 PRAGMA defer_foreign_keys; 156} {0} 157 158do_execsql_test fkey6-2.5 { 159 DROP TABLE p1; 160 CREATE TABLE p1(a PRIMARY KEY); 161 INSERT INTO p1 VALUES('one'), ('two'); 162 CREATE TABLE c1(x REFERENCES p1); 163 INSERT INTO c1 VALUES('two'), ('one'); 164} 165 166do_execsql_test fkey6-2.6 { 167 BEGIN; 168 PRAGMA defer_foreign_keys = 1; 169 INSERT INTO c1 VALUES('three'); 170 DROP TABLE c1; 171 COMMIT; 172 PRAGMA defer_foreign_keys; 173} {0} 174 175#-------------------------------------------------------------------------- 176# Test that defer_foreign_keys disables RESTRICT. 177# 178do_execsql_test 3.1 { 179 CREATE TABLE p2(a PRIMARY KEY, b); 180 CREATE TABLE c2(x, y REFERENCES p2 ON DELETE RESTRICT ON UPDATE RESTRICT); 181 INSERT INTO p2 VALUES(1, 'one'); 182 INSERT INTO p2 VALUES(2, 'two'); 183 INSERT INTO c2 VALUES('i', 1); 184} 185 186do_catchsql_test 3.2.1 { 187 BEGIN; 188 UPDATE p2 SET a=a-1; 189} {1 {FOREIGN KEY constraint failed}} 190do_execsql_test 3.2.2 { COMMIT } 191 192do_execsql_test 3.2.3 { 193 BEGIN; 194 PRAGMA defer_foreign_keys = 1; 195 UPDATE p2 SET a=a-1; 196 COMMIT; 197} 198 199do_execsql_test 3.2.4 { 200 BEGIN; 201 PRAGMA defer_foreign_keys = 1; 202 UPDATE p2 SET a=a-1; 203} 204do_catchsql_test 3.2.5 { 205 COMMIT; 206} {1 {FOREIGN KEY constraint failed}} 207do_execsql_test 3.2.6 { ROLLBACK } 208 209do_execsql_test 3.3.1 { 210 CREATE TRIGGER p2t AFTER DELETE ON p2 BEGIN 211 INSERT INTO p2 VALUES(old.a, 'deleted!'); 212 END; 213} 214do_catchsql_test 3.3.2 { 215 BEGIN; 216 DELETE FROM p2 WHERE a=1; 217} {1 {FOREIGN KEY constraint failed}} 218do_execsql_test 3.3.3 { COMMIT } 219 220do_execsql_test 3.3.4 { 221 BEGIN; 222 PRAGMA defer_foreign_keys = 1; 223 DELETE FROM p2 WHERE a=1; 224 COMMIT; 225 SELECT * FROM p2; 226} {0 one 1 deleted!} 227 228 229finish_test 230