From: drh <> Date: Mon, 11 May 2026 16:58:05 +0000 (+0000) Subject: Fix the xfer-optimization such that if the destination table has X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=e14c16189ef6ae3cf9e43c3cfc99456809decaf5;p=thirdparty%2Fsqlite.git Fix the xfer-optimization such that if the destination table has constraints on the hidden rowid, the optimization is not attempted. [forum:/forumpost/6dcc95e3ca|Forum post 6dcc95e3ca]. FossilOrigin-Name: da9ca357fb24f39a4a3292ca447773c6233a3084721abfbd5665a45ee8a4bed4 --- diff --git a/manifest b/manifest index 9e7ba56db3..3cc216a3a6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Prevent\sinternal-use-only\sSQL\sfunctions\sfrom\sbeing\sused\sinside\sof\sa\sCHECK\nconstraint\sadded\susing\sALTER\sTABLE\sADD\sCONSTRAINT.\n[forum:/forumpost/6256ee34ed|Forum\spost\s6256ee34ed]. -D 2026-05-11T14:22:45.851 +C Fix\sthe\sxfer-optimization\ssuch\sthat\sif\sthe\sdestination\stable\shas\nconstraints\son\sthe\shidden\srowid,\sthe\soptimization\sis\snot\sattempted.\n[forum:/forumpost/6dcc95e3ca|Forum\spost\s6dcc95e3ca]. +D 2026-05-11T16:58:05.251 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -696,7 +696,7 @@ F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 2b84fbcb063c29648f15f3704f902e404a0be7580c8d9559a9d369f03d6b6598 +F src/insert.c 66cb27a8cb3509ca4fa9204d8beba31baaf23a40dca2e23156393bce09655417 F src/json.c ed93368fab7943a4822bc179fd914e63f5a2a18d6ef429c16ac49ea13eaffd49 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 78d5b06f18996ffa1203129b28fea043f63a87a4117539678f1d761c30b4ff65 @@ -1313,7 +1313,7 @@ F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 97cfb30b83ca1622b9422a1e4c4831b4cb767cf5d654660945036d1e72067e70 F test/insert2.test 4d14b8f1b810a41995f6286b64a6943215d52208 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 -F test/insert4.test 2bf81535a990c969665d66db51fcf76c23499b39893b5109f413d1de4ad34cd3 +F test/insert4.test c57951c5db531509b3ad55a65c642b6250d51fa4f92bc67613ef900a32e9c3bd F test/insert5.test 79f6b6efd0d3db5f4e3ff442300b7d9e7185adb345b29aacc3ea5a9c58ab9beb F test/insertfault.test ac63d14ea3b49c573673a572f4014b9117383a03e497c58f308b5c776e4a7f74 F test/instr.test 67ba309e9697c24a304e98a7c8f372456177dd4e32237d2a305e1e05f7bb79c2 @@ -2204,9 +2204,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 87b653731171a26396f9796b0a5c436593571d39e991d8d040ef4473cf459b67 7a85921ae585f948f084bd8fccc1cc002539415e629aa0021d58afc17e5471a3 -R 2a707e2c4c5fac58a7ce25fe390d4d94 -T +closed 7a85921ae585f948f084bd8fccc1cc002539415e629aa0021d58afc17e5471a3 +P 07beb966daddd0dfea36265eb38ebfcfbb10b0cbccda458dea501eda330a49f0 +R 1955398b2f2da5d960daeec18f38ded2 U drh -Z 188e9734e7f0fed6075a207e631c04b9 +Z 071b161c34e74b182ba62199af464639 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c94bd2c33e..7dae3384df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -07beb966daddd0dfea36265eb38ebfcfbb10b0cbccda458dea501eda330a49f0 +da9ca357fb24f39a4a3292ca447773c6233a3084721abfbd5665a45ee8a4bed4 diff --git a/src/insert.c b/src/insert.c index 5656b0d7ef..f9af6ea243 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2987,6 +2987,44 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ return 1; } +/* +** Examine an expression node and abort if it references the ROWID. +** This is a Walker callback used by xferCompatibleCheck() +*/ +static int xferCheckRowid(Walker *pWalk, Expr *pExpr){ + if( pExpr->op==TK_COLUMN && pExpr->iColumn<0 ){ + pWalk->eCode = 1; + return WRC_Abort; + }else{ + return WRC_Continue; + } +} + +/* +** Analyze CHECK constraints on the source and destination tables and +** return true if those CHECK constraints are compatible with the +** xfer-optimization. +** +** * The pDest and pSrc tables must have identical CHECK constraints. +** +** * If the destination table, pDest, does not have an +** INTEGER PRIMARY KEY column, then no CHECK constraint may +** referenced the ROWID. (See forum post 2026-05-11T13:15:57Z) +*/ +static int xferCompatibleCheck(Table *pDest, Table *pSrc){ + if( sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ + return 0; + } + if( pDest->iPKey<0 ){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = xferCheckRowid; + sqlite3WalkExprList(&w,pDest->pCheck); + if( w.eCode ) return 0; + } + return 1; +} + /* ** Attempt the transfer optimization on INSERTs of the form ** @@ -3219,7 +3257,7 @@ static int xferOptimization( #ifndef SQLITE_OMIT_CHECK if( pDest->pCheck && (db->mDbFlags & DBFLAG_Vacuum)==0 - && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) + && !xferCompatibleCheck(pDest,pSrc) ){ return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } diff --git a/test/insert4.test b/test/insert4.test index 8bd65a006f..d5aab56c83 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -625,4 +625,45 @@ do_execsql_test 11.0 { PRAGMA integrity_check; } {1 1 1 2 2 2 3 3 3 ok} +#------------------------------------------------------------------------- +# forum post 2026-05-11T13:15:57Z +# +do_execsql_test 12.0 { + CREATE TABLE src(x,y,z, CONSTRAINT c1 CHECK(rowid<=5)); + CREATE TABLE dest(x,y,z, CONSTRAINT c2 CHECK(rowid<=5)); + INSERT INTO src(x) VALUES(22),(33),(44); + UPDATE src SET y=x+100, z=x*100; + INSERT INTO dest(x) VALUES(55),(66),(77); + UPDATE dest SET y=x+100, z=x*100; + PRAGMA integrity_check; +} ok +set sqlite3_xferopt_count 0 +do_catchsql_test 12.1 { + INSERT INTO dest SELECT * FROM src; +} {1 {CHECK constraint failed: c2}} +do_test 12.2 { + set sqlite3_xferopt_count +} 0 +do_execsql_test 12.3 { + SELECT rowid, x FROM dest; + PRAGMA integrity_check; +} {1 55 2 66 3 77 ok} +do_execsql_test 12.4 { + ALTER TABLE src DROP CONSTRAINT c1; + ALTER TABLE dest DROP CONSTRAINT c2; +} +set sqlite3_xferopt_count 0 +do_catchsql_test 12.5 { + INSERT INTO dest SELECT * FROM src; +} {0 {}} +do_test 12.6 { + set sqlite3_xferopt_count +} 1 +do_execsql_test 12.7 { + SELECT rowid, x FROM dest; + PRAGMA integrity_check; +} {1 55 2 66 3 77 4 22 5 33 6 44 ok} + + + finish_test