diff options
author | drh <> | 2025-07-07 15:40:53 +0000 |
---|---|---|
committer | drh <> | 2025-07-07 15:40:53 +0000 |
commit | 4fe1ac8fe1c3831588ae2ad1f8ea0841b11523ab (patch) | |
tree | 088d1cd122272ca4a858a8cbf914149d57c95c70 /src | |
parent | 4aacd1ef8eff53662b827e920d2c7d5d46833b9d (diff) | |
download | sqlite-4fe1ac8fe1c3831588ae2ad1f8ea0841b11523ab.tar.gz sqlite-4fe1ac8fe1c3831588ae2ad1f8ea0841b11523ab.zip |
Simplifications to the row-value IN operator logic. Do not let the query
planner accept a WhereLoop for a row-value IN operator that uses the same
index column more than once.
FossilOrigin-Name: d2adf61f21a3ce901a2b08199ad0de191e88ef16e097c5f7a75c95ad958eff12
Diffstat (limited to 'src')
-rw-r--r-- | src/where.c | 16 | ||||
-rw-r--r-- | src/wherecode.c | 25 |
2 files changed, 23 insertions, 18 deletions
diff --git a/src/where.c b/src/where.c index 6a195dd2d..5d80dd3d6 100644 --- a/src/where.c +++ b/src/where.c @@ -3239,6 +3239,7 @@ static int whereLoopAddBtreeIndex( if( ExprUseXSelect(pExpr) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ int i; + int bRedundant = 0; nIn = 46; assert( 46==sqlite3LogEst(25) ); /* The expression may actually be of the form (x, y) IN (SELECT...). @@ -3247,7 +3248,20 @@ static int whereLoopAddBtreeIndex( ** for each such term. The following loop checks that pTerm is the ** first such term in use, and sets nIn back to 0 if it is not. */ for(i=0; i<pNew->nLTerm-1; i++){ - if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; + if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ){ + nIn = 0; + if( pNew->aLTerm[i]->u.x.iField == pTerm->u.x.iField ){ + /* Detect when two or more columns of an index match the same + ** column of a vector IN operater, and avoid adding the column + ** to the WhereLoop more than once. See tag-20250707-01 + ** in test/rowvalue.test */ + bRedundant = 1; + } + } + } + if( bRedundant ){ + pNew->nLTerm--; + continue; } }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ diff --git a/src/wherecode.c b/src/wherecode.c index cc672aa83..eb508d938 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -695,7 +695,7 @@ static SQLITE_NOINLINE void codeINTerm( return; } } - for(i=iEq;i<pLoop->nLTerm; i++){ + for(i=iEq; i<pLoop->nLTerm; i++){ assert( pLoop->aLTerm[i]!=0 ); if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } @@ -704,22 +704,13 @@ static SQLITE_NOINLINE void codeINTerm( if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab); }else{ - Expr *pExpr = pTerm->pExpr; - if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){ - sqlite3 *db = pParse->db; - pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); - if( !db->mallocFailed ){ - aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq); - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab); - pExpr->iTable = iTab; - } - sqlite3ExprDelete(db, pX); - }else{ - int n = sqlite3ExprVectorSize(pX->pLeft); - aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n)); - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab); + sqlite3 *db = pParse->db; + Expr *pXMod = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); + if( !db->mallocFailed ){ + aiMap = (int*)sqlite3DbMallocZero(db, sizeof(int)*nEq); + eType = sqlite3FindInIndex(pParse, pXMod, IN_INDEX_LOOP, 0, aiMap, &iTab); } - pX = pExpr; + sqlite3ExprDelete(db, pXMod); } if( eType==IN_INDEX_INDEX_DESC ){ @@ -749,7 +740,7 @@ static SQLITE_NOINLINE void codeINTerm( if( pIn ){ int iMap = 0; /* Index in aiMap[] */ pIn += i; - for(i=iEq;i<pLoop->nLTerm; i++){ + for(i=iEq; i<pLoop->nLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iOut = iTarget + i - iEq; if( eType==IN_INDEX_ROWID ){ |