aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2024-04-18 16:11:01 +0000
committerdrh <>2024-04-18 16:11:01 +0000
commit0526db32e2657b2b16fa3333e5b8c6e24754eaf2 (patch)
treeca76dd3163ef69ff01ebc69fdcfdf5ea5e162f9a /src
parent06915d014545ebf1b00163351e76fbaa6a3ba7b8 (diff)
downloadsqlite-0526db32e2657b2b16fa3333e5b8c6e24754eaf2.tar.gz
sqlite-0526db32e2657b2b16fa3333e5b8c6e24754eaf2.zip
Correct handling of OUTER JOIN when on or the other operand is a subquery
implemented using the VALUES-as-coroutine optimization. dbsqlfuzz bde3bf80aedf25afa56e2997a0545a314765d3f8. FossilOrigin-Name: 8c0f69e0e4ae0a446838cc193bfd4395fd251f3c7659b35ac388e5a0a7650a66
Diffstat (limited to 'src')
-rw-r--r--src/vdbe.c6
-rw-r--r--src/where.c13
-rw-r--r--src/wherecode.c18
3 files changed, 29 insertions, 8 deletions
diff --git a/src/vdbe.c b/src/vdbe.c
index ed1d277b2..143fd49c1 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -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;
}
diff --git a/src/where.c b/src/where.c
index 65b6ae2c9..93984347b 100644
--- a/src/where.c
+++ b/src/where.c
@@ -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)
diff --git a/src/wherecode.c b/src/wherecode.c
index 1f9c84f00..e91bc283b 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -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 ){