diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 4 | ||||
-rw-r--r-- | src/sqliteInt.h | 1 | ||||
-rw-r--r-- | src/where.c | 198 |
3 files changed, 103 insertions, 100 deletions
diff --git a/src/build.c b/src/build.c index b3e963974..3e011c625 100644 --- a/src/build.c +++ b/src/build.c @@ -2315,9 +2315,6 @@ static void recomputeColumnsNotIndexed(Parse *pParse, Index *pIdx){ } } pIdx->colNotIdxed = ~m; - if( pIdx->pPartIdxWhere ){ - sqlite3WherePartIdxExpr(pParse, pIdx, pIdx->pPartIdxWhere, 0, 0); - } assert( (pIdx->colNotIdxed>>63)==1 ); /* See note-20221022-a */ } @@ -4277,7 +4274,6 @@ void sqlite3CreateIndex( assert( HasRowid(pTab) || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 ); recomputeColumnsNotIndexed(pParse, pIndex); - if( pParse->nErr ) goto exit_create_index; if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ pIndex->isCovering = 1; for(j=0; j<pTab->nCol; j++){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 35864de5e..722197499 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4940,7 +4940,6 @@ int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */ #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ int sqlite3WhereUsesDeferredSeek(WhereInfo*); -void sqlite3WherePartIdxExpr(Parse*, Index*, Expr*, int, SrcItem*); void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); diff --git a/src/where.c b/src/where.c index 65f7f5acd..777e49854 100644 --- a/src/where.c +++ b/src/where.c @@ -3499,6 +3499,104 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex( } /* +** This is an sqlite3ParserAddCleanup() callback that is invoked to +** free the Parse->pIdxEpr list when the Parse object is destroyed. +*/ +static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){ + IndexedExpr **pp = (IndexedExpr**)pObject; + while( *pp!=0 ){ + IndexedExpr *p = *pp; + *pp = p->pIENext; + sqlite3ExprDelete(db, p->pExpr); + sqlite3DbFreeNN(db, p); + } +} + +/* +** This function is called for a partial index - one with a WHERE clause - in +** two scenarios. In both cases, it determines whether or not the WHERE +** clause on the index implies that a column of the table may be safely +** replaced by a constant expression. For example, in the following +** SELECT: +** +** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>; +** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?; +** +** The "a" in the select-list may be replaced by <expr>, iff: +** +** (a) <expr> is a constant expression, and +** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and +** (c) Column "a" has an affinity other than NONE or BLOB. +** +** If argument pItem is NULL, then pMask must not be NULL. In this case this +** function is being called as part of determining whether or not pIdx +** is a covering index. This function clears any bits in (*pMask) +** corresponding to columns that may be replaced by constants as described +** above. +** +** Otherwise, if pItem is not NULL, then this function is being called +** as part of coding a loop that uses index pIdx. In this case, add entries +** to the Parse.pIdxPartExpr list for each column that can be replaced +** by a constant. +*/ +static void wherePartIdxExpr( + Parse *pParse, /* Parse context */ + Index *pIdx, /* Partial index being processed */ + Expr *pPart, /* WHERE clause being processed */ + Bitmask *pMask, /* Mask to clear bits in */ + int iIdxCur, /* Cursor number for index */ + SrcItem *pItem /* The FROM clause entry for the table */ +){ + assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 ); + assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) ); + + if( pPart->op==TK_AND ){ + wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem); + pPart = pPart->pLeft; + } + + if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){ + Expr *pLeft = pPart->pLeft; + Expr *pRight = pPart->pRight; + u8 aff; + + if( pRight->op==TK_COLUMN ){ + SWAP(Expr*, pLeft, pRight); + } + + if( pLeft->op!=TK_COLUMN ) return; + if( !sqlite3ExprIsConstant(pRight) ) return; + if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return; + if( pLeft->iColumn<0 ) return; + aff = pIdx->pTable->aCol[pLeft->iColumn].affinity; + if( aff>=SQLITE_AFF_TEXT ){ + if( pItem ){ + sqlite3 *db = pParse->db; + IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocZero(db, sizeof(*p)); + if( p ){ + int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0; + p->pExpr = sqlite3ExprDup(db, pRight, 0); + p->iDataCur = pItem->iCursor; + p->iIdxCur = iIdxCur; + p->iIdxCol = pLeft->iColumn; + p->bMaybeNullRow = bNullRow; + p->pIENext = pParse->pIdxPartExpr; + p->aff = aff; + pParse->pIdxPartExpr = p; + if( p->pIENext==0 ){ + void *pArg = (void*)&pParse->pIdxPartExpr; + sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg); + } + } + }else if( pLeft->iColumn<(BMS-1) ){ + *pMask &= ~((Bitmask)1 << pLeft->iColumn); + } + } + } +} + + +/* ** Add all WhereLoop objects for a single table of the join where the table ** is identified by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. @@ -3713,6 +3811,9 @@ static int whereLoopAddBtree( pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; }else{ m = pSrc->colUsed & pProbe->colNotIdxed; + if( pProbe->pPartIdxWhere ){ + wherePartIdxExpr(pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0); + } pNew->wsFlags = WHERE_INDEXED; if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){ u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor); @@ -5669,20 +5770,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } /* -** This is an sqlite3ParserAddCleanup() callback that is invoked to -** free the Parse->pIdxEpr list when the Parse object is destroyed. -*/ -static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){ - IndexedExpr **pp = (IndexedExpr**)pObject; - while( *pp!=0 ){ - IndexedExpr *p = *pp; - *pp = p->pIENext; - sqlite3ExprDelete(db, p->pExpr); - sqlite3DbFreeNN(db, p); - } -} - -/* ** The index pIdx is used by a query and contains one or more expressions. ** In other words pIdx is an index on an expression. iIdxCur is the cursor ** number for the index and iDataCur is the cursor number for the corresponding @@ -5750,85 +5837,6 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( } /* -** This function is called for a partial index - one with a WHERE clause - in -** two scenarios. In both cases, it determines whether or not the WHERE -** clause on the index implies that a column of the table may be safely -** replaced by a constant expression. For example, in the following -** SELECT: -** -** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>; -** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?; -** -** The "a" in the select-list may be replaced by <expr>, iff: -** -** (a) <expr> is a constant expression, and -** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and -** (c) Column "a" has an affinity other than NONE or BLOB. -** -** If argument pTabItem is NULL, then this function is being called as part -** of parsing the CREATE INDEX statement. In that case the Index.colNotIdxed -** mask is updated to mark any columns that will be replaced by constant -** values as indexed. -** -** Otherwise, if pTabItem is not NULL, then this function is being called -** as part of coding a loop that uses index pIdx. In this case, add entries -** to the Parse.pIdxPartExpr list for each column that can be replaced -** by a constant. -*/ -void sqlite3WherePartIdxExpr( - Parse *pParse, /* Parse context */ - Index *pIdx, /* Partial index being processed */ - Expr *pPart, /* WHERE clause being processed */ - int iIdxCur, /* Cursor number for index */ - SrcItem *pTabItem /* The FROM clause entry for the table */ -){ - assert( pTabItem==0 || (pTabItem->fg.jointype & JT_RIGHT)==0 ); - if( pPart->op==TK_AND ){ - sqlite3WherePartIdxExpr(pParse, pIdx, pPart->pRight, iIdxCur, pTabItem); - pPart = pPart->pLeft; - } - - if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){ - Expr *pLeft = pPart->pLeft; - Expr *pRight = pPart->pRight; - u8 aff; - - if( pRight->op==TK_COLUMN ){ - SWAP(Expr*, pLeft, pRight); - } - - if( pLeft->op!=TK_COLUMN ) return; - if( !sqlite3ExprIsConstant(pRight) ) return; - if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return; - if( pLeft->iColumn<0 ) return; - aff = pIdx->pTable->aCol[pLeft->iColumn].affinity; - if( aff>=SQLITE_AFF_TEXT ){ - if( pTabItem ){ - sqlite3 *db = pParse->db; - IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocZero(db, sizeof(*p)); - if( p ){ - int bNullRow = (pTabItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0; - p->pExpr = sqlite3ExprDup(db, pRight, 0); - p->iDataCur = pTabItem->iCursor; - p->iIdxCur = iIdxCur; - p->iIdxCol = pLeft->iColumn; - p->bMaybeNullRow = bNullRow; - p->pIENext = pParse->pIdxPartExpr; - p->aff = aff; - pParse->pIdxPartExpr = p; - if( p->pIENext==0 ){ - void *pArg = (void*)&pParse->pIdxPartExpr; - sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg); - } - } - }else if( pLeft->iColumn<(BMS-1) ){ - pIdx->colNotIdxed &= ~((Bitmask)1 << pLeft->iColumn); - } - } - } -} - -/* ** Set the reverse-scan order mask to one for all tables in the query ** with the exception of MATERIALIZED common table expressions that have ** their own internal ORDER BY clauses. @@ -6436,8 +6444,8 @@ WhereInfo *sqlite3WhereBegin( whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem); } if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){ - sqlite3WherePartIdxExpr( - pParse, pIx, pIx->pPartIdxWhere, iIndexCur, pTabItem + wherePartIdxExpr( + pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem ); } } |