diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 12 | ||||
-rw-r--r-- | src/delete.c | 4 | ||||
-rw-r--r-- | src/expr.c | 5 | ||||
-rw-r--r-- | src/parse.y | 23 | ||||
-rw-r--r-- | src/select.c | 17 | ||||
-rw-r--r-- | src/sqliteInt.h | 7 | ||||
-rw-r--r-- | src/where.c | 169 |
7 files changed, 156 insertions, 81 deletions
diff --git a/src/build.c b/src/build.c index 91c8323c7..2ed5d8692 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.496 2008/08/20 16:35:10 drh Exp $ +** $Id: build.c,v 1.497 2008/10/06 05:32:19 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -3052,7 +3052,6 @@ SrcList *sqlite3SrcListAppend( pItem->zName = sqlite3NameFromToken(db, pTable); pItem->zDatabase = sqlite3NameFromToken(db, pDatabase); pItem->iCursor = -1; - pItem->isPopulated = 0; pList->nSrc++; return pList; } @@ -3086,6 +3085,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ sqlite3DbFree(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); sqlite3DbFree(db, pItem->zAlias); + sqlite3DbFree(db, pItem->zIndex); sqlite3DeleteTable(pItem->pTab); sqlite3SelectDelete(db, pItem->pSelect); sqlite3ExprDelete(db, pItem->pOn); @@ -3116,6 +3116,7 @@ SrcList *sqlite3SrcListAppendFromTerm( Token *pTable, /* Name of the table to add to the FROM clause */ Token *pDatabase, /* Name of the database containing pTable */ Token *pAlias, /* The right-hand side of the AS subexpression */ + Token *pIndexedBy, /* Token from INDEXED BY clause, if any */ Select *pSubquery, /* A subquery used in place of a table name */ Expr *pOn, /* The ON clause of a join */ IdList *pUsing /* The USING clause of a join */ @@ -3133,6 +3134,13 @@ SrcList *sqlite3SrcListAppendFromTerm( if( pAlias && pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } + if( pIndexedBy && pIndexedBy->n==1 && !pIndexedBy->z ){ + /* A "NOT INDEXED" clause was supplied. See parse.y + ** construct "indexed_opt" for details. */ + pItem->notIndexed = 1; + }else{ + pItem->zIndex = sqlite3NameFromToken(db, pIndexedBy); + } pItem->pSelect = pSubquery; pItem->pOn = pOn; pItem->pUsing = pUsing; diff --git a/src/delete.c b/src/delete.c index cc25c1b72..a9a887ec0 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.175 2008/09/01 21:59:43 shane Exp $ +** $Id: delete.c,v 1.176 2008/10/06 05:32:19 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -106,7 +106,7 @@ void sqlite3MaterializeView( pWhere = sqlite3ExprDup(db, pWhere); viewName.z = (u8*)pView->zName; viewName.n = (unsigned int)strlen((const char*)viewName.z); - pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0); + pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName,0,pDup,0,0); pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0); } sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); diff --git a/src/expr.c b/src/expr.c index b13bb99e0..b5fc4f9d1 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.396 2008/10/02 16:42:07 danielk1977 Exp $ +** $Id: expr.c,v 1.397 2008/10/06 05:32:19 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -733,6 +733,9 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){ pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; pNewItem->isPopulated = pOldItem->isPopulated; + pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); + pNewItem->notIndexed = pOldItem->notIndexed; + pNewItem->pIndex = pOldItem->pIndex; pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nRef++; diff --git a/src/parse.y b/src/parse.y index 7ec634317..4af16d422 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.252 2008/08/20 16:35:10 drh Exp $ +** @(#) $Id: parse.y,v 1.253 2008/10/06 05:32:19 danielk1977 Exp $ */ // All token codes are small integers with #defines that begin with "TK_" @@ -456,13 +456,13 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). { if( A && A->nSrc>0 ) A->a[A->nSrc-1].jointype = Y; } stl_prefix(A) ::= . {A = 0;} -seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). { - A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U); +seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) using_opt(U). { + A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,&I,0,N,U); } %ifndef SQLITE_OMIT_SUBQUERY seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP as(Z) on_opt(N) using_opt(U). { - A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U); + A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,0,S,N,U); } // A seltablist_paren nonterminal represents anything in a FROM that @@ -499,6 +499,21 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN. on_opt(N) ::= ON expr(E). {N = E;} on_opt(N) ::= . {N = 0;} +// Note that this block abuses the Token type just a little. If there is +// no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If +// there is an INDEXED BY clause, then the token is populated as per normal, +// with z pointing to the token data and n containing the number of bytes +// in the token. +// +// If there is a "NOT INDEXED" clause, then (z==0 && n==1), which is +// normally illegal. The sqlite3SrcListAppendFromTerm() function +// recognizes and interprets this as a special case. +// +%type indexed_opt {Token} +indexed_opt(A) ::= . {A.z=0; A.n=0;} +indexed_opt(A) ::= INDEXED BY nm(X). {A = X;} +indexed_opt(A) ::= NOT INDEXED. {A.z=0; A.n=1;} + %type using_opt {IdList*} %destructor using_opt {sqlite3IdListDelete(pParse->db, $$);} using_opt(U) ::= USING LP inscollist(L) RP. {U = L;} diff --git a/src/select.c b/src/select.c index adbf9e432..eebeb4cf4 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.476 2008/09/23 09:36:10 drh Exp $ +** $Id: select.c,v 1.477 2008/10/06 05:32:19 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -2982,6 +2982,21 @@ static int selectExpander(Walker *pWalker, Select *p){ } #endif } + + /* Locate the index named by the INDEXED BY clause, if any. */ + if( pFrom->zIndex ){ + char *zIndex = pFrom->zIndex; + Index *pIdx; + for(pIdx=pTab->pIndex; + pIdx && sqlite3StrICmp(pIdx->zName, zIndex); + pIdx=pIdx->pNext + ); + if( !pIdx ){ + sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0); + return WRC_Abort; + } + pFrom->pIndex = pIdx; + } } /* Process NATURAL keywords, and ON and USING clauses of joins. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index daa85a722..134886f4d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.773 2008/10/02 13:50:56 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.774 2008/10/06 05:32:19 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1448,6 +1448,9 @@ struct SrcList { Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */ + u8 notIndexed; /* True if there is a NOT INDEXED clause */ + char *zIndex; /* Identifier from "INDEXED BY <zIndex>" clause */ + Index *pIndex; /* Index structure corresponding to zIndex, if any */ } a[1]; /* One entry for each identifier on the list */ }; @@ -2139,7 +2142,7 @@ IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, - Select*, Expr*, IdList*); + Token*, Select*, Expr*, IdList*); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); diff --git a/src/where.c b/src/where.c index 08dc448aa..afb61b4ce 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.323 2008/10/01 08:43:03 danielk1977 Exp $ +** $Id: where.c,v 1.324 2008/10/06 05:32:19 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -1473,6 +1473,16 @@ static double bestVirtualIndex( ** * Whether or not there must be separate lookups in the ** index and in the main table. ** +** If there was an INDEXED BY clause attached to the table in the SELECT +** statement, then this function only considers strategies using the +** named index. If one cannot be found, then the returned cost is +** SQLITE_BIG_DBL. If a strategy can be found that uses the named index, +** then the cost is calculated in the usual way. +** +** If a NOT INDEXED clause was attached to the table in the SELECT +** statement, then no indexes are considered. However, the selected +** stategy may still take advantage of the tables built-in rowid +** index. */ static double bestIndex( Parse *pParse, /* The parsing context */ @@ -1500,6 +1510,9 @@ static double bestIndex( WHERETRACE(("bestIndex: tbl=%s notReady=%llx\n", pSrc->pTab->zName, notReady)); lowestCost = SQLITE_BIG_DBL; pProbe = pSrc->pTab->pIndex; + if( pSrc->notIndexed ){ + pProbe = 0; + } /* If the table has no indices and there are no terms in the where ** clause that refer to the ROWID, then we will never be able to do @@ -1516,74 +1529,77 @@ static double bestIndex( return 0.0; } - /* Check for a rowid=EXPR or rowid IN (...) constraints - */ - pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); - if( pTerm ){ - Expr *pExpr; - *ppIndex = 0; - bestFlags = WHERE_ROWID_EQ; - if( pTerm->eOperator & WO_EQ ){ - /* Rowid== is always the best pick. Look no further. Because only - ** a single row is generated, output is always in sorted order */ - *pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE; - *pnEq = 1; - WHERETRACE(("... best is rowid\n")); - return 0.0; - }else if( (pExpr = pTerm->pExpr)->pList!=0 ){ - /* Rowid IN (LIST): cost is NlogN where N is the number of list - ** elements. */ - lowestCost = pExpr->pList->nExpr; - lowestCost *= estLog(lowestCost); - }else{ - /* Rowid IN (SELECT): cost is NlogN where N is the number of rows - ** in the result of the inner select. We have no way to estimate - ** that value so make a wild guess. */ - lowestCost = 200; - } - WHERETRACE(("... rowid IN cost: %.9g\n", lowestCost)); - } - - /* Estimate the cost of a table scan. If we do not know how many - ** entries are in the table, use 1 million as a guess. + /* Check for a rowid=EXPR or rowid IN (...) constraints. If there was + ** an INDEXED BY clause attached to this table, skip this step. */ - cost = pProbe ? pProbe->aiRowEst[0] : 1000000; - WHERETRACE(("... table scan base cost: %.9g\n", cost)); - flags = WHERE_ROWID_RANGE; - - /* Check for constraints on a range of rowids in a table scan. - */ - pTerm = findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE|WO_GT|WO_GE, 0); - if( pTerm ){ - if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){ - flags |= WHERE_TOP_LIMIT; - cost /= 3; /* Guess that rowid<EXPR eliminates two-thirds or rows */ - } - if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){ - flags |= WHERE_BTM_LIMIT; - cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */ + if( !pSrc->pIndex ){ + pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); + if( pTerm ){ + Expr *pExpr; + *ppIndex = 0; + bestFlags = WHERE_ROWID_EQ; + if( pTerm->eOperator & WO_EQ ){ + /* Rowid== is always the best pick. Look no further. Because only + ** a single row is generated, output is always in sorted order */ + *pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE; + *pnEq = 1; + WHERETRACE(("... best is rowid\n")); + return 0.0; + }else if( (pExpr = pTerm->pExpr)->pList!=0 ){ + /* Rowid IN (LIST): cost is NlogN where N is the number of list + ** elements. */ + lowestCost = pExpr->pList->nExpr; + lowestCost *= estLog(lowestCost); + }else{ + /* Rowid IN (SELECT): cost is NlogN where N is the number of rows + ** in the result of the inner select. We have no way to estimate + ** that value so make a wild guess. */ + lowestCost = 200; + } + WHERETRACE(("... rowid IN cost: %.9g\n", lowestCost)); } - WHERETRACE(("... rowid range reduces cost to %.9g\n", cost)); - }else{ - flags = 0; - } - - /* If the table scan does not satisfy the ORDER BY clause, increase - ** the cost by NlogN to cover the expense of sorting. */ - if( pOrderBy ){ - if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){ - flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE; - if( rev ){ - flags |= WHERE_REVERSE; + + /* Estimate the cost of a table scan. If we do not know how many + ** entries are in the table, use 1 million as a guess. + */ + cost = pProbe ? pProbe->aiRowEst[0] : 1000000; + WHERETRACE(("... table scan base cost: %.9g\n", cost)); + flags = WHERE_ROWID_RANGE; + + /* Check for constraints on a range of rowids in a table scan. + */ + pTerm = findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE|WO_GT|WO_GE, 0); + if( pTerm ){ + if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){ + flags |= WHERE_TOP_LIMIT; + cost /= 3; /* Guess that rowid<EXPR eliminates two-thirds or rows */ + } + if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){ + flags |= WHERE_BTM_LIMIT; + cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */ } + WHERETRACE(("... rowid range reduces cost to %.9g\n", cost)); }else{ - cost += cost*estLog(cost); - WHERETRACE(("... sorting increases cost to %.9g\n", cost)); + flags = 0; + } + + /* If the table scan does not satisfy the ORDER BY clause, increase + ** the cost by NlogN to cover the expense of sorting. */ + if( pOrderBy ){ + if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){ + flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE; + if( rev ){ + flags |= WHERE_REVERSE; + } + }else{ + cost += cost*estLog(cost); + WHERETRACE(("... sorting increases cost to %.9g\n", cost)); + } + } + if( cost<lowestCost ){ + lowestCost = cost; + bestFlags = flags; } - } - if( cost<lowestCost ){ - lowestCost = cost; - bestFlags = flags; } /* If the pSrc table is the right table of a LEFT JOIN then we may not @@ -1599,7 +1615,10 @@ static double bestIndex( /* Look at each index. */ - for(; pProbe; pProbe=pProbe->pNext){ + if( pSrc->pIndex ){ + pProbe = pSrc->pIndex; + } + for(; pProbe; pProbe=(pSrc->pIndex ? 0 : pProbe->pNext)){ int i; /* Loop counter */ double inMultiplier = 1; @@ -2065,7 +2084,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo = sqlite3DbMallocZero(db, sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel)); if( db->mallocFailed ){ - goto whereBeginNoMem; + goto whereBeginError; } pWInfo->nLevel = pTabList->nSrc; pWInfo->pParse = pParse; @@ -2112,7 +2131,7 @@ WhereInfo *sqlite3WhereBegin( */ exprAnalyzeAll(pTabList, &wc); if( db->mallocFailed ){ - goto whereBeginNoMem; + goto whereBeginError; } /* Chose the best index to use for each table in the FROM clause. @@ -2122,7 +2141,7 @@ WhereInfo *sqlite3WhereBegin( ** pWInfo->a[].pIdx The index to use for this level of the loop. ** pWInfo->a[].flags WHERE_xxx flags associated with pIdx ** pWInfo->a[].nEq The number of == and IN constraints - ** pWInfo->a[].iFrom When term of the FROM clause is being coded + ** pWInfo->a[].iFrom Which term of the FROM clause is being coded ** pWInfo->a[].iTabCur The VDBE cursor for the database table ** pWInfo->a[].iIdxCur The VDBE cursor for the index ** @@ -2219,6 +2238,18 @@ WhereInfo *sqlite3WhereBegin( } notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor); pLevel->iFrom = bestJ; + + /* Check that if the table scanned by this loop iteration had an + ** INDEXED BY clause attached to it, that the named index is being + ** used for the scan. If not, then query compilation has failed. + ** Return an error. + */ + pIdx = pTabList->a[bestJ].pIndex; + assert( !pIdx || !pBest || pIdx==pBest ); + if( pIdx && pBest!=pIdx ){ + sqlite3ErrorMsg(pParse, "cannot use index: %s", pIdx->zName); + goto whereBeginError; + } } WHERETRACE(("*** Optimizer Finished ***\n")); @@ -2778,7 +2809,7 @@ WhereInfo *sqlite3WhereBegin( return pWInfo; /* Jump here if malloc fails */ -whereBeginNoMem: +whereBeginError: whereClauseClear(&wc); whereInfoFree(pWInfo); return 0; |