diff options
author | dan <dan@noemail.net> | 2020-01-04 16:55:57 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2020-01-04 16:55:57 +0000 |
commit | 74ebaadcdd8b1058bbc80bf61334fe09da1c64b5 (patch) | |
tree | a1ee43b8fd756ca0f38d6fa570a36ad7f8db83c7 /src | |
parent | f6ea97ea3d278c212ef366e255051e52ca352332 (diff) | |
download | sqlite-74ebaadcdd8b1058bbc80bf61334fe09da1c64b5.tar.gz sqlite-74ebaadcdd8b1058bbc80bf61334fe09da1c64b5.zip |
Fix a problem where the loop for the RHS of a LEFT JOIN uses values from an IN() clause as the second or subsequent field of an index.
FossilOrigin-Name: 95ef68966c50f311830cba8c9257a4085c93011d205e0e31867c2917fa62a48e
Diffstat (limited to 'src')
-rw-r--r-- | src/vdbe.c | 15 | ||||
-rw-r--r-- | src/where.c | 24 | ||||
-rw-r--r-- | src/wherecode.c | 2 |
3 files changed, 35 insertions, 6 deletions
diff --git a/src/vdbe.c b/src/vdbe.c index 5479a311b..8ddc904d1 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -4374,7 +4374,7 @@ seek_not_found: ** Synopsis: seekHit=P2 ** ** Set the seekHit flag on cursor P1 to the value in P2. -** The seekHit flag is used by the IfNoHope opcode. +* The seekHit flag is used by the IfNoHope opcode. ** ** P1 must be a valid b-tree cursor. P2 must be a boolean value, ** either 0 or 1. @@ -4389,6 +4389,19 @@ case OP_SeekHit: { break; } +/* Opcode: IfNotOpen P1 P2 * * * +** Synopsis: if( !csr[P1] ) goto P2 +** +** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through. +*/ +case OP_IfNotOpen: { /* jump */ + assert( pOp->p1>=0 && pOp->p1<p->nCursor ); + if( !p->apCsr[pOp->p1] ){ + goto jump_to_p2_and_check_for_interrupt; + } + break; +} + /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** diff --git a/src/where.c b/src/where.c index 0877b80dd..075276168 100644 --- a/src/where.c +++ b/src/where.c @@ -5273,10 +5273,26 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ if( pIn->eEndLoopOp!=OP_Noop ){ if( pIn->nPrefix ){ assert( pLoop->wsFlags & WHERE_IN_EARLYOUT ); - sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, - sqlite3VdbeCurrentAddr(v)+2, - pIn->iBase, pIn->nPrefix); - VdbeCoverage(v); + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, + sqlite3VdbeCurrentAddr(v)+2+(pLevel->iLeftJoin!=0), + pIn->iBase, pIn->nPrefix); + VdbeCoverage(v); + } + if( pLevel->iLeftJoin ){ + /* For LEFT JOIN queries, cursor pIn->iCur may not have been + ** opened yet. This occurs for WHERE clauses such as + ** "a = ? AND b IN (...)", where the index is on (a, b). If + ** the RHS of the (a=?) is NULL, then the "b IN (...)" may + ** never have been coded, but the body of the loop run to + ** return the null-row. So, if the cursor is not open yet, + ** jump over the OP_Next or OP_Prev instruction about to + ** be coded. */ + sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur, + sqlite3VdbeCurrentAddr(v) + 2 + ); + VdbeCoverage(v); + } } sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); VdbeCoverage(v); diff --git a/src/wherecode.c b/src/wherecode.c index beb23e0c1..03e393498 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -593,7 +593,7 @@ static int codeEqualityTerm( if( i==iEq ){ pIn->iCur = iTab; pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; - if( iEq>0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + if( iEq>0 ){ pIn->iBase = iReg - i; pIn->nPrefix = i; pLoop->wsFlags |= WHERE_IN_EARLYOUT; |