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