]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
In the MULTI-INDEX OR query plan, code for sub-expressions can sometimes be
authordrh <>
Tue, 18 May 2021 19:10:10 +0000 (19:10 +0000)
committerdrh <>
Tue, 18 May 2021 19:10:10 +0000 (19:10 +0000)
generated twice.  But for some subqueries, generating code off of the same
tree twice causes problems.  So now MULTI-INDEX OR makes a copy of the
sub-expressions it uses to avoid code-generating them more than once.
dbsqlfuzz 9ebd2140e7206ff724e665f172faea28af801635.

FossilOrigin-Name: 4a55f72542c8bcc80253aa77043314cecb29d73cb4f51aa80f7811e86cc8ef68

manifest
manifest.uuid
src/select.c
src/vdbe.c
src/wherecode.c
test/fuzzdata8.db
test/where9.test

index 8977013c7fd351bd40c5334be913574f0ec59c2c..cce7561db1abf1ecdbd6335d795d3c4a7bb040fe 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improved\scomments\son\sthe\sgenerated\sopcodes.h\sfile.
-D 2021-05-18T12:36:35.719
+C In\sthe\sMULTI-INDEX\sOR\squery\splan,\scode\sfor\ssub-expressions\scan\ssometimes\sbe\ngenerated\stwice.\s\sBut\sfor\ssome\ssubqueries,\sgenerating\scode\soff\sof\sthe\ssame\ntree\stwice\scauses\sproblems.\s\sSo\snow\sMULTI-INDEX\sOR\smakes\sa\scopy\sof\sthe\nsub-expressions\sit\suses\sto\savoid\scode-generating\sthem\smore\sthan\sonce.\ndbsqlfuzz\s9ebd2140e7206ff724e665f172faea28af801635.
+D 2021-05-18T19:10:10.627
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -543,7 +543,7 @@ F src/printf.c 78fabb49b9ac9a12dd1c89d744abdc9b67fd3205e62967e158f78b965a29ec4b
 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c 40e216d9a72e52841a9c8e0aec7d367bade8e2df17b804653b539b20c1ab5660
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
-F src/select.c 0ba381ae7f9f4f84bed7d3a357703fd08b587fef6477f78953d8bcfe4e42328f
+F src/select.c acf228163efe1f3f9137e47bc9b6ab9844846bb92a707f320d05b911f1b9ea4a
 F src/shell.c.in 1b32ba2918ede13b68df47c7b92b72ba0d06e68d384e78bb9d7456527271d400
 F src/sqlite.h.in 5c950066775ca9efdaa49077c05d38d0bef6418f3bd07d2dce0210f1d2f3c326
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
@@ -615,7 +615,7 @@ F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
-F src/vdbe.c 50d998ebf8fe6dcefa91348356aa3dbaf0bae641b074c9f6e8503960eab81324
+F src/vdbe.c 74491791630743ef5215a90e6ec94c0965577b9b7086b2180d2c7fa0954317a8
 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
 F src/vdbeInt.h 58980223a32495ad059d10581b83e133abdc77248b1bab85c080cab8a13bd819
 F src/vdbeapi.c d9e99daf59fec928986838b3389a7337e82fec6b3b5de30206cb99fb4661b94e
@@ -632,7 +632,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
 F src/walker.c 7342becedf3f8a26f9817f08436bdf8b56ad69af83705f6b9320a0ad3092c2ac
 F src/where.c 32f41c3c93c6785e0077e3a2cdc669c3ccfe70173787847be77f294c18fc7dc3
 F src/whereInt.h 9248161dd004f625ce5d3841ca9b99fed3fc8d61522cf76340fc5217dbe1375b
-F src/wherecode.c b4c21439f0549bb5c571214e08ddb5ec58d5e972f4b4c87c0cc79351edd43704
+F src/wherecode.c 110ed13049e0f1dc27e9dd942eb870417b36480cb7819302f5804cbcf9330b0e
 F src/whereexpr.c 5a9c9f5d2dac4bcdcaae3035034b4667523f731df228e0bb1d4efc669efa9da5
 F src/window.c 0c910a222f357e3e175a998874abd12f3e2f312e10950d304f3d28b0fb6bc509
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1055,7 +1055,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
 F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
 F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
 F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
