1
0
mirror of https://github.com/sqlite/sqlite.git synced 2026-10-23 21:49:02 +03:00

Move the new test cases for this branch into a new *.test file.

FossilOrigin-Name: 7bdce4ec3b9995a13536eaa2e6a5702333e792b35fa58e606b2e4fa38b85f524
This commit is contained in:
drh
2026-07-20 14:37:21 +00:00
parent 65a80d9000
commit 5179e97d9e
4 changed files with 206 additions and 185 deletions

View File

@@ -1,5 +1,5 @@
C Test\scase\sfixes\sdue\sto\sthe\sprevious.
D 2026-07-18T19:49:18.411
C Move\sthe\snew\stest\scases\sfor\sthis\sbranch\sinto\sa\snew\s*.test\sfile.
D 2026-07-20T14:37:21.102
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -996,6 +996,7 @@ F test/columncount.test 6fe99c2f35738b0129357a1cf3fa483f76140f4cd8a89014c88c33c8
F test/conflict.test 3307ffdf988e04b01c4e942d8aa369a977f085bf629f43a627c9a77f39d65926
F test/conflict2.test 5557909ce683b1073982f5d1b61dfb1d41e369533bfdaf003180c5bc87282dd1
F test/conflict3.test 81865d9599609aca394fb3b9cd5f561d4729ea5b176bece3644f6ecb540f88ac
F test/conflict4.test ac0d4274d63dc3531707c78d112b1f2411a03a71b9801a237fb325d2ff76f0a1
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
F test/corrupt.test 54509b182b1927663e0a425b681b0935a08a01b11d8153a4a9545ed36760ebe2
F test/corrupt2.test 4ce5eadd51baa1aedb48e141dd885d155946f5c3677bb032547e350ce91b17f4
@@ -1947,7 +1948,7 @@ F test/upfrom2.test 66f3ebf721b3cebd922faee5c386bf244f816d416b57c000753ff51af623
F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0
F test/upfrom4.test 78f742a6577c91a7a55c64edb8811004e7c6aa99b8d57b2320f70a918c357807
F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6
F test/upsert1.test 1ae9667f734f5ba1f4be4db351020e336e661e77192fb726b211cc5b74d6ce9b
F test/upsert1.test 55e85a95cc6e09ab436b411eb4d76b37952752e0501a57848e4296d6be585ef5
F test/upsert2.test 720e94d09f7362a282bc69b3c6b83d51daeaaf0440eb4920a08b86518b8c7496
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
@@ -2215,8 +2216,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
P e2ab286bb713e1358ae9a1d50dc894362d0ea6f1a2e8467c587f42f0e483dd3a
R b1bddc0276aa195bc5ec2df639e3f657
P 923665823276ee9404a9fdb19378b970eeea77a97bc2f4312446c6f6bc5e4405
R c590c51c3034bc599664aab2db20c157
U drh
Z d0f0bea09313f1d71203c2b202fb85a6
Z a7c0e72149e007f4528ceaeb8c532ec1
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
923665823276ee9404a9fdb19378b970eeea77a97bc2f4312446c6f6bc5e4405
7bdce4ec3b9995a13536eaa2e6a5702333e792b35fa58e606b2e4fa38b85f524

162
test/conflict4.test Normal file
View File

