aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2022-04-09 12:27:20 +0000
committerdrh <>2022-04-09 12:27:20 +0000
commit7c1734b09e436176c2aac461e835c29532403ad4 (patch)
tree31980b91155d55166411d6be8f963e85514ca12d /src
parentc2308ad2a0cb4f6d957518c615d308ed79b42d04 (diff)
downloadsqlite-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.c19
-rw-r--r--src/whereInt.h13
-rw-r--r--src/wherecode.c24
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 */