-F test/fuzzdata8.db b8dd9fc73f09b2098d942fa225f99aa3bb5999d07917c75e29bb121c0012b444
+F test/fuzzdata8.db 5e616432bbdd9b27014463545cae06797790645021fbc650d28c994b4f02a6f5
 F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
 F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
 F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
@@ -1749,7 +1749,7 @@ F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
 F test/where7.test ab41d53ce8f2a6919ea3d5b13cd1153c1375a8e3ddaa129b81781f9033981383
 F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f
-F test/where9.test b1942ed1d4c4632ea99e135691371f33803428ee4092a462280338ab3347f916
+F test/where9.test 1ffb75edc50a8faa6e7bd77f8221d783febb00b44b0bdb32fb48cec6e38eca95
 F test/whereA.test 9d1077b117f1b68d5f739d94f36956c36cf995eb87bb19b77b2e81af020edd20
 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
 F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
@@ -1913,7 +1913,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 304739d2382446e7b698d67377679168e46f0a19bb0794fdf22d0a0a84a8cbcc
-R 488974183caf351481b145abe81d4cf1
+P f2a17f1fad08779486e4d50d0d9277c7f87a9558a53af1a68aa5fe2ec30e820e
+R d1ee727748d372a9a4a6be0c1bffc86c
 U drh