@@ -0,0 +1,162 @@
# 2026-07-20
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Test cases for UNIQUE ON CONFLICT REPLACE and UNIQUE ON CONFLICT FAIL
# behavior including when there are also triggers and/or an UPSERT.
#
# Forum thread 2026-07-17T09:30:42Z
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix conflict4
# Combination of ON CONFLICT FAIL on a UNIQUE index and
# an ON CONFLICT DO NOTHING in a different index leads to
# database corruption.
#
do_execsql_test 1.1 {
CREATE TABLE t0(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT FAIL,
c INT UNIQUE ON CONFLICT ABORT
);
INSERT INTO t0 VALUES (1, 10, 100),(2, 20, 200);
}
do_catchsql_test 1.2 {
INSERT INTO t0 VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t0.b}}
do_execsql_test 1.3 {
PRAGMA integrity_check;
} {ok}
do_execsql_test 1.4 {
SELECT * FROM t0 ORDER BY a;
} {1 10 100 2 20 200}
do_execsql_test 1.5 {
DROP TABLE t0;
CREATE TABLE t0(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT IGNORE,
c INT UNIQUE ON CONFLICT ABORT
);
INSERT INTO t0 VALUES (1, 10, 100),(2, 20, 200);
}
do_catchsql_test 1.6 {
INSERT INTO t0 VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING;
} {0 {}}
do_execsql_test 1.7 {
PRAGMA integrity_check;
} {ok}
do_execsql_test 1.8 {
SELECT * FROM t0 ORDER BY a;
} {1 10 100 2 20 200}
do_execsql_test 1.9 {
DROP TABLE t0;
CREATE TABLE t0(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT FAIL,
c INT UNIQUE ON CONFLICT ABORT
);
INSERT INTO t0 VALUES (1, 10, 100),(2, 20, 200);
}
do_catchsql_test 1.10 {
INSERT INTO t0 VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t0.b}}
do_execsql_test 1.11 {
PRAGMA integrity_check;
} {ok}
do_execsql_test 1.12 {
SELECT * FROM t0 ORDER BY a;
} {1 10 100 2 20 200}
do_execsql_test 1.13 {
DROP TABLE t0;
CREATE TABLE t1(
a INTEGER PRIMARY KEY,
b UNIQUE ON CONFLICT FAIL,
c UNIQUE
);
INSERT INTO t1 VALUES(1, 1, 1);
}
do_catchsql_test 1.14 {
-- Inserts 0 rows, because hitting the constraint on (b) does ABORT:
INSERT INTO t1 VALUES(3, 3, 3), (2, 1, 2) ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t1.b}}
do_execsql_test 1.15 {
SELECT * FROM t1 ORDER BY a;
} {1 1 1 3 3 3}
do_catchsql_test 1.16 {
-- Inserts 1 row, because hitting the constraint on (b) does FAIL:
DELETE FROM t1 WHERE a=3;
INSERT INTO t1 VALUES(3, 3, 3), (2, 1, 2);
} {1 {UNIQUE constraint failed: t1.b}}
do_execsql_test 1.17 {
SELECT * FROM t1 ORDER BY a;
} {1 1 1 3 3 3}
do_execsql_test 1.18 {
PRAGMA integrity_check;
} ok
# Counter-example to the fix at check-in 2026-07-17T16:26:56.257Z
# provided by Pavan Nambi at forum post 2026-07-18T03:35:48Z
do_execsql_test 2.1 {
DROP TABLE t1;
PRAGMA recursive_triggers=ON;
CREATE TABLE t2(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT FAIL,
c INT UNIQUE ON CONFLICT ABORT
);
CREATE TRIGGER t_ad AFTER DELETE ON t2 BEGIN
INSERT INTO t2 VALUES(99,30,999);
END;
INSERT INTO t2 VALUES(1,10,100),(2,20,200);
SELECT * FROM t2 ORDER BY a;
} {1 10 100 2 20 200}
do_catchsql_test 2.2 {
INSERT INTO t2 VALUES(4,40,400),(1,30,300),(5,50,500)
ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t2.b}}
do_execsql_test 2.3 {
PRAGMA integrity_check;
} ok
do_execsql_test 2.4 {
SELECT * FROM t2 ORDER BY a;
} {1 10 100 2 20 200}
# This is a slightly simpler version of the test above. Before
# the bug was fixed, this would:
#
# 1) Checks there are no instances of 'HELLO' in the index on t1(b),
# 2) Deletes the row from t1 as a result of the REPLACE on the PK,
# 3) Fires the trigger, inserting ('HELLO', 200) into index t1(b).
# 4) Finishes the insert without rechecking t1(b), inserting
# ('HELLO', 100). Corruption.
#
reset_db
do_execsql_test 3.1 {
PRAGMA recursive_triggers = ON;
CREATE TABLE t1(
a PRIMARY KEY ON CONFLICT REPLACE,
b UNIQUE
);
INSERT INTO t1 VALUES(100, 'abcde');
CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
INSERT INTO t1 VALUES(200, 'HELLO');
END;
}
do_catchsql_test 3.2 {
INSERT INTO t1 VALUES(100, 'HELLO');
} {1 {UNIQUE constraint failed: t1.b}}
do_execsql_test 3.3 {
PRAGMA integrity_check;
SELECT * FROM t1 ORDER BY +a;
} {ok 100 abcde}
finish_test

View File

@@ -13,47 +13,47 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix zipfile
set testprefix upsert1
do_execsql_test upsert1-100 {
do_execsql_test 100 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c DEFAULT 0);
CREATE UNIQUE INDEX t1x1 ON t1(b);
INSERT INTO t1(a,b) VALUES(1,2) ON CONFLICT DO NOTHING;
INSERT INTO t1(a,b) VALUES(1,99),(99,2) ON CONFLICT DO NOTHING;
SELECT * FROM t1;
} {1 2 0}
do_execsql_test upsert1-101 {
do_execsql_test 101 {
DELETE FROM t1;
INSERT INTO t1(a,b) VALUES(2,3) ON CONFLICT(a) DO NOTHING;
INSERT INTO t1(a,b) VALUES(2,99) ON CONFLICT(a) DO NOTHING;
SELECT * FROM t1;
} {2 3 0}
do_execsql_test upsert1-102 {
do_execsql_test 102 {
DELETE FROM t1;
INSERT INTO t1(a,b) VALUES(3,4) ON CONFLICT(b) DO NOTHING;
INSERT INTO t1(a,b) VALUES(99,4) ON CONFLICT(b) DO NOTHING;
SELECT * FROM t1;
} {3 4 0}
do_catchsql_test upsert1-110 {
do_catchsql_test 110 {
INSERT INTO t1(a,b) VALUES(5,6) ON CONFLICT(x) DO NOTHING;
SELECT * FROM t1;
} {1 {no such column: x}}
do_catchsql_test upsert1-120 {
do_catchsql_test 120 {
INSERT INTO t1(a,b) VALUES(5,6) ON CONFLICT(c) DO NOTHING;
SELECT * FROM t1;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
breakpoint
do_catchsql_test upsert1-130 {
do_catchsql_test 130 {
INSERT INTO t1(a,b) VALUES(5,6) ON CONFLICT(b COLLATE nocase) DO NOTHING;
SELECT * FROM t1;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
do_execsql_test upsert1-140 {
do_execsql_test 140 {
DELETE FROM t1;
INSERT INTO t1(a,b) VALUES(5,6) ON CONFLICT(b COLLATE binary) DO NOTHING;
SELECT * FROM t1;
} {5 6 0}
do_catchsql_test upsert1-200 {
do_catchsql_test 200 {
DROP TABLE t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c DEFAULT 0);
CREATE UNIQUE INDEX t1x1 ON t1(a+b);
@@ -61,28 +61,28 @@ do_catchsql_test upsert1-200 {
INSERT INTO t1(a,b) VALUES(8,7),(9,6) ON CONFLICT(a+b) DO NOTHING;
SELECT * FROM t1;
} {0 {7 8 0}}
do_catchsql_test upsert1-201 {
do_catchsql_test 201 {
INSERT INTO t1(a,b) VALUES(8,7),(9,6) ON CONFLICT(a) DO NOTHING;
} {1 {UNIQUE constraint failed: index 't1x1'}}
do_catchsql_test upsert1-210 {
do_catchsql_test 210 {
DELETE FROM t1;
INSERT INTO t1(a,b) VALUES(9,10) ON CONFLICT(a+(+b)) DO NOTHING;
SELECT * FROM t1;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
do_catchsql_test upsert1-300 {
do_catchsql_test 300 {
DROP INDEX t1x1;
DELETE FROM t1;
CREATE UNIQUE INDEX t1x1 ON t1(b) WHERE b>10;
INSERT INTO t1(a,b) VALUES(1,2),(3,2) ON CONFLICT(b) DO NOTHING;
SELECT * FROM t1;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
do_catchsql_test upsert1-310 {
do_catchsql_test 310 {
DELETE FROM t1;
INSERT INTO t1(a,b) VALUES(1,2),(3,2) ON CONFLICT(b) WHERE b!=10 DO NOTHING;
SELECT * FROM t1;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
do_execsql_test upsert1-320 {
do_execsql_test 320 {
DELETE FROM t1;
INSERT INTO t1(a,b) VALUES(1,2),(3,2),(4,20),(5,20)
ON CONFLICT(b) WHERE b>10 DO NOTHING;
@@ -90,7 +90,7 @@ do_execsql_test upsert1-320 {
} {1 2 0 x 3 2 0 x 4 20 0 x}
# Upsert works with count_changes=on;
do_execsql_test upsert1-400 {
do_execsql_test 400 {
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(a TEXT UNIQUE, b INT DEFAULT 1);
INSERT INTO t2(a) VALUES('one'),('two'),('three');
@@ -98,13 +98,13 @@ do_execsql_test upsert1-400 {
INSERT INTO t2(a) VALUES('one'),('one'),('three'),('four')
ON CONFLICT(a) DO UPDATE SET b=b+1;
} {1}
do_execsql_test upsert1-410 {
do_execsql_test 410 {
PRAGMA count_changes=OFF;
SELECT a, b FROM t2 ORDER BY a;
} {four 1 one 3 three 2 two 1}
# Problem found by AFL prior to any release
do_execsql_test upsert1-500 {
do_execsql_test 500 {
DROP TABLE t1;
CREATE TABLE t1(x INTEGER PRIMARY KEY, y INT UNIQUE);
INSERT INTO t1(x,y) SELECT 1,2 WHERE true
@@ -116,13 +116,13 @@ do_execsql_test upsert1-500 {
# Ticket https://sqlite.org/src/tktview/79cad5e4b2e219dd197242e9e5f4
# UPSERT leads to a corrupt index.
#
do_execsql_test upsert1-600 {
do_execsql_test 600 {
DROP TABLE t1;
CREATE TABLE t1(b UNIQUE, a INT PRIMARY KEY) WITHOUT ROWID;
INSERT OR IGNORE INTO t1(a) VALUES('1') ON CONFLICT(a) DO NOTHING;
PRAGMA integrity_check;
} {ok}
do_execsql_test upsert1-610 {
do_execsql_test 610 {
DELETE FROM t1;
INSERT OR IGNORE INTO t1(a) VALUES('1'),(1) ON CONFLICT(a) DO NOTHING;
PRAGMA integrity_check;
@@ -135,7 +135,7 @@ do_execsql_test upsert1-610 {
# the other constraints pass or fail. In other words, the UPSERT constraint
# should be tested first.
#
do_execsql_test upsert1-700 {
do_execsql_test 700 {
DROP TABLE t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c INT, d INT, e INT);
CREATE UNIQUE INDEX t1b ON t1(b);
@@ -145,21 +145,21 @@ do_execsql_test upsert1-700 {
ON CONFLICT(e) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-710 {
do_execsql_test 710 {
DELETE FROM t1;
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
ON CONFLICT(a) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-720 {
do_execsql_test 720 {
DELETE FROM t1;
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
ON CONFLICT(b) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-730 {
do_execsql_test 730 {
DROP TABLE t1;
CREATE TABLE t1(a INT, b INT, c INT, d INT, e INT);
CREATE UNIQUE INDEX t1a ON t1(a);
@@ -170,21 +170,21 @@ do_execsql_test upsert1-730 {
ON CONFLICT(e) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-740 {
do_execsql_test 740 {
DELETE FROM t1;
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
ON CONFLICT(a) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-750 {
do_execsql_test 750 {
DELETE FROM t1;
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
ON CONFLICT(b) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-760 {
do_execsql_test 760 {
DROP TABLE t1;
CREATE TABLE t1(a INT PRIMARY KEY, b INT, c INT, d INT, e INT) WITHOUT ROWID;
CREATE UNIQUE INDEX t1a ON t1(a);
@@ -195,14 +195,14 @@ do_execsql_test upsert1-760 {
ON CONFLICT(e) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-770 {
do_execsql_test 770 {
DELETE FROM t1;
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
ON CONFLICT(a) DO UPDATE SET c=excluded.c;
SELECT * FROM t1;
} {1 2 33 4 5}
do_execsql_test upsert1-780 {
do_execsql_test 780 {
DELETE FROM t1;
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5)
@@ -211,7 +211,7 @@ do_execsql_test upsert1-780 {
} {1 2 33 4 5}
# 2019-08-30 ticket https://sqlite.org/src/info/5a3dba8104421320
do_execsql_test upsert1-800 {
do_execsql_test 800 {
DROP TABLE IF EXISTS t0;
CREATE TABLE t0(c0 REAL UNIQUE, c1);
CREATE UNIQUE INDEX test800i0 ON t0(0 || c1);
@@ -223,19 +223,19 @@ do_execsql_test upsert1-800 {
# 2019-12-06 gramfuzz find
sqlite3 db :memory:
do_execsql_test upsert1-900 {
do_execsql_test 900 {
CREATE VIEW t1(a) AS SELECT 1;
CREATE TRIGGER t1r1 INSTEAD OF INSERT ON t1 BEGIN
SELECT 2;
END;
}
do_catchsql_test upsert1-910 {
do_catchsql_test 910 {
INSERT INTO t1 VALUES(3) ON CONFLICT(x) DO NOTHING;
} {1 {cannot UPSERT a view}}
# 2019-12-26 ticket 7c13db5c3bf74001
reset_db
do_catchsql_test upsert1-1000 {
do_catchsql_test 1000 {
CREATE TABLE t0(c0 PRIMARY KEY, c1, c2 UNIQUE) WITHOUT ROWID;
INSERT OR FAIL INTO t0(c2) VALUES (0), (NULL)
ON CONFLICT(c2) DO UPDATE SET c1 = c0;
@@ -248,7 +248,7 @@ do_catchsql_test upsert1-1000 {
# in a NULL pointer dereference.
#
reset_db
do_execsql_test upsert1-1100 {
do_execsql_test 1100 {
CREATE TABLE t1(a INTEGER PRIMARY KEY ON CONFLICT REPLACE, b UNIQUE);
INSERT INTO t1(b) VALUES(22);
INSERT INTO t1 VALUES(2,22) ON CONFLICT (b) DO NOTHING;
@@ -259,12 +259,12 @@ do_execsql_test upsert1-1100 {
# Bound parameters in the ON CONFLICT clause of an UPSERT.
#
reset_db
do_execsql_test upsert1-1200 {
do_execsql_test 1200 {
CREATE TABLE t1(a INT, b INT);
CREATE UNIQUE INDEX t1x ON t1(b+3);
}
sqlite3_db_config db ENABLE_QPSG 1
do_catchsql_test upsert1-1210 {
do_catchsql_test 1210 {
INSERT INTO t1(a,b) VALUES(1,2) ON CONFLICT(b+?1) DO NOTHING;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}
@@ -273,7 +273,7 @@ do_catchsql_test upsert1-1210 {
# an upsert.
#
reset_db
do_execsql_test upsert1-1300 {
do_execsql_test 1300 {
CREATE TABLE t1(x INT, y TEXT);
INSERT INTO t1 VALUES
(11, printf('%.9000c','a')),
@@ -292,146 +292,4 @@ do_execsql_test upsert1-1300 {
ON CONFLICT (x) DO UPDATE SET y = excluded.y;
} {}
# 2026-07-17 Forum Post 2026-07-17T09:30:42Z
# Combination of ON CONFLICT FAIL on a UNIQUE index and
# an ON CONFLICT DO NOTHING in a different index leads to
# database corruption.
#
reset_db
do_execsql_test upsert1-1400 {
CREATE TABLE t0(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT FAIL,
c INT UNIQUE ON CONFLICT ABORT
);
INSERT INTO t0 VALUES (1, 10, 100),(2, 20, 200);
}
do_catchsql_test upsert1-1401 {
INSERT INTO t0 VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t0.b}}
do_execsql_test upsert1-1402 {
PRAGMA integrity_check;
} {ok}
do_execsql_test upsert1-1403 {
SELECT * FROM t0 ORDER BY a;
} {1 10 100 2 20 200}
do_execsql_test upsert1-1404 {
DROP TABLE t0;
CREATE TABLE t0(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT IGNORE,
c INT UNIQUE ON CONFLICT ABORT
);
INSERT INTO t0 VALUES (1, 10, 100),(2, 20, 200);
}
do_catchsql_test upsert1-1405 {
INSERT INTO t0 VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING;
} {0 {}}
do_execsql_test upsert1-1406 {
PRAGMA integrity_check;
} {ok}
do_execsql_test upsert1-1407 {
SELECT * FROM t0 ORDER BY a;
} {1 10 100 2 20 200}
do_execsql_test upsert1-1408 {
DROP TABLE t0;
CREATE TABLE t0(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT FAIL,
c INT UNIQUE ON CONFLICT ABORT
);
INSERT INTO t0 VALUES (1, 10, 100),(2, 20, 200);
}
do_catchsql_test upsert1-1409 {
INSERT INTO t0 VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t0.b}}
do_execsql_test upsert1-1490 {
PRAGMA integrity_check;
} {ok}
do_execsql_test upsert1-1410 {
SELECT * FROM t0 ORDER BY a;
} {1 10 100 2 20 200}
do_execsql_test upsert1-1411 {
DROP TABLE t0;
CREATE TABLE t1(
a INTEGER PRIMARY KEY,
b UNIQUE ON CONFLICT FAIL,
c UNIQUE
);
INSERT INTO t1 VALUES(1, 1, 1);
}
do_catchsql_test upsert1-1412 {
-- Inserts 0 rows, because hitting the constraint on (b) does ABORT:
INSERT INTO t1 VALUES(3, 3, 3), (2, 1, 2) ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t1.b}}
do_execsql_test upsert1-1413 {
SELECT * FROM t1 ORDER BY a;
} {1 1 1 3 3 3}
do_catchsql_test upsert1-1414 {
-- Inserts 1 row, because hitting the constraint on (b) does FAIL:
DELETE FROM t1 WHERE a=3;
INSERT INTO t1 VALUES(3, 3, 3), (2, 1, 2);
} {1 {UNIQUE constraint failed: t1.b}}
do_execsql_test upsert1-1415 {
SELECT * FROM t1 ORDER BY a;
} {1 1 1 3 3 3}
do_execsql_test upsert1-1416 {
PRAGMA integrity_check;
} ok
# Counter-example to the fix at check-in 2026-07-17T16:26:56.257Z
# provided by Pavan Nambi at forum post 2026-07-18T03:35:48Z
do_execsql_test upsert1-1417 {
DROP TABLE t1;
PRAGMA recursive_triggers=ON;
CREATE TABLE t2(
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
b INT UNIQUE ON CONFLICT FAIL,
c INT UNIQUE ON CONFLICT ABORT
);
CREATE TRIGGER t_ad AFTER DELETE ON t2 BEGIN
INSERT INTO t2 VALUES(99,30,999);
END;
INSERT INTO t2 VALUES(1,10,100),(2,20,200);
SELECT * FROM t2 ORDER BY a;
} {1 10 100 2 20 200}
do_catchsql_test upsert1-1418 {
INSERT INTO t2 VALUES(4,40,400),(1,30,300),(5,50,500)
ON CONFLICT(c) DO NOTHING;
} {1 {UNIQUE constraint failed: t2.b}}
do_execsql_test upsert1-1419 {
PRAGMA integrity_check;
} ok
do_execsql_test upsert1-1420 {
SELECT * FROM t2 ORDER BY a;
} {1 10 100 2 20 200}
# This is a slightly simpler version of the test above (1417-1420). Before
# the bug was fixed, this would:
#
# 1) Checks there are no instances of 'HELLO' in the index on t1(b),
# 2) Deletes the row from t1 as a result of the REPLACE on the PK,
# 3) Fires the trigger, inserting ('HELLO', 200) into index t1(b).
# 4) Finishes the insert without rechecking t1(b), inserting
# ('HELLO', 100). Corruption.
#
reset_db
do_execsql_test upsert-1421 {
PRAGMA recursive_triggers = ON;
CREATE TABLE t1(
a PRIMARY KEY ON CONFLICT REPLACE,
b UNIQUE
);
INSERT INTO t1 VALUES(100, 'abcde');
CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
INSERT INTO t1 VALUES(200, 'HELLO');
END;
}
do_catchsql_test upsert-1422 {
INSERT INTO t1 VALUES(100, 'HELLO');
} {1 {UNIQUE constraint failed: t1.b}}
do_execsql_test upsert-1423 {
PRAGMA integrity_check;
SELECT * FROM t1 ORDER BY +a;
} {ok 100 abcde}
finish_test