mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
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
This commit is contained in:
16
src/where.c
16
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, ...)" */
|
||||
|
@@ -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 ){
|
||||
|
Reference in New Issue
Block a user