diff options
author | drh <> | 2022-04-09 12:27:20 +0000 |
---|---|---|
committer | drh <> | 2022-04-09 12:27:20 +0000 |
commit | 7c1734b09e436176c2aac461e835c29532403ad4 (patch) | |
tree | 31980b91155d55166411d6be8f963e85514ca12d /src | |
parent | c2308ad2a0cb4f6d957518c615d308ed79b42d04 (diff) | |
download | sqlite-7c1734b09e436176c2aac461e835c29532403ad4.tar.gz sqlite-7c1734b09e436176c2aac461e835c29532403ad4.zip |
The interior of the RIGHT JOIN loop is now a subroutine.
FossilOrigin-Name: 549f5a7ee639de80f049445002f58e93c805f9a3d3db1987ec9d139ccef4805e
Diffstat (limited to 'src')
-rw-r--r-- | src/where.c | 19 | ||||
-rw-r--r-- | src/whereInt.h | 13 | ||||
-rw-r--r-- | src/wherecode.c | 24 |
3 files changed, 46 insertions, 10 deletions
diff --git a/src/where.c b/src/where.c index a5fab2cd5..afcecd77b 100644 --- a/src/where.c +++ b/src/where.c @@ -5869,12 +5869,18 @@ WhereInfo *sqlite3WhereBegin( } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); - if( pTabItem->fg.jointype & JT_RIGHT ){ + if( (pTabItem->fg.jointype & JT_RIGHT)!=0 + && (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0 + ){ + WhereRightJoin *pRJ = pLevel->pRJ; + pRJ->iMatch = pParse->nTab++; + pRJ->regBloom = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); + pRJ->regReturn = ++pParse->nMem; assert( pTab==pTabItem->pTab ); - pLevel->iRJMatch = pParse->nTab++; if( HasRowid(pTab) ){ KeyInfo *pInfo; - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pLevel->iRJMatch, 1); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0); if( pInfo ){ pInfo->aColl[0] = 0; @@ -5883,7 +5889,7 @@ WhereInfo *sqlite3WhereBegin( } }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pLevel->iRJMatch, pPk->nKeyCol); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } } @@ -5999,6 +6005,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; + if( pLevel->pRJ ){ + WhereRightJoin *pRJ = (WhereRightJoin*)pLevel->pRJ; + sqlite3VdbeChangeP2(v, pRJ->addrSubrtn-1, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeAddOp2(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn); + } pLoop = pLevel->pWLoop; if( pLevel->op!=OP_Noop ){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT diff --git a/src/whereInt.h b/src/whereInt.h index df62db4f1..7b5be3011 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -33,6 +33,7 @@ typedef struct WhereScan WhereScan; typedef struct WhereOrCost WhereOrCost; typedef struct WhereOrSet WhereOrSet; typedef struct WhereMemBlock WhereMemBlock; +typedef struct WhereRightJoin WhereRightJoin; /* ** This object is a header on a block of allocated memory that will be @@ -44,6 +45,16 @@ struct WhereMemBlock { }; /* +** Extra information attached to a WhereLevel that is a RIGHT JOIN. +*/ +struct WhereRightJoin { + int iMatch; /* Cursor used to determine prior matched rows */ + int regBloom; /* Bloom filter for iRJMatch */ + int regReturn; /* Return register for the interior subroutine */ + int addrSubrtn; /* Starting address for the interior subroutine */ +}; + +/* ** This object contains information needed to implement a single nested ** loop in WHERE clause. ** @@ -75,7 +86,7 @@ struct WhereLevel { int addrLikeRep; /* LIKE range processing address */ #endif int regFilter; /* Bloom filter */ - int iRJMatch; /* Cursor or rowset used for matched RIGHT JOIN rows */ + WhereRightJoin *pRJ; /* Extra information for RIGHT JOIN */ u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to end the loop */ diff --git a/src/wherecode.c b/src/wherecode.c index 5b8ed8934..853646c71 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2724,12 +2724,18 @@ Bitmask sqlite3WhereCodeOneLoopStart( /* For a RIGHT OUTER JOIN, record the fact that the current row has ** been matched at least once. */ - if( pLevel->iRJMatch ){ + if( pLevel->pRJ ){ Table *pTab; int nPk; int r; int jmp1 = 0; + WhereRightJoin *pRJ = pLevel->pRJ; + /* pTab is the right-hand table of the RIGHT JOIN. Generate code that + ** will record that the current row of that table has been matched at + ** least once. This is accomplished by storing the PK for the row in + ** both the iMatch index and the regBloom Bloom filter. + */ pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; if( HasRowid(pTab) ){ r = sqlite3GetTempRange(pParse, 2); @@ -2745,15 +2751,23 @@ Bitmask sqlite3WhereCodeOneLoopStart( sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk); } } - jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pLevel->iRJMatch, 0, r+1, nPk); + jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, 0, r+1, nPk); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pLevel->iRJMatch, r, r+1, nPk); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk); + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3VdbeJumpHere(v, jmp1); - - /* Release the array of temp registers */ sqlite3ReleaseTempRange(pParse, r, nPk+1); + + /* Create a subroutine used to process all interior loops and code + ** of the RIGHT JOIN. During normal operation, the subroutine will + ** be in-line with the rest of the code. But at the end, a separate + ** loop will run that invokes this subroutine for unmatched rows + ** of pTab, with all tables to left begin set to NULL. + */ + sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn); + pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v); } #if WHERETRACE_ENABLED /* 0x20800 */ |