]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Do not use the one-pass optimization on an UPDATE if there is a subquery
authordrh <>
Thu, 16 Mar 2023 10:17:30 +0000 (10:17 +0000)
committerdrh <>
Thu, 16 Mar 2023 10:17:30 +0000 (10:17 +0000)
in the WHERE clause, since if the subquery is hidden behind a short-circuit
operator, the subquery might not be evaluated until after one or more rows
have been updated.  Fix for the problem reported by
[forum:/forumpost/0007d1fdb1|forum post 0007d1fdb1].  This is the same
problem that was fixed by [73f0036f045bf371] only for UPDATE instead of
DELETE.

FossilOrigin-Name: 2c56b984a0bd3be5ec326a2109ea7b8f1d4ef63c8fc325caac9663cf2479eaff

manifest
manifest.uuid
src/update.c
test/corruptL.test
test/delete.test
test/update.test

index 100d6872eee6f6f5a1e66f6e0195d75cd357b18b..e55697af41362c270ec3ad5ff0ae72bafd5b9bca 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sa\sNEVER()\sfrom\sbtreeNext()\sthat\sdbsqlfuzz\s460aa158f9a2c41145831cc924296cde1f312b3f\nfound\scould\ssometimes\sbe\sreached.\s\sI\swill\sfind\sa\sway\sto\stest\sthat\sbranch\nlater.
-D 2023-03-16T09:07:46.644
+C Do\snot\suse\sthe\sone-pass\soptimization\son\san\sUPDATE\sif\sthere\sis\sa\ssubquery\nin\sthe\sWHERE\sclause,\ssince\sif\sthe\ssubquery\sis\shidden\sbehind\sa\sshort-circuit\noperator,\sthe\ssubquery\smight\snot\sbe\sevaluated\suntil\safter\sone\sor\smore\srows\nhave\sbeen\supdated.\s\sFix\sfor\sthe\sproblem\sreported\sby\n[forum:/forumpost/0007d1fdb1|forum\spost\s0007d1fdb1].\s\sThis\sis\sthe\ssame\nproblem\sthat\swas\sfixed\sby\s[73f0036f045bf371]\sonly\sfor\sUPDATE\sinstead\sof\nDELETE.
+D 2023-03-16T10:17:30.566
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -690,7 +690,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
 F src/tokenize.c 1305797eab3542a0896b552c6e7669c972c1468e11e92b370533c1f37a37082b
 F src/treeview.c fccf3b8c517c1f55cb380c1522febe6921fcb2bd800c16c78cab571d0eb0ccbd
 F src/trigger.c 6072c531d9bcc3980528150a1b03fda2e85a08c10023fafb42f93ffd68607ffe
-F src/update.c f118e51768d2c1309e3c81e9f91141b22b8a1339cbc5969b1b2d810feaa25b22
+F src/update.c 76664e1beae86e8e961983ebe19a4ee9ebd7e26683ead2b288ba08f81fc7ba4e
 F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
 F src/util.c 3ff7bc2b48dd425b1448304bb86273b05da1621f136d51dbb9789f8803559a1f
@@ -890,7 +890,7 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
 F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
 F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
 F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
-F test/corruptL.test 9d1a0055c8db19baccd12f22ac36a33ec7d63afb59e82eb30835aea8f89b94df
+F test/corruptL.test b42978028afc5eefc8b51d8d7cd6a9344ba7362d7ed4511ee2070f56e06d5a1c
 F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
 F test/corruptN.test 7c099d153a554001b4fb829c799b01f2ea6276cbc32479131e0db0da4efd9cc4
 F test/cost.test b11cdbf9f11ffe8ef99c9881bf390e61fe92baf2182bad1dbe6de59a7295c576
@@ -928,7 +928,7 @@ F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed
 F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
 F test/decimal.test fcf403fd5585f47342234e153c4a4338cd737b8e0884ac66fc484df47dbcf1a7
 F test/default.test 9687cfb16717e4b8238c191697c98be88c0b16e568dd5368cd9284154097ef50
-F test/delete.test f66581a22960dae89b05f14755a576d935dcb94aa3aeacc0005b29bdbaa9949c
+F test/delete.test 2686e1c98d552ef37d79ad55b17b93fe96fad9737786917ce3839767f734c48f
 F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
 F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
 F test/delete4.test 51fafebe9503a40796d1aae1565c60524cada720e50eecac01b7fd0419d9ea0b
@@ -1774,7 +1774,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
 F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
 F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
 F test/unordered.test 0edaf3411d300693bca595897c5201421c6c5ec787990a1dfe2f7f60ae93f1e2
-F test/update.test eb7f4eb172ce270e51bb67d7867521f33a63635bb671e261bbafccaef3bd6db2
+F test/update.test 90772ede84cfc779fc3d31884a84ec4c74deb501eeb09a1c6c91c03d8e94c0d8
 F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
 F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041
 F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1
@@ -2050,8 +2050,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 73f0036f045bf37193b6e87ae45b578c5831614c530488257c69666178da3aa5
-R 416ca2e38e88837ddad74173b91b3e6d
+P 1dffeffe150fff6777cf26bc960326ca4e4190d25d05bb066b082d1e1c8eb374
+R 5410b321a0481083a3d313d81510e3fc
 U drh
-Z 476a952efa83c3a1b612460afea7cd08
+Z eea9af84fd6b98bd366cd12ed13a97d2
 # Remove this line to create a well-formed Fossil manifest.
index 7a6660030afecd06eeda2672e6b04fe7c3f2929f..7742930f8ee20b2faacaab79e18a5c7f0dd23dc2 100644 (file)
@@ -1 +1 @@
-1dffeffe150fff6777cf26bc960326ca4e4190d25d05bb066b082d1e1c8eb374
\ No newline at end of file
+2c56b984a0bd3be5ec326a2109ea7b8f1d4ef63c8fc325caac9663cf2479eaff
\ No newline at end of file
index a4e57d1d4228c11783351ec06392424502193762..bd1ddb1a309ce1286c56626b407a577924c35650 100644 (file)
@@ -727,12 +727,22 @@ void sqlite3Update(
       /* Begin the database scan. 
       **
       ** Do not consider a single-pass strategy for a multi-row update if
-      ** there are any triggers or foreign keys to process, or rows may
-      ** be deleted as a result of REPLACE conflict handling. Any of these
-      ** things might disturb a cursor being used to scan through the table
-      ** or index, causing a single-pass approach to malfunction.  */
+      ** there is anything that might disrupt the cursor being used to do
+      ** the UPDATE:
+      **   (1) This is a nested UPDATE
+      **   (2) There are triggers
+      **   (3) There are FOREIGN KEY constraints
+      **   (4) There are REPLACE conflict handlers
+      **   (5) There are subqueries in the WHERE clause
+      */
       flags = WHERE_ONEPASS_DESIRED;
-      if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
+      if( !pParse->nested
+       && !pTrigger
+       && !hasFK
+       && !chngKey
+       && !bReplace
+       && (sNC.ncFlags & NC_Subquery)==0
+      ){
         flags |= WHERE_ONEPASS_MULTIROW;
       }
       pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
index 3a841a8199126d434d8ffb50ff2df14ce0ce8556..65d9821b351addf36d05cd8098f64bd686abba88 100644 (file)
@@ -1269,11 +1269,14 @@ do_test 15.0 {
 }]} {}
 
 extra_schema_checks 0
-do_execsql_test 15.1 {
+do_catchsql_test 15.1 {
   PRAGMA cell_size_check = 0;
   UPDATE c1 SET c= NOT EXISTS(SELECT 1 FROM c1 ORDER BY (SELECT 1 FROM c1 ORDER BY a)) +10 WHERE d BETWEEN 4 AND 7;
-} {}
+} {1 {database disk image is malformed}}
 extra_schema_checks 1
+do_execsql_test 15.2 {
+  PRAGMA integrity_check;
+} {/in database main/}
 
 #-------------------------------------------------------------------------
 reset_db
index cdf6798ea6da89440ed1bdae346a800ea689054f..214bae6f703937266e682816264ce310fb30799d 100644 (file)
@@ -426,6 +426,9 @@ do_execsql_test delete-11.1 {
 # run after one or more rows have been deleted, which can change
 # the result of the subquery, and result in the wrong answer.
 #
+# Similar problem for UPDATE tested by update-21.4
+# https://sqlite.org/forum/forumpost/0007d1fdb1
+#
 reset_db
 do_execsql_test delete-12.0 {
   CREATE TABLE t0(vkey INTEGER, pkey INTEGER,c1 INTEGER);
index 66efd10ec8d1fb45183133494ad4f3d3acc2f0a0..47b6029bee2733349fae5a811ab5dd549eb8c428 100644 (file)
@@ -732,4 +732,37 @@ do_execsql_test update-20.30 {
   PRAGMA integrity_check;
 } {ok}
 
+# 2023-03-16 https://sqlite.org/forum/forumpost/0007d1fdb1
+# A subquery in the WHERE clause of an UPDATE and behind a
+# short-circuit evaluation caused problems because multi-row
+# single-pass was selected.
+#
+# Similar problem for DELETE tested by delete-12.0.
+# https://sqlite.org/src/info/73f0036f045bf371
+#
+reset_db
+do_execsql_test update-21.1 {
+  CREATE TABLE t1 (vkey INTEGER, c5 INTEGER);
+  INSERT INTO t1 VALUES(3,NULL),(6,-54);
+}
+db null NULL
+do_execsql_test update-21.2 {
+  BEGIN;
+  UPDATE t1 SET vkey = 100 WHERE c5 is null;
+  SELECT * FROM t1 ORDER BY vkey, c5;
+  ROLLBACK;
+} {6 -54 100 NULL}
+do_execsql_test update-21.3 {
+  BEGIN;
+  UPDATE t1 SET vkey = 100 WHERE NOT (-10*(select min(vkey) from t1) >= c5);
+  SELECT * FROM t1 ORDER BY vkey, c5;
+  ROLLBACK;
+} {3 NULL 6 -54}
+do_execsql_test update-21.4 {
+  BEGIN;
+  UPDATE t1 SET vkey = 100 WHERE c5 is null OR NOT (-10*(select min(vkey) from t1) >= c5);
+  SELECT * FROM t1 ORDER BY vkey, c5;
+  ROLLBACK;
+} {6 -54 100 NULL}
+
 finish_test