-Z 66f78faa347185fdfe747ad66ceffb44
+Z 41c8ad722578c7f47efc179345a7656e
index 0dac44b6c6ceb38b60cf28155f7b602c4f8769e3..f8eef81ae50accde9fa51f98976e1cce1d645911 100644 (file)
@@ -1 +1 @@
-f2a17f1fad08779486e4d50d0d9277c7f87a9558a53af1a68aa5fe2ec30e820e
\ No newline at end of file
+4a55f72542c8bcc80253aa77043314cecb29d73cb4f51aa80f7811e86cc8ef68
\ No newline at end of file
index e18333e7b8dfef5d18824086a9b51731cbc7e246..c73bad36efef9b4b8838f542a3ce2ee515d31ccb 100644 (file)
@@ -2748,6 +2748,7 @@ static int multiSelect(
         pPrior->iLimit = p->iLimit;
         pPrior->iOffset = p->iOffset;
         pPrior->pLimit = p->pLimit;
+        SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL left...\n"));
         rc = sqlite3Select(pParse, pPrior, &dest);
         pPrior->pLimit = 0;
         if( rc ){
@@ -2765,6 +2766,7 @@ static int multiSelect(
           }
         }
         ExplainQueryPlan((pParse, 1, "UNION ALL"));
+        SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL right...\n"));
         rc = sqlite3Select(pParse, p, &dest);
         testcase( rc!=SQLITE_OK );
         pDelete = p->pPrior;
@@ -2817,6 +2819,7 @@ static int multiSelect(
         */
         assert( !pPrior->pOrderBy );
         sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
+        SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION left...\n"));
         rc = sqlite3Select(pParse, pPrior, &uniondest);
         if( rc ){
           goto multi_select_end;
@@ -2836,6 +2839,7 @@ static int multiSelect(
         uniondest.eDest = op;
         ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
                           sqlite3SelectOpName(p->op)));
+        SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION right...\n"));
         rc = sqlite3Select(pParse, p, &uniondest);
         testcase( rc!=SQLITE_OK );
         assert( p->pOrderBy==0 );
@@ -2896,6 +2900,7 @@ static int multiSelect(
         /* Code the SELECTs to our left into temporary table "tab1".
         */
         sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
+        SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT left...\n"));
         rc = sqlite3Select(pParse, pPrior, &intersectdest);
         if( rc ){
           goto multi_select_end;
@@ -2912,6 +2917,7 @@ static int multiSelect(
         intersectdest.iSDParm = tab2;
         ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
                           sqlite3SelectOpName(p->op)));
+        SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT right...\n"));
         rc = sqlite3Select(pParse, p, &intersectdest);
         testcase( rc!=SQLITE_OK );
         pDelete = p->pPrior;
index 1d255d3ee896d4e4ca27424bf71711ee5a0bc662..54588b2a10e2a97c1f02fccf456893cd64b9ec67 100644 (file)
@@ -592,7 +592,7 @@ static void registerTrace(int iReg, Mem *p){
   printf("\n");
   sqlite3VdbeCheckMemInvariants(p);
 }
-void sqlite3PrintMem(Mem *pMem){
+/**/ void sqlite3PrintMem(Mem *pMem){
   memTracePrint(pMem);
   printf("\n");
   fflush(stdout);
index 507148d314c0199de8dc1d06d070e19ddbeb2f0e..4d0ba880d1db6306a55bf679ef29fdd0a12c5215 100644 (file)
@@ -2170,7 +2170,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
         /* The extra 0x10000 bit on the opcode is masked off and does not
         ** become part of the new Expr.op.  However, it does make the
         ** op==TK_AND comparison inside of sqlite3PExpr() false, and this
-        ** prevents sqlite3PExpr() from implementing AND short-circuit 
+        ** prevents sqlite3PExpr() from applying the AND short-circuit 
         ** optimization, which we do not want here. */
         pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr);
       }
@@ -2186,10 +2186,16 @@ Bitmask sqlite3WhereCodeOneLoopStart(
       if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
         WhereInfo *pSubWInfo;           /* Info for single OR-term scan */
         Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
+        Expr *pDelete;                  /* Local copy of OR clause term */
         int jmp1 = 0;                   /* Address of jump operation */
         testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
                && !ExprHasProperty(pOrExpr, EP_FromJoin)
         ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
+        pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0);
+        if( db->mallocFailed ){
+          sqlite3ExprDelete(db, pDelete);
+          continue;
+        }
         if( pAndExpr ){
           pAndExpr->pLeft = pOrExpr;
           pOrExpr = pAndExpr;
@@ -2304,6 +2310,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
           sqlite3WhereEnd(pSubWInfo);
           ExplainQueryPlanPop(pParse);
         }
+        sqlite3ExprDelete(db, pDelete);
       }
     }
     ExplainQueryPlanPop(pParse);
index b39887db1ebd835f36e05ebc25dac8e3e43e783d..a5521775916979cff9b93273d0dd0cd3b0087d1b 100644 (file)
Binary files a/test/fuzzdata8.db and b/test/fuzzdata8.db differ
index cb52b2b37da27d438ad369eea863e48184a5e81c..429708f1fe8350080ef02f0da3da43065825ff09 100644 (file)
@@ -982,6 +982,23 @@ do_test where9-10.2 {
   }
 } {1 {} 1}
 
-
+# dbsqlfuzz 9df1d53c24c4c96af0dae15ee764897af415ac76
+# The MULTI-INDEX OR processing evaluates the same WHERE-clause sub-expression
+# twice.  But if that sub-expression contains a UNION ALL SELECT statement
+# subject to query flattening, the sub-expression might be transformed in a
+# way that it can only be code-generated once.  An assert() will fail on
+# the second attempt to generate code from the same sub-expression.
+# The solution is to make a copy of sub-expressions used by MULTI-INDEX OR
+#
+reset_db
+do_execsql_test where9-11.1 {
+  CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
+  CREATE TABLE t2_a(k INTEGER PRIMARY KEY, v TEXT);
+  CREATE TABLE t2_b(k INTEGER PRIMARY KEY, v TEXT);
+  CREATE VIEW t2 AS SELECT * FROM t2_a UNION ALL SELECT * FROM t2_b;
+  SELECT 1 FROM t1 JOIN t1 USING(a)
+   WHERE (a=1)
+      OR (a=2 AND (SELECT 4 FROM t2,(SELECT 5 FROM t1 ORDER BY a) WHERE a));
+} {}
 
 finish_test