]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Correct handling of OUTER JOIN when on or the other operand is a subquery
authordrh <>
Thu, 18 Apr 2024 16:11:01 +0000 (16:11 +0000)
committerdrh <>
Thu, 18 Apr 2024 16:11:01 +0000 (16:11 +0000)
implemented using the VALUES-as-coroutine optimization.
dbsqlfuzz bde3bf80aedf25afa56e2997a0545a314765d3f8.

FossilOrigin-Name: 8c0f69e0e4ae0a446838cc193bfd4395fd251f3c7659b35ac388e5a0a7650a66

manifest
manifest.uuid
src/vdbe.c
src/where.c
src/wherecode.c
test/values.test

index 51a37eef64d876bb666c03b1e3b363ff8a5ba337..98a7d3badaadcb84eac479efcabe5e37e5a69599 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sfirst\sassert()\sadded\sin\s[0ebc65481f4a3e79]\sis\snot\snecessarily\strue\sin\sa\ncorrupt\sdatabase\sfile.\s\sSo\sadd\sa\sterm\sto\smake\sit\strue.
-D 2024-04-15T20:43:21.644
+C Correct\shandling\sof\sOUTER\sJOIN\swhen\son\sor\sthe\sother\soperand\sis\sa\ssubquery\nimplemented\susing\sthe\sVALUES-as-coroutine\soptimization.\ndbsqlfuzz\sbde3bf80aedf25afa56e2997a0545a314765d3f8.
+D 2024-04-18T16:11:01.833
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -820,7 +820,7 @@ F src/upsert.c 2e60567a0e9e8520c18671b30712a88dc73534474304af94f32bb5f3ef65ac65
 F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
 F src/util.c 4d6d7ebfe6772a1b950c97bbb1d1a72ad4874617ec498ab8aa73b7f5a43e44bb
 F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
-F src/vdbe.c 651aa0f31027d5d0a133eb7b41d11c41dc3b88ecb760b770430da0e477ae3b6c
+F src/vdbe.c 298e8bf31adbcad0d8dfa37e106372e0d59ce531f2cca5b8ce559f9e173085f2
 F src/vdbe.h c2d78d15112c3fc5ab87f5e8e0b75d2db1c624409de2e858c3d1aafb1650bb4f
 F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
 F src/vdbeapi.c 80235ac380e9467fec1cb0883354d841f2a771976e766995f7e0c77f845406df
@@ -835,9 +835,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
-F src/where.c 09253e913dc1a93aa6e0e1a5d25a392b8fa39096cc30d230dd302264b3be0661
+F src/where.c 40ee94edd4cf31e6dc3e4c9ac814777b8cf4dc8ee985d87eb5f77bd4c42e69da
 F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
-F src/wherecode.c e033875570f5d65b99fdb5189e597d91c8bc34f4196089fd50e6086d174035e7
+F src/wherecode.c 4b5909be0c36030eec18ea0e7a64c60254180a21e626c9d2e0e9be3007ad47c1
 F src/whereexpr.c 7b64295f1d82ad0928df435925dd7bbd5997b44a026153113eace0d9e71ff435
 F src/window.c 5d95122dd330bfaebd732358c8ef067c5a9394a53ac249470d611d0ce2c52be2
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1924,7 +1924,7 @@ F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7
 F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c
 F test/vacuum6.test b137b04bf3392d3f5c3b8fda0ce85a6775a70ca112f6559f74ff52dc9ce042fd
 F test/vacuummem.test 4b30f5b95a9ff86e9d5c20741e50a898b2dc10b0962a3211571eb165357003fb
-F test/values.test 6c2426de40cd397a8ab68d375b6964ab3bce1244bbb69f5d1ed3ccd0e039c1f3
+F test/values.test 8c1e0157ba64aeaebdecd4b0b6b1b1422740664e29c17153499973e77ca5200b
 F test/valuesfault.test 2ef23ed965e3bd08e268cdc38a0d11653390ddbbe1e8e2e98d16f55edd30f6e8
 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
@@ -2184,8 +2184,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 b40580be719a129ecd1aa3c69d1086c967d063920fdd48617c864e73c059abc1
-R 8fc5f990e4d938881ab9bd286e3b11d3
+P 6b21cccdeec92db9f6ce3dd7ea5e61b8b46650cc1e550271aa51bdc619f55b11
+R 742e51db40c512171314564bf9760205
 U drh
-Z fa0c07b8b0de569fa969f3e2656bc2dc
+Z 2a179895cc5d13f95288c795c253907b
 # Remove this line to create a well-formed Fossil manifest.
index b31a38051e179b6fc1baea1fa7ef617b3aa1c315..2e5a76fc98c16a27af1ef3199fa4ae7a414dabac 100644 (file)
@@ -1 +1 @@
-6b21cccdeec92db9f6ce3dd7ea5e61b8b46650cc1e550271aa51bdc619f55b11
\ No newline at end of file
+8c0f69e0e4ae0a446838cc193bfd4395fd251f3c7659b35ac388e5a0a7650a66
\ No newline at end of file
index ed1d277b23406d35128f224d6b9f0b852410e687..143fd49c1e9358412f17fefe7070510f91f597e4 100644 (file)
@@ -1152,7 +1152,9 @@ jump_to_p2:
 **
 ** The instruction at the address in register P1 is a Yield.
 ** Jump to the P2 parameter of that Yield.
-** After the jump, register P1 becomes undefined.
+** After the jump, the value register P1 is left with a value
+** such that subsequent OP_Yields go back to the this same
+** OP_EndCoroutine instruction.
 **
 ** See also: InitCoroutine
 */
@@ -1164,8 +1166,8 @@ case OP_EndCoroutine: {           /* in1 */
   pCaller = &aOp[pIn1->u.i];
   assert( pCaller->opcode==OP_Yield );
   assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
+  pIn1->u.i = (int)(pOp - p->aOp) - 1;
   pOp = &aOp[pCaller->p2 - 1];
-  pIn1->flags = MEM_Undefined;
   break;
 }
 
index 65b6ae2c92b1c55cdf12f2b70e95a36a63bbedf4..93984347b75757f2f5b6a600621a008a5ed7d767 100644 (file)
@@ -6940,8 +6940,17 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
       addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
       assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
       if( (ws & WHERE_IDX_ONLY)==0 ){
-        assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
-        sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
+        SrcItem *pSrc = &pTabList->a[pLevel->iFrom];
+        assert( pLevel->iTabCur==pSrc->iCursor );
+        if( pSrc->fg.viaCoroutine ){
+          int m, n;
+          n = pSrc->regResult;
+          assert( pSrc->pTab!=0 );
+          m = pSrc->pTab->nCol;
+          sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
+        }else{
+          sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
+        }
       }
       if( (ws & WHERE_INDEXED)
        || ((ws & WHERE_MULTI_OR) && pLevel->u.pCoveringIdx)
index 1f9c84f0086b35de98d69a861678c79915557077..e91bc283b7df658c071efa9012e42450edc93e6b 100644 (file)
@@ -2730,11 +2730,21 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
                                   pRJ->regReturn);
   for(k=0; k<iLevel; k++){
     int iIdxCur;
+    SrcItem *pRight;
+    assert( pWInfo->a[k].pWLoop->iTab == pWInfo->a[k].iFrom );
+    pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
     mAll |= pWInfo->a[k].pWLoop->maskSelf;
-    sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
-    iIdxCur = pWInfo->a[k].iIdxCur;
-    if( iIdxCur ){
-      sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
+    if( pRight->fg.viaCoroutine ){
+      sqlite3VdbeAddOp3(
+          v, OP_Null, 0, pRight->regResult, 
+          pRight->regResult + pRight->pSelect->pEList->nExpr-1
+      );
+    }else{
+      sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
+      iIdxCur = pWInfo->a[k].iIdxCur;
+      if( iIdxCur ){
+        sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
+      }
     }
   }
   if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){
index 4252f2e13b3af0f06748f36e71ecb3a869fa187d..7e81cdeebbc6b22a8a8673010e131de8ef96a266 100644 (file)
@@ -648,6 +648,27 @@ do_catchsql_test 18.5.3 {
   SELECT * FROM t1;
 } {0 {}}
 
-
+# 2024-04-18 dbsqlfuzz crash-bde3bf80aedf25afa56e2997a0545a314765d3f8
+# Verify that the VALUES expressions used as an argument to an outer
+# join work correctly.
+#
+reset_db
+db null NULL
+do_execsql_test 19.1 {
+  CREATE TABLE t1(a INT, b INT);
+  INSERT INTO t1 VALUES(11,22);
+  SELECT * FROM t1 LEFT JOIN (VALUES(33,44),(55,66)) AS t2 ON a=b;
+} {11 22 NULL NULL}
+do_execsql_test 19.2 {
+  SELECT * FROM (VALUES(33,44),(55,66)) AS t2 RIGHT JOIN t1 ON a=b;
+} {NULL NULL 11 22}
+do_execsql_test 19.3 {
+  SELECT *, '|' FROM t1 FULL JOIN (VALUES(33,44),(55,66)) AS t2 ON a=b
+  ORDER BY +column1
+} {11 22 NULL NULL | NULL NULL 33 44 | NULL NULL 55 66 |}
+do_execsql_test 19.4 {
+  SELECT *, '|' FROM (VALUES(33,44),(55,66)) AS t2 FULL JOIN t1 ON a=b
+  ORDER BY +column1
+} {NULL NULL 11 22 | 33 44 NULL NULL | 55 66 NULL NULL |}
 
 finish_test