xref: /sqlite-3.40.0/test/fkey1.test (revision 39075608)
1c2eef3b3Sdrh# 2001 September 15
2c2eef3b3Sdrh#
3c2eef3b3Sdrh# The author disclaims copyright to this source code.  In place of
4c2eef3b3Sdrh# a legal notice, here is a blessing:
5c2eef3b3Sdrh#
6c2eef3b3Sdrh#    May you do good and not evil.
7c2eef3b3Sdrh#    May you find forgiveness for yourself and forgive others.
8c2eef3b3Sdrh#    May you share freely, never taking more than you give.
9c2eef3b3Sdrh#
10c2eef3b3Sdrh#***********************************************************************
11c2eef3b3Sdrh# This file implements regression tests for SQLite library.
12c2eef3b3Sdrh#
13c2eef3b3Sdrh# This file implements tests for foreign keys.
14c2eef3b3Sdrh#
15c2eef3b3Sdrh
16c2eef3b3Sdrhset testdir [file dirname $argv0]
17c2eef3b3Sdrhsource $testdir/tester.tcl
1868a494c0Sdanset testprefix fkey1
19c2eef3b3Sdrh
206bf89570Sdrhifcapable {!foreignkey} {
216bf89570Sdrh  finish_test
226bf89570Sdrh  return
236bf89570Sdrh}
246bf89570Sdrh
25c2eef3b3Sdrh# Create a table and some data to work with.
26c2eef3b3Sdrh#
27c2eef3b3Sdrhdo_test fkey1-1.0 {
28c2eef3b3Sdrh  execsql {
29c2eef3b3Sdrh    CREATE TABLE t1(
30c2eef3b3Sdrh      a INTEGER PRIMARY KEY,
31c2eef3b3Sdrh      b INTEGER
32c2eef3b3Sdrh           REFERENCES t1 ON DELETE CASCADE
33c2eef3b3Sdrh           REFERENCES t2,
34c2eef3b3Sdrh      c TEXT,
35c2eef3b3Sdrh      FOREIGN KEY (b,c) REFERENCES t2(x,y) ON UPDATE CASCADE
36c2eef3b3Sdrh    );
37c2eef3b3Sdrh  }
38c2eef3b3Sdrh} {}
39c2eef3b3Sdrhdo_test fkey1-1.1 {
40c2eef3b3Sdrh  execsql {
41c2eef3b3Sdrh    CREATE TABLE t2(
42c2eef3b3Sdrh      x INTEGER PRIMARY KEY,
43c2eef3b3Sdrh      y TEXT
44c2eef3b3Sdrh    );
45c2eef3b3Sdrh  }
46c2eef3b3Sdrh} {}
472dcc9aa2Sdrhdo_test fkey1-1.2 {
482dcc9aa2Sdrh  execsql {
492dcc9aa2Sdrh    CREATE TABLE t3(
501da40a38Sdan      a INTEGER REFERENCES t2,
512dcc9aa2Sdrh      b INTEGER REFERENCES t1,
522dcc9aa2Sdrh      FOREIGN KEY (a,b) REFERENCES t2(x,y)
532dcc9aa2Sdrh    );
542dcc9aa2Sdrh  }
552dcc9aa2Sdrh} {}
5685c23c61Sdrh
5785c23c61Sdrhdo_test fkey1-2.1 {
5885c23c61Sdrh  execsql {
5985c23c61Sdrh    CREATE TABLE t4(a integer primary key);
6085c23c61Sdrh    CREATE TABLE t5(x references t4);
6185c23c61Sdrh    CREATE TABLE t6(x references t4);
6285c23c61Sdrh    CREATE TABLE t7(x references t4);
6385c23c61Sdrh    CREATE TABLE t8(x references t4);
6485c23c61Sdrh    CREATE TABLE t9(x references t4);
6585c23c61Sdrh    CREATE TABLE t10(x references t4);
6685c23c61Sdrh    DROP TABLE t7;
6785c23c61Sdrh    DROP TABLE t9;
6885c23c61Sdrh    DROP TABLE t5;
6985c23c61Sdrh    DROP TABLE t8;
7085c23c61Sdrh    DROP TABLE t6;
7185c23c61Sdrh    DROP TABLE t10;
7285c23c61Sdrh  }
7385c23c61Sdrh} {}
7485c23c61Sdrh
7550af3e1dSdanielk1977do_test fkey1-3.1 {
7650af3e1dSdanielk1977  execsql {
7750af3e1dSdanielk1977    CREATE TABLE t5(a PRIMARY KEY, b, c);
7850af3e1dSdanielk1977    CREATE TABLE t6(
7950af3e1dSdanielk1977      d REFERENCES t5,
8050af3e1dSdanielk1977      e REFERENCES t5(c)
8150af3e1dSdanielk1977    );
8250af3e1dSdanielk1977    PRAGMA foreign_key_list(t6);
8350af3e1dSdanielk1977  }
8450af3e1dSdanielk1977} [concat                                         \
851da40a38Sdan  {0 0 t5 e c {NO ACTION} {NO ACTION} NONE}       \
861da40a38Sdan  {1 0 t5 d {} {NO ACTION} {NO ACTION} NONE}      \
8750af3e1dSdanielk1977]
8850af3e1dSdanielk1977do_test fkey1-3.2 {
8950af3e1dSdanielk1977  execsql {
9050af3e1dSdanielk1977    CREATE TABLE t7(d, e, f,
9150af3e1dSdanielk1977      FOREIGN KEY (d, e) REFERENCES t5(a, b)
9250af3e1dSdanielk1977    );
9350af3e1dSdanielk1977    PRAGMA foreign_key_list(t7);
9450af3e1dSdanielk1977  }
9550af3e1dSdanielk1977} [concat                                   \
961da40a38Sdan  {0 0 t5 d a {NO ACTION} {NO ACTION} NONE} \
971da40a38Sdan  {0 1 t5 e b {NO ACTION} {NO ACTION} NONE} \
9850af3e1dSdanielk1977]
9950af3e1dSdanielk1977do_test fkey1-3.3 {
10050af3e1dSdanielk1977  execsql {
10150af3e1dSdanielk1977    CREATE TABLE t8(d, e, f,
10250af3e1dSdanielk1977      FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET NULL
10350af3e1dSdanielk1977    );
10450af3e1dSdanielk1977    PRAGMA foreign_key_list(t8);
10550af3e1dSdanielk1977  }
10650af3e1dSdanielk1977} [concat                        \
10750af3e1dSdanielk1977  {0 0 t5 d {} {SET NULL} CASCADE NONE} \
10850af3e1dSdanielk1977  {0 1 t5 e {} {SET NULL} CASCADE NONE} \
10950af3e1dSdanielk1977]
110d2cb50b7Sdrhdo_test fkey1-3.4 {
111d2cb50b7Sdrh  execsql {
112d2cb50b7Sdrh    CREATE TABLE t9(d, e, f,
113d2cb50b7Sdrh      FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET DEFAULT
114d2cb50b7Sdrh    );
115d2cb50b7Sdrh    PRAGMA foreign_key_list(t9);
116d2cb50b7Sdrh  }
117d2cb50b7Sdrh} [concat                        \
118d2cb50b7Sdrh  {0 0 t5 d {} {SET DEFAULT} CASCADE NONE} \
119d2cb50b7Sdrh  {0 1 t5 e {} {SET DEFAULT} CASCADE NONE} \
120d2cb50b7Sdrh]
121648e2643Sdrhdo_test fkey1-3.5 {
122648e2643Sdrh  sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0
123648e2643Sdrh} {0 0 0}
124c2eef3b3Sdrh
125b6b676eaSdrh# Stress the dequoting logic.  The first test is not so bad.
126b6b676eaSdrhdo_execsql_test fkey1-4.0 {
127b6b676eaSdrh  PRAGMA foreign_keys=ON;
128b6b676eaSdrh  CREATE TABLE "xx1"("xx2" TEXT PRIMARY KEY, "xx3" TEXT);
129b6b676eaSdrh  INSERT INTO "xx1"("xx2","xx3") VALUES('abc','def');
130b6b676eaSdrh  CREATE TABLE "xx4"("xx5" TEXT REFERENCES "xx1" ON DELETE CASCADE);
131b6b676eaSdrh  INSERT INTO "xx4"("xx5") VALUES('abc');
132b6b676eaSdrh  INSERT INTO "xx1"("xx2","xx3") VALUES('uvw','xyz');
133b6b676eaSdrh  SELECT 1, "xx5" FROM "xx4";
134b6b676eaSdrh  DELETE FROM "xx1";
135b6b676eaSdrh  SELECT 2, "xx5" FROM "xx4";
136b6b676eaSdrh} {1 abc}
137b6b676eaSdrh
138b6b676eaSdrh# This case is identical to the previous except the "xx" in each name
139b6b676eaSdrh# is changed to a single escaped double-quote character.
140b6b676eaSdrhdo_execsql_test fkey1-4.1 {
141b6b676eaSdrh  PRAGMA foreign_keys=ON;
142b6b676eaSdrh  CREATE TABLE """1"("""2" TEXT PRIMARY KEY, """3" TEXT);
143b6b676eaSdrh  INSERT INTO """1"("""2","""3") VALUES('abc','def');
144b6b676eaSdrh  CREATE TABLE """4"("""5" TEXT REFERENCES """1" ON DELETE CASCADE);
145b6b676eaSdrh  INSERT INTO """4"("""5") VALUES('abc');
146b6b676eaSdrh  INSERT INTO """1"("""2","""3") VALUES('uvw','xyz');
147b6b676eaSdrh  SELECT 1, """5" FROM """4";
148b6b676eaSdrh  DELETE FROM """1";
149b6b676eaSdrh  SELECT 2, """5" FROM """4";
150b6b676eaSdrh} {1 abc}
151b6b676eaSdrhdo_execsql_test fkey1-4.2 {
152b6b676eaSdrh  PRAGMA table_info="""1";
153b6b676eaSdrh} {0 {"2} TEXT 0 {} 1 1 {"3} TEXT 0 {} 0}
154b6b676eaSdrh
155e755e10aSdan#-------------------------------------------------------------------------
156e755e10aSdan#
157e755e10aSdando_execsql_test fkey1-5.1 {
158e755e10aSdan  CREATE TABLE t11(
159e755e10aSdan    x INTEGER PRIMARY KEY,
160e755e10aSdan    parent REFERENCES t11 ON DELETE CASCADE
161e755e10aSdan  );
162e755e10aSdan  INSERT INTO t11 VALUES (1, NULL), (2, 1), (3, 2);
163e755e10aSdan} {}
164e755e10aSdan
165e755e10aSdan# The REPLACE part of this statement deletes the row (2, 1). Then the
166e755e10aSdan# DELETE CASCADE caused by deleting that row removes the (3, 2) row. Which
167e755e10aSdan# would have been the parent of the new row being inserted. Causing an
168e755e10aSdan# FK violation.
169e755e10aSdan#
170e755e10aSdando_catchsql_test fkey1-5.2 {
171e755e10aSdan  INSERT OR REPLACE INTO t11 VALUES (2, 3);
172e755e10aSdan} {1 {FOREIGN KEY constraint failed}}
173e755e10aSdan
174e307e11dSdrh# Make sure sqlite3_trace() output works with triggers used to implement
175e307e11dSdrh# FK constraints
176e307e11dSdrh#
1774064a4ccSdanifcapable trace {
178e307e11dSdrh  proc sqltrace {txt} {
179e307e11dSdrh    global traceoutput
180e307e11dSdrh    lappend traceoutput $txt
181e307e11dSdrh  }
182e307e11dSdrh  do_test fkey1-5.2.1 {
183e307e11dSdrh    unset -nocomplain traceoutput
184e307e11dSdrh    db trace sqltrace
185e307e11dSdrh    catch {db eval {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
186e307e11dSdrh    set traceoutput
187e307e11dSdrh  } {{INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
1884064a4ccSdan}
189e307e11dSdrh
190e755e10aSdan# A similar test to the above.
191e755e10aSdando_execsql_test fkey1-5.3 {
192e755e10aSdan  CREATE TABLE Foo (
193e755e10aSdan    Id INTEGER PRIMARY KEY,
194e755e10aSdan    ParentId INTEGER REFERENCES Foo(Id) ON DELETE CASCADE, C1
195e755e10aSdan  );
196e755e10aSdan  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (1, null, 'A');
197e755e10aSdan  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 1, 'A-2-1');
198e755e10aSdan  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (3, 2, 'A-3-2');
199e755e10aSdan  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (4, 3, 'A-4-3');
200e755e10aSdan}
201e755e10aSdando_catchsql_test fkey1-5.4 {
202e755e10aSdan  INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 3, 'A-2-3');
203e755e10aSdan} {1 {FOREIGN KEY constraint failed}}
204e755e10aSdan
20568a494c0Sdan#-------------------------------------------------------------------------
20668a494c0Sdan# Check that foreign key processing is not fooled by partial indexes
20768a494c0Sdan# on the parent table.
20868a494c0Sdan#
20968a494c0Sdando_execsql_test 6.0 {
21068a494c0Sdan  CREATE TABLE p1(x, y);
21168a494c0Sdan  CREATE UNIQUE INDEX p1x ON p1(x) WHERE y<2;
21268a494c0Sdan  INSERT INTO p1 VALUES(1, 1);
21368a494c0Sdan  CREATE TABLE c1(a REFERENCES p1(x));
21468a494c0Sdan}
21568a494c0Sdan
21668a494c0Sdando_catchsql_test 6.1 {
21768a494c0Sdan  INSERT INTO c1 VALUES(1);
21868a494c0Sdan} {1 {foreign key mismatch - "c1" referencing "p1"}}
21968a494c0Sdan
22068a494c0Sdando_execsql_test 6.2 {
22168a494c0Sdan  CREATE UNIQUE INDEX p1x2 ON p1(x);
22268a494c0Sdan  INSERT INTO c1 VALUES(1);
22368a494c0Sdan} {}
22468a494c0Sdan
2255c46a7e5Sdrh# 2021-07-03 https://sqlite.org/forum/forumpost/a6b0c05277
2264f16ff9dSdrh# 2021-07-07 https://sqlite.org/forum/forumpost/79c9e4797d
2275c46a7e5Sdrh# Failure to allocate enough registers in the VDBE for a
2285c46a7e5Sdrh# PRAGMA foreign_key_check when the foreign key has more
2295c46a7e5Sdrh# columns than the table.
2305c46a7e5Sdrh#
2315c46a7e5Sdrhreset_db
2325c46a7e5Sdrhdo_execsql_test 7.1 {
2335c46a7e5Sdrh  PRAGMA foreign_keys=OFF;
2345c46a7e5Sdrh  CREATE TABLE t1(a,b,c,FOREIGN KEY(a,a,a,a,a,a,a,a,a,a,a,a,a,a) REFERENCES t0);
2355c46a7e5Sdrh  INSERT INTO t1 VALUES(1,2,3);
2365c46a7e5Sdrh  PRAGMA foreign_key_check;
2375c46a7e5Sdrh} {t1 1 t0 0}
2384f16ff9dSdrhdo_execsql_test 7.2 {
2394f16ff9dSdrh  DROP TABLE t1;
2404f16ff9dSdrh  CREATE TABLE t1(a,b,c AS(1),d, FOREIGN KEY(c,d,b,a,b,d,b,c) REFERENCES t0);
2414f16ff9dSdrh  PRAGMA foreign_key_check;
2424f16ff9dSdrh} {}
2435c46a7e5Sdrh
244*39075608Sdrh# 2021-12-31 forum https://sqlite.org/forum/forumpost/24bd1fef7e9323ef
245*39075608Sdrh# Memory leak caused by sqlite3NestedParse() running on a corrupt system
246*39075608Sdrh# table.  Discovered by Jingzhou Fu.
247*39075608Sdrh#
248*39075608Sdrhreset_db
249*39075608Sdrhdo_execsql_test 8.1 {
250*39075608Sdrh  PRAGMA writable_schema=ON;
251*39075608Sdrh  PRAGMA foreign_keys = ON;
252*39075608Sdrh  CREATE TABLE sqlite_stat1 (tbl INTEGER PRIMARY KEY DESC, idx UNIQUE DEFAULT NULL) WITHOUT ROWID;
253*39075608Sdrh  PRAGMA writable_schema=OFF;
254*39075608Sdrh  CREATE TABLE sqlsim4(stat PRIMARY KEY);;
255*39075608Sdrh  CREATE TABLE t1(sqlsim7 REFERENCES sqlite_stat1 ON DELETE CASCADE);
256*39075608Sdrh  DROP table "sqlsim4";
257*39075608Sdrh} {}
258*39075608Sdrh# 2022-01-01 dbsqlfuzz 1c57440219f6f0aedf5e8f72a8ddd75f15aea381
259*39075608Sdrh# Follow-up case to the above.  Assertion is not true if the schema
260*39075608Sdrh# is corrupt.
261*39075608Sdrhreset_db
262*39075608Sdrhdatabase_may_be_corrupt
263*39075608Sdrhdo_execsql_test 8.2 {
264*39075608Sdrh  CREATE TABLE t1(a REFERENCES sqlite_stat1 ON DELETE CASCADE);
265*39075608Sdrh  CREATE TABLE t2(a TEXT PRIMARY KEY);
266*39075608Sdrh  PRAGMA writable_schema=ON;
267*39075608Sdrh  CREATE TABLE sqlite_stat1(tbl INTEGER PRIMARY KEY DESC, idx UNIQUE DEFAULT NULL) WITHOUT ROWID;
268*39075608Sdrh  UPDATE sqlite_schema SET name='sqlite_autoindex_sqlite_stat1_1' WHERE name='sqlite_autoindex_sqlite_stat1_2';
269*39075608Sdrh  PRAGMA writable_schema=RESET;
270*39075608Sdrh} {}
271*39075608Sdrhdo_catchsql_test 8.3 {
272*39075608Sdrh  REINDEX;
273*39075608Sdrh} {1 {database disk image is malformed}}
27468a494c0Sdan
275c2eef3b3Sdrhfinish_test
276