xref: /sqlite-3.40.0/test/fkey1.test (revision 38d69855)
1# 2001 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
16set testdir [file dirname $argv0]
17source $testdir/tester.tcl
18
19ifcapable {!foreignkey} {
20  finish_test
21  return
22}
23
24# Create a table and some data to work with.
25#
26do_test fkey1-1.0 {
27  execsql {
28    CREATE TABLE t1(
29      a INTEGER PRIMARY KEY,
30      b INTEGER
31           REFERENCES t1 ON DELETE CASCADE
32           REFERENCES t2,
33      c TEXT,
34      FOREIGN KEY (b,c) REFERENCES t2(x,y) ON UPDATE CASCADE
35    );
36  }
37} {}
38do_test fkey1-1.1 {
39  execsql {
40    CREATE TABLE t2(
41      x INTEGER PRIMARY KEY,
42      y TEXT
43    );
44  }
45} {}
46do_test fkey1-1.2 {
47  execsql {
48    CREATE TABLE t3(
49      a INTEGER REFERENCES t2,
50      b INTEGER REFERENCES t1,
51      FOREIGN KEY (a,b) REFERENCES t2(x,y)
52    );
53  }
54} {}
55
56do_test fkey1-2.1 {
57  execsql {
58    CREATE TABLE t4(a integer primary key);
59    CREATE TABLE t5(x references t4);
60    CREATE TABLE t6(x references t4);
61    CREATE TABLE t7(x references t4);
62    CREATE TABLE t8(x references t4);
63    CREATE TABLE t9(x references t4);
64    CREATE TABLE t10(x references t4);
65    DROP TABLE t7;
66    DROP TABLE t9;
67    DROP TABLE t5;
68    DROP TABLE t8;
69    DROP TABLE t6;
70    DROP TABLE t10;
71  }
72} {}
73
74do_test fkey1-3.1 {
75  execsql {
76    CREATE TABLE t5(a PRIMARY KEY, b, c);
77    CREATE TABLE t6(
78      d REFERENCES t5,
79      e REFERENCES t5(c)
80    );
81    PRAGMA foreign_key_list(t6);
82  }
83} [concat                                         \
84  {0 0 t5 e c {NO ACTION} {NO ACTION} NONE}       \
85  {1 0 t5 d {} {NO ACTION} {NO ACTION} NONE}      \
86]
87do_test fkey1-3.2 {
88  execsql {
89    CREATE TABLE t7(d, e, f,
90      FOREIGN KEY (d, e) REFERENCES t5(a, b)
91    );
92    PRAGMA foreign_key_list(t7);
93  }
94} [concat                                   \
95  {0 0 t5 d a {NO ACTION} {NO ACTION} NONE} \
96  {0 1 t5 e b {NO ACTION} {NO ACTION} NONE} \
97]
98do_test fkey1-3.3 {
99  execsql {
100    CREATE TABLE t8(d, e, f,
101      FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET NULL
102    );
103    PRAGMA foreign_key_list(t8);
104  }
105} [concat                        \
106  {0 0 t5 d {} {SET NULL} CASCADE NONE} \
107  {0 1 t5 e {} {SET NULL} CASCADE NONE} \
108]
109do_test fkey1-3.4 {
110  execsql {
111    CREATE TABLE t9(d, e, f,
112      FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET DEFAULT
113    );
114    PRAGMA foreign_key_list(t9);
115  }
116} [concat                        \
117  {0 0 t5 d {} {SET DEFAULT} CASCADE NONE} \
118  {0 1 t5 e {} {SET DEFAULT} CASCADE NONE} \
119]
120do_test fkey1-3.5 {
121  sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
122} {0 0 0}
123
124# Stress the dequoting logic.  The first test is not so bad.
125do_execsql_test fkey1-4.0 {
126  PRAGMA foreign_keys=ON;
127  CREATE TABLE "xx1"("xx2" TEXT PRIMARY KEY, "xx3" TEXT);
128  INSERT INTO "xx1"("xx2","xx3") VALUES('abc','def');
129  CREATE TABLE "xx4"("xx5" TEXT REFERENCES "xx1" ON DELETE CASCADE);
130  INSERT INTO "xx4"("xx5") VALUES('abc');
131  INSERT INTO "xx1"("xx2","xx3") VALUES('uvw','xyz');
132  SELECT 1, "xx5" FROM "xx4";
133  DELETE FROM "xx1";
134  SELECT 2, "xx5" FROM "xx4";
135} {1 abc}
136
137# This case is identical to the previous except the "xx" in each name
138# is changed to a single escaped double-quote character.
139do_execsql_test fkey1-4.1 {
140  PRAGMA foreign_keys=ON;
141  CREATE TABLE """1"("""2" TEXT PRIMARY KEY, """3" TEXT);
142  INSERT INTO """1"("""2","""3") VALUES('abc','def');
143  CREATE TABLE """4"("""5" TEXT REFERENCES """1" ON DELETE CASCADE);
144  INSERT INTO """4"("""5") VALUES('abc');
145  INSERT INTO """1"("""2","""3") VALUES('uvw','xyz');
146  SELECT 1, """5" FROM """4";
147  DELETE FROM """1";
148  SELECT 2, """5" FROM """4";
149} {1 abc}
150do_execsql_test fkey1-4.2 {
151  PRAGMA table_info="""1";
152} {0 {"2} TEXT 0 {} 1 1 {"3} TEXT 0 {} 0}
153
154#-------------------------------------------------------------------------
155#
156do_execsql_test fkey1-5.1 {
157  CREATE TABLE t11(
158    x INTEGER PRIMARY KEY,
159    parent REFERENCES t11 ON DELETE CASCADE
160  );
161  INSERT INTO t11 VALUES (1, NULL), (2, 1), (3, 2);
162} {}
163
164# The REPLACE part of this statement deletes the row (2, 1). Then the
165# DELETE CASCADE caused by deleting that row removes the (3, 2) row. Which
166# would have been the parent of the new row being inserted. Causing an
167# FK violation.
168#
169do_catchsql_test fkey1-5.2 {
170  INSERT OR REPLACE INTO t11 VALUES (2, 3);
171} {1 {FOREIGN KEY constraint failed}}
172
173# A similar test to the above.
174do_execsql_test fkey1-5.3 {
175  CREATE TABLE Foo (
176    Id INTEGER PRIMARY KEY,
177    ParentId INTEGER REFERENCES Foo(Id) ON DELETE CASCADE, C1
178  );
179  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (1, null, 'A');
180  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 1, 'A-2-1');
181  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (3, 2, 'A-3-2');
182  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (4, 3, 'A-4-3');
183}
184do_catchsql_test fkey1-5.4 {
185  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 3, 'A-2-3');
186} {1 {FOREIGN KEY constraint failed}}
187
188finish_test
189