From: dan Date: Fri, 17 Jul 2026 16:26:56 +0000 (+0000) Subject: Ensure that a write with REPLACE conflict resolution on an integer primary key column... X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=88b4e34fa994c4784e5472d40ba683300478a64e;p=thirdparty%2Fsqlite.git Ensure that a write with REPLACE conflict resolution on an integer primary key column is handled after any IGNORE or FAIL conflicts, even if there is also an explicit "ON CONFLICT" clause unrelated to the IPK. Forum post [forum:/info/2026-07-17T09:30:42Z | 2026-07-17T09:30:42Z]. FossilOrigin-Name: 1875249ab30fb110bc09963b592c8f48d2fb57066d770ad7e1da7e8bc8602977 --- diff --git a/manifest b/manifest index b3a06aaa88..eb751f2c8f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_SHELL_EDITION\scompile-time\soption,\swhich\sif\sset\sto\sa\ndate\snumber\sof\sthe\sform\sYYYYMMDD\swill\stry\sto\sconfigure\sthe\sdefaults\nto\sbe\ssimilar\sto\sthe\slatest\srelease\sat\sor\sprior\sto\sthat\sdate. -D 2026-07-16T23:55:15.551 +C Ensure\sthat\sa\swrite\swith\sREPLACE\sconflict\sresolution\son\san\sinteger\sprimary\skey\scolumn\sis\shandled\safter\sany\sIGNORE\sor\sFAIL\sconflicts,\seven\sif\sthere\sis\salso\san\sexplicit\s"ON\sCONFLICT"\sclause\sunrelated\sto\sthe\sIPK.\sForum\spost\s[forum:/info/2026-07-17T09:30:42Z\s|\s2026-07-17T09:30:42Z]. +D 2026-07-17T16:26:56.257 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -702,7 +702,7 @@ F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf F src/hwtime.h 5cb15147c8583d0fc4748e1c12ea6f38c9deaeefa147a4d8d379fd9bc81fee9a F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c e6e9b574b4863649e2c433f2260f226183e697df1ab73fcb8da9a85d5abcd390 +F src/insert.c 71776cca5bf05b05b1427fa1dc1b0d391e7f3805abaf9b6f3c24ec7350040838 F src/json.c e4af4d799e4e7630c633b3b356d65e92d1781e42343ab77b8ef747c932762012 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 5cd4cd7ec6e1a46416806899086363fbf95eecd3bfb9a388b436c9a77243c902 @@ -1947,7 +1947,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 77e3cbabd6b5c773056aca39bda7a690901f1dbd08b0a26ee3b5aec9e9e26198 +F test/upsert1.test cfaa6eab3c0d3e8512664a92570348482c61e71b02e0ec75837e4fb37fe4e430 F test/upsert2.test 720e94d09f7362a282bc69b3c6b83d51daeaaf0440eb4920a08b86518b8c7496 F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5 @@ -2215,8 +2215,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9062c79fc273d9e59090ea475e7d2abaf33c7cfe9948cbfb92b979a6ed31a37f -R 962f8f7981b575eb8d2ef8e19f91d63a -U drh -Z 10ca7fd768bd6c7b1db171f45c9c110e +P 6924895d2cbc50971d8da1810423ad15c638dabc31b4f1083dd6076e20492ef4 +R 506e7819684ce1917475a4b1d4a399da +T *branch * do-nothing-replace-bug +T *sym-do-nothing-replace-bug * +T -sym-trunk * +U dan +Z 975ed7664c025722600a0d0d2b0ab4aa # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..d04b2e9f24 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch do-nothing-replace-bug +tag do-nothing-replace-bug diff --git a/manifest.uuid b/manifest.uuid index 83d1ffb12a..ec96f9a1e4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6924895d2cbc50971d8da1810423ad15c638dabc31b4f1083dd6076e20492ef4 +1875249ab30fb110bc09963b592c8f48d2fb57066d770ad7e1da7e8bc8602977 diff --git a/src/insert.c b/src/insert.c index 61aabc6617..15a9a5fe89 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2281,9 +2281,13 @@ void sqlite3GenerateConstraintChecks( if( onError==OE_Replace /* IPK rule is REPLACE */ && onError!=overrideError /* Rules for other constraints are different */ && pTab->pIndex /* There exist other constraints */ - && !upsertIpkDelay /* IPK check already deferred by UPSERT */ ){ - ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; + if( upsertIpkDelay ){ + ipkTop = upsertIpkDelay + 1; + upsertIpkDelay = 0; + }else{ + ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; + } VdbeComment((v, "defer IPK REPLACE until last")); } @@ -2377,11 +2381,11 @@ void sqlite3GenerateConstraintChecks( } } sqlite3VdbeResolveLabel(v, addrRowidOk); - if( pUpsert && pUpsertClause!=pUpsert ){ - upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto); - }else if( ipkTop ){ + if( ipkTop ){ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, ipkTop-1); + }else if( pUpsert && pUpsertClause!=pUpsert ){ + upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto); } } diff --git a/test/upsert1.test b/test/upsert1.test index 49168f840b..aecf1c8530 100644 --- a/test/upsert1.test +++ b/test/upsert1.test @@ -292,4 +292,67 @@ 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 t( + a INTEGER PRIMARY KEY ON CONFLICT REPLACE, + b INT UNIQUE ON CONFLICT FAIL, + c INT UNIQUE + ); + INSERT INTO t VALUES (1, 10, 100),(2, 20, 200); +} +do_catchsql_test upsert1-1410 { + INSERT INTO t VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING; +} {1 {UNIQUE constraint failed: t.b}} +do_execsql_test upsert1-1420 { + PRAGMA integrity_check; +} {ok} +do_execsql_test upsert1-1430 { + SELECT * FROM t ORDER BY a; +} {1 10 100 2 20 200} + +do_execsql_test upsert1-1440 { + DROP TABLE t; + CREATE TABLE t( + a INTEGER PRIMARY KEY ON CONFLICT REPLACE, + b INT UNIQUE ON CONFLICT IGNORE, + c INT UNIQUE + ); + INSERT INTO t VALUES (1, 10, 100),(2, 20, 200); +} +do_catchsql_test upsert1-1450 { + INSERT INTO t VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING; +} {0 {}} +do_execsql_test upsert1-1420 { + PRAGMA integrity_check; +} {ok} +do_execsql_test upsert1-1460 { + SELECT * FROM t ORDER BY a; +} {1 10 100 2 20 200} + +do_execsql_test upsert1-1470 { + DROP TABLE t; + CREATE TABLE t( + a INTEGER PRIMARY KEY ON CONFLICT REPLACE, + b INT UNIQUE ON CONFLICT FAIL, + c INT UNIQUE + ); + INSERT INTO t VALUES (1, 10, 100),(2, 20, 200); +} +do_catchsql_test upsert1-1480 { + INSERT INTO t VALUES (1, 20, 300) ON CONFLICT(c) DO NOTHING; +} {1 {UNIQUE constraint failed: t.b}} +do_execsql_test upsert1-1490 { + PRAGMA integrity_check; +} {ok} +do_execsql_test upsert1-1500 { + SELECT * FROM t ORDER BY a; +} {1 10 100 2 20 200} + finish_test +