]> 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:21:52 +0000 (10:21 +0000)
committerdrh <>
Thu, 16 Mar 2023 10:21:52 +0000 (10:21 +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.

FossilOrigin-Name: b5d8a9a6a58b4eb81a663192f578e0fbed72e8155bc7e1100ece04e8394a1984

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

index 46ed0ca09e413a56952fdc8d06e9ad041ea5a2b9..72ccc21ca8adf7288b2b12419330288260388cf1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sa\sNEVER()\sfrom\sbtreeNext().
-D 2023-03-16T09:16:31.055
+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.
+D 2023-03-16T10:21:52.307
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -686,7 +686,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
@@ -886,7 +886,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
@@ -924,7 +924,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
@@ -1769,7 +1769,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
@@ -2045,9 +2045,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 048711e49002e59cbaf51079403a3f37abaa7d3a04e0cb20de4aed2d56c0e837
-Q +1dffeffe150fff6777cf26bc960326ca4e4190d25d05bb066b082d1e1c8eb374
-R 514cfcdaded26951aac4ab75c255adfe
+P 40623f5ab07481179f1efd5d377555c8d78bf0706a16212c0f6b954c17736a5c
+Q +2c56b984a0bd3be5ec326a2109ea7b8f1d4ef63c8fc325caac9663cf2479eaff
+R 6de8235dc7b56e5ae85b9cbade33385b
 U drh
-Z f3663ffc26ca62852f1067ce8c9f730a
+Z e4d27df9efe5c6e71838a2507dbb8d7d
 # Remove this line to create a well-formed Fossil manifest.
index ce5d07c31ea2199ce6743e4a882a376cf2b71feb..0cfe1faf07d950d5959c58adda377891730a8c16 100644 (file)
@@ -1 +1 @@
-40623f5ab07481179f1efd5d377555c8d78bf0706a16212c0f6b954c17736a5c
\ No newline at end of file
+b5d8a9a6a58b4eb81a663192f578e0fbed72e8155bc7e1100ece04e8394a1984
\ 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