From: drh Date: Sat, 18 Dec 2004 18:40:26 +0000 (+0000) Subject: Improvements to the query optimizer. This is a work in progress. (CVS 2169) X-Git-Tag: version-3.6.10~3983 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=51669863a83aa0fb9aacdb9744f80ab234d72530;p=thirdparty%2Fsqlite.git Improvements to the query optimizer. This is a work in progress. (CVS 2169) FossilOrigin-Name: 9b86993ff721b577b920c7c67fb41d3d4355fe88 --- diff --git a/manifest b/manifest index 787d64ae26..b0d627cc51 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sC++-ism\sin\sthe\sprevious\schange\sto\stclsqlite.c.\s(CVS\s2168) -D 2004-12-17T20:48:06 +C Improvements\sto\sthe\squery\soptimizer.\s\sThis\sis\sa\swork\sin\sprogress.\s(CVS\s2169) +D 2004-12-18T18:40:27 F Makefile.in da09f379b80c8cd78d78abaa0f32ca90a124e884 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -35,7 +35,7 @@ F src/build.c af1296e8a21a406b4f4c4f1e1365e075071219f3 F src/cursor.c f883813759742068890b1f699335872bfa8fdf41 F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f F src/delete.c 6debe7893fa09bb5b386df0f26165f13132423e6 -F src/expr.c d61efc526449a7a4c725325a3001a614cbcc3bed +F src/expr.c d718509e56f58b06bc5f9b46afb295675334d544 F src/func.c b668e5ad043176049454c95a6a780367a0e8f6bb F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 @@ -62,7 +62,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c ac6610b4b2c5bd5ffc46536b760dacc420119dac F src/shell.c e8f4f486cbf6e60d81173146ac8a6522c930fa51 F src/sqlite.h.in fa75850f412808afd38fddc1fd6456f4efc6fb97 -F src/sqliteInt.h e0c5c1af95e975645c7a09b151af258d6fca1c53 +F src/sqliteInt.h 9f95e46c03ba8466e7bc4528ffe39e3ae0c955ab F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c 3a4044ef609565c8cc51e887d8b96933ba9f3b5c F src/test1.c b7d94c54e58f95452387a5cabdf98b2be8059f29 @@ -82,7 +82,7 @@ F src/vdbeInt.h 0f74561e629af86172de7cdf0ecaea014c51696c F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd F src/vdbeaux.c a7c4c90786e2633b38f2d89f3dc49aed747454e4 F src/vdbemem.c 5876c8abf4374fef671f4fd8dc333ef3fc95a2f0 -F src/where.c 35ea898e6414864afb819d3fde30f11179dbede0 +F src/where.c 94b784521e40f1b181ac151f89150a243c88feee F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432 F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c F test/alter.test 95c57a4f461fa81293e0dccef7f83889aadb169a @@ -202,7 +202,7 @@ F test/utf16.test 459c2f5ab80c60092c603630a348c32d6e59c558 F test/vacuum.test f18eccdee5b538d46298c64d6a060cfbf97bbc23 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/view.test 3f96df86f1c61ee850b945204683773bbbb8643e -F test/where.test 6914a44678693e78d379eab389140a33334633a2 +F test/where.test e092b5c206a58d61282090acce63a9d5fbe401f3 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/lemon.c 250b30bcf3f1f422a2cad24b1597314777058a4b F tool/lempar.c 1e61d2b6cb9d8affa264a13336bc0c088498caa4 @@ -263,7 +263,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c -P a9311d9df054a91e231d4e4332df0d661675744d -R 82afa2ad55f8fa2d63a8a18ec3035e8e +P b49b8fdd11a5a4aac15ceda58a28bbc852f6f239 +R 98ad9cc1dc8e1742c8a95031c2f5cb13 U drh -Z 1ee374478d3894044f0834b2bb0bd546 +Z e1e7b9285b9bdd508bb0434689171c56 diff --git a/manifest.uuid b/manifest.uuid index b4fa3d69e1..bea4ff6f39 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b49b8fdd11a5a4aac15ceda58a28bbc852f6f239 \ No newline at end of file +9b86993ff721b577b920c7c67fb41d3d4355fe88 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 9b011c514e..95710f6355 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.175 2004/12/07 15:41:49 drh Exp $ +** $Id: expr.c,v 1.176 2004/12/18 18:40:27 drh Exp $ */ #include "sqliteInt.h" #include @@ -690,7 +690,9 @@ static int lookupName( int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ - sqlite3 *db = pParse->db; /* The database */ + sqlite3 *db = pParse->db; /* The database */ + struct SrcList_item *pItem; /* Use for looping over pSrcList items */ + struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */ zDb = sqlite3NameFromToken(pDbToken); @@ -702,8 +704,7 @@ static int lookupName( assert( zTab==0 || pEList==0 ); pExpr->iTable = -1; - for(i=0; inSrc; i++){ - struct SrcList_item *pItem = &pSrcList->a[i]; + for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ Table *pTab = pItem->pTab; Column *pCol; @@ -724,11 +725,13 @@ static int lookupName( if( 0==(cntTab++) ){ pExpr->iTable = pItem->iCursor; pExpr->iDb = pTab->iDb; + pMatch = pItem; } for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ cnt++; pExpr->iTable = pItem->iCursor; + pMatch = pItem; pExpr->iDb = pTab->iDb; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; @@ -842,6 +845,21 @@ static int lookupName( sqliteFree(z); } + /* If a column from a table in pSrcList is referenced, then record + ** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes + ** bit 0 to be set. Column 1 sets bit 1. And so forth. If the + ** column number is greater than the number of bits in the bitmask + ** then set the high-order bit of the bitmask. + */ + if( pExpr->iColumn>=0 && pMatch!=0 ){ + int n = pExpr->iColumn; + if( n>=sizeof(Bitmask)*8 ){ + n = sizeof(Bitmask)*8-1; + } + assert( pMatch->iCursor==pExpr->iTable ); + pMatch->colUsed |= 1< +** +** Where is a simple column name and is on of the operators +** that allowedOp() recognizes. */ typedef struct ExprInfo ExprInfo; struct ExprInfo { @@ -29,24 +70,41 @@ struct ExprInfo { ** p->pLeft is not the column of any table */ short int idxRight; /* p->pRight is a column in this table number. -1 if ** p->pRight is not the column of any table */ - unsigned prereqLeft; /* Bitmask of tables referenced by p->pLeft */ - unsigned prereqRight; /* Bitmask of tables referenced by p->pRight */ - unsigned prereqAll; /* Bitmask of tables referenced by p */ + Bitmask prereqLeft; /* Bitmask of tables referenced by p->pLeft */ + Bitmask prereqRight; /* Bitmask of tables referenced by p->pRight */ + Bitmask prereqAll; /* Bitmask of tables referenced by p */ }; /* ** An instance of the following structure keeps track of a mapping -** between VDBE cursor numbers and bitmasks. The VDBE cursor numbers -** are small integers contained in SrcList_item.iCursor and Expr.iTable -** fields. For any given WHERE clause, we want to track which cursors -** are being used, so we assign a single bit in a 32-bit word to track -** that cursor. Then a 32-bit integer is able to show the set of all -** cursors being used. +** between VDBE cursor numbers and bits of the bitmasks in ExprInfo. +** +** The VDBE cursor numbers are small integers contained in +** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE +** clause, the cursor numbers might not begin with 0 and they might +** contain gaps in the numbering sequence. But we want to make maximum +** use of the bits in our bitmasks. This structure provides a mapping +** from the sparse cursor numbers into consecutive integers beginning +** with 0. +** +** If ExprMaskSet.ix[A]==B it means that The A-th bit of a Bitmask +** corresponds VDBE cursor number B. The A-th bit of a bitmask is 1<3, 5->1, 8->2, 29->0, +** 57->5, 73->4. Or one of 719 other combinations might be used. It +** does not really matter. What is important is that sparse cursor +** numbers all get mapped into bit numbers that begin with 0 and contain +** no gaps. */ typedef struct ExprMaskSet ExprMaskSet; struct ExprMaskSet { - int n; /* Number of assigned cursor values */ - int ix[31]; /* Cursor assigned to each bit */ + int n; /* Number of assigned cursor values */ + int ix[sizeof(Bitmask)*8-1]; /* Cursor assigned to each bit */ }; /* @@ -55,13 +113,21 @@ struct ExprMaskSet { #define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0])) /* -** This routine is used to divide the WHERE expression into subexpressions -** separated by the AND operator. +** This routine identifies subexpressions in the WHERE clause where +** each subexpression is separate by the AND operator. aSlot is +** filled with pointers to the subexpressions. For example: +** +** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22) +** \________/ \_______________/ \________________/ +** slot[0] slot[1] slot[2] +** +** The original WHERE clause in pExpr is unaltered. All this routine +** does is make aSlot[] entries point to substructure within pExpr. ** -** aSlot[] is an array of subexpressions structures. -** There are nSlot spaces left in this array. This routine attempts to -** split pExpr into subexpressions and fills aSlot[] with those subexpressions. -** The return value is the number of slots filled. +** aSlot[] is an array of subexpressions structures. There are nSlot +** spaces left in this array. This routine finds as many AND-separated +** subexpressions as it can and puts pointers to those subexpressions +** into aSlot[] entries. The return value is the number of slots filled. */ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){ int cnt = 0; @@ -86,18 +152,20 @@ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){ #define initMaskSet(P) memset(P, 0, sizeof(*P)) /* -** Return the bitmask for the given cursor. Assign a new bitmask +** Return the bitmask for the given cursor number. Assign a new bitmask ** if this is the first time the cursor has been seen. */ -static int getMask(ExprMaskSet *pMaskSet, int iCursor){ +static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){ int i; for(i=0; in; i++){ - if( pMaskSet->ix[i]==iCursor ) return 1<ix[i]==iCursor ){ + return ((Bitmask)1)<n && iix) ){ pMaskSet->n++; pMaskSet->ix[i] = iCursor; - return 1<op==TK_COLUMN ){ mask = getMask(pMaskSet, p->iTable); @@ -144,7 +212,7 @@ static int exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){ /* ** Return TRUE if the given operator is one of the operators that is -** allowed for an indexable WHERE clause. The allowed operators are +** allowed for an indexable WHERE clause term. The allowed operators are ** "=", "<", ">", "<=", ">=", and "IN". */ static int allowedOp(int op){ @@ -153,7 +221,7 @@ static int allowedOp(int op){ } /* -** Swap two integers. +** Swap two objects of type T. */ #define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} @@ -168,8 +236,9 @@ static int allowedOp(int op){ */ static int tableOrder(SrcList *pList, int iCur){ int i; - for(i=0; inSrc; i++){ - if( pList->a[i].iCursor==iCur ) return i; + struct SrcList_item *pItem; + for(i=0, pItem=pList->a; inSrc; i++, pItem++){ + if( pItem->iCursor==iCur ) return i; } return -1; } @@ -324,6 +393,100 @@ static Index *findSortingIndex( return pMatch; } +/* +** This routine decides if pIdx can be used to satisfy the ORDER BY +** clause. If it can, it returns 1. If pIdx cannot satisfy the +** ORDER BY clause, this routine returns 0. +** +** pOrderBy is an ORDER BY clause from a SELECT statement. pTab is the +** left-most table in the FROM clause of that same SELECT statement and +** the table has a cursor number of "base". pIdx is an index on pTab. +** +** nEqCol is the number of columns of pIdx that are used as equality +** constraints. Any of these columns may be missing from the ORDER BY +** clause and the match can still be a success. +** +** If the index is UNIQUE, then the ORDER BY clause is allowed to have +** additional terms past the end of the index and the match will still +** be a success. +** +** All terms of the ORDER BY that match against the index must be either +** ASC or DESC. (Terms of the ORDER BY clause past the end of a UNIQUE +** index do not need to satisfy this constraint.) The *pbRev value is +** set to 1 if the ORDER BY clause is all DESC and it is set to 0 if +** the ORDER BY clause is all ASC. +*/ +static int isSortingIndex( + Parse *pParse, /* Parsing context */ + Index *pIdx, /* The index we are testing */ + Table *pTab, /* The table to be sorted */ + int base, /* Cursor number for pTab */ + ExprList *pOrderBy, /* The ORDER BY clause */ + int nEqCol, /* Number of index columns with == constraints */ + int *pbRev /* Set to 1 if ORDER BY is DESC */ +){ + int i, j; /* Loop counters */ + int sortOrder; /* Which direction we are sorting */ + int nTerm; /* Number of ORDER BY terms */ + struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ + sqlite3 *db = pParse->db; + + assert( pOrderBy!=0 ); + nTerm = pOrderBy->nExpr; + assert( nTerm>0 ); + + /* Match terms of the ORDER BY clause against columns of + ** the index. + */ + for(i=j=0, pTerm=pOrderBy->a; jnColumn; i++){ + Expr *pExpr; /* The expression of the ORDER BY pTerm */ + CollSeq *pColl; /* The collating sequence of pExpr */ + + pExpr = pTerm->pExpr; + if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){ + /* Can not use an index sort on anything that is not a column in the + ** left-most table of the FROM clause */ + return 0; + } + pColl = sqlite3ExprCollSeq(pParse, pExpr); + if( !pColl ) pColl = db->pDfltColl; + if( pExpr->iColumn!=pIdx->aiColumn[i] && pColl!=pIdx->keyInfo.aColl[i] ){ + if( i<=nEqCol ){ + /* If an index column that is constrained by == fails to match an + ** ORDER BY term, that is OK. Just ignore that column of the index + */ + continue; + }else{ + /* If an index column fails to match and is not constrained by == + ** then the index cannot satisfy the ORDER BY constraint. + */ + return 0; + } + } + if( i>nEqCol ){ + if( pTerm->sortOrder!=sortOrder ){ + /* Indices can only be used if all ORDER BY terms past the + ** equality constraints are all either DESC or ASC. */ + return 0; + } + }else{ + sortOrder = pTerm->sortOrder; + } + j++; + pTerm++; + } + + /* The index can be used for sorting if all terms of the ORDER BY clause + ** or covered or if we ran out of index columns and the it is a UNIQUE + ** index. + */ + if( j>=nTerm || (i>=pIdx->nColumn && pIdx->onError!=OE_None) ){ + *pbRev = sortOrder==SQLITE_SO_DESC; + return 1; + } + return 0; +} + /* ** Check table to see if the ORDER BY clause in pOrderBy can be satisfied ** by sorting in order of ROWID. Return true if so and set *pbRev to be @@ -421,6 +584,11 @@ static void codeEqualityTerm( disableTerm(pLevel, &pTerm->p); } +/* +** The number of bits in a Bitmask +*/ +#define BMS (sizeof(Bitmask)*8-1) + /* ** Generate the beginning of the loop used for WHERE clause processing. @@ -512,13 +680,13 @@ WhereInfo *sqlite3WhereBegin( Vdbe *v = pParse->pVdbe; /* The virtual database engine */ int brk, cont = 0; /* Addresses used during code generation */ int nExpr; /* Number of subexpressions in the WHERE clause */ - int loopMask; /* One bit set for each outer loop */ + Bitmask loopMask; /* One bit set for each outer loop */ int haveKey = 0; /* True if KEY is on the stack */ ExprInfo *pTerm; /* A single term in the WHERE clause; ptr to aExpr[] */ ExprMaskSet maskSet; /* The expression mask set */ - int iDirectEq[32]; /* Term of the form ROWID==X for the N-th table */ - int iDirectLt[32]; /* Term of the form ROWIDX or ROWID>=X */ + int iDirectEq[BMS]; /* Term of the form ROWID==X for the N-th table */ + int iDirectLt[BMS]; /* Term of the form ROWIDX or ROWID>=X */ ExprInfo aExpr[101]; /* The WHERE clause is divided into these terms */ /* pushKey is only allowed if there is a single table (as in an INSERT or @@ -526,9 +694,6 @@ WhereInfo *sqlite3WhereBegin( */ assert( pushKey==0 || pTabList->nSrc==1 ); - /* - */ - /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. If the aExpr[] ** array fills up, the last entry might point to an expression which @@ -575,13 +740,13 @@ WhereInfo *sqlite3WhereBegin( if( (pStack = pParse->trigStack)!=0 ){ int x; if( (x=pStack->newIdx) >= 0 ){ - int mask = ~getMask(&maskSet, x); + Bitmask mask = ~getMask(&maskSet, x); pTerm->prereqRight &= mask; pTerm->prereqLeft &= mask; pTerm->prereqAll &= mask; } if( (x=pStack->oldIdx) >= 0 ){ - int mask = ~getMask(&maskSet, x); + Bitmask mask = ~getMask(&maskSet, x); pTerm->prereqRight &= mask; pTerm->prereqLeft &= mask; pTerm->prereqAll &= mask; @@ -609,12 +774,13 @@ WhereInfo *sqlite3WhereBegin( for(i=0; inSrc && ia[i]; - int iCur = pTabList->a[i].iCursor; /* The cursor for this table */ - int mask = getMask(&maskSet, iCur); /* Cursor mask for this table */ + int iCur = pTabList->a[i].iCursor; /* The cursor for this table */ + Bitmask mask = getMask(&maskSet, iCur); /* Cursor mask for this table */ Table *pTab = pTabList->a[i].pTab; Index *pIdx; Index *pBestIdx = 0; int bestScore = 0; + int bestRev = 0; /* Check to see if there is an expression that uses only the ** ROWID field of this table. For terms of the form ROWID==expr @@ -660,17 +826,25 @@ WhereInfo *sqlite3WhereBegin( ** ** The best index is determined as follows. For each of the ** left-most terms that is fixed by an equality operator, add - ** 8 to the score. The right-most term of the index may be - ** constrained by an inequality. Add 1 if for an "x<..." constraint - ** and add 2 for an "x>..." constraint. Chose the index that - ** gives the best score. + ** 32 to the score. The right-most term of the index may be + ** constrained by an inequality. Add 4 if for an "x<..." constraint + ** and add 8 for an "x>..." constraint. If both constraints + ** are present, add 12. + ** + ** If the left-most term of the index uses an IN operator + ** (ex: "x IN (...)") then add 16 to the score. + ** + ** If an index can be used for sorting, add 2 to the score. + ** If an index contains all the terms of a table that are ever + ** used by any expression in the SQL statement, then add 1 to + ** the score. ** ** This scoring system is designed so that the score can later be - ** used to determine how the index is used. If the score&7 is 0 - ** then all constraints are equalities. If score&1 is not 0 then + ** used to determine how the index is used. If the score&0x1c is 0 + ** then all constraints are equalities. If score&0x4 is not 0 then ** there is an inequality used as a termination key. (ex: "x<...") - ** If score&2 is not 0 then there is an inequality used as the - ** start key. (ex: "x>..."). A score or 4 is the special case + ** If score&0x8 is not 0 then there is an inequality used as the + ** start key. (ex: "x>..."). A score or 0x10 is the special case ** of an IN operator constraint. (ex: "x IN ..."). ** ** The IN operator (as in " IN (...)") is treated the same as @@ -680,13 +854,16 @@ WhereInfo *sqlite3WhereBegin( ** other columns of the index. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - int eqMask = 0; /* Index columns covered by an x=... term */ - int ltMask = 0; /* Index columns covered by an x<... term */ - int gtMask = 0; /* Index columns covered by an x>... term */ - int inMask = 0; /* Index columns covered by an x IN .. term */ - int nEq, m, score; + Bitmask eqMask = 0; /* Index columns covered by an x=... term */ + Bitmask ltMask = 0; /* Index columns covered by an x<... term */ + Bitmask gtMask = 0; /* Index columns covered by an x>... term */ + Bitmask inMask = 0; /* Index columns covered by an x IN .. term */ + Bitmask m; + int nEq, score, bRev = 0; - if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */ + if( pIdx->nColumn>sizeof(eqMask)*8 ){ + continue; /* Ignore indices with too many columns to analyze */ + } for(pTerm=aExpr, j=0; jp; CollSeq *pColl = sqlite3ExprCollSeq(pParse, pX->pLeft); @@ -713,17 +890,17 @@ WhereInfo *sqlite3WhereBegin( break; } case TK_EQ: { - eqMask |= 1<nColumn; nEq++){ - m = (1<<(nEq+1))-1; + m = (((Bitmask)1)<<(nEq+1))-1; if( (m & eqMask)!=m ) break; } - score = nEq*8; /* Base score is 8 times number of == constraints */ - m = 1< constraint */ - if( score==0 && inMask ) score = 4; /* Default score for IN constraint */ + + /* Begin assemblying the score + */ + score = nEq*32; /* Base score is 32 times number of == constraints */ + m = ((Bitmask)1)< constraint */ + if( score==0 && inMask ) score = 16; /* Default score for IN constraint */ + + /* Give bonus points if this index can be used for sorting + */ + if( i==0 && score>0 && ppOrderBy && *ppOrderBy ){ + int base = pTabList->a[0].iCursor; + if( isSortingIndex(pParse, pIdx, pTab, base, *ppOrderBy, nEq, &bRev) ){ + score += 2; + } + } + + /* If the score for this index is the best we have seen so far, then + ** save it + */ if( score>bestScore ){ pBestIdx = pIdx; bestScore = score; + bestRev = bRev; } } pLevel->pIdx = pBestIdx; pLevel->score = bestScore; - pLevel->bRev = 0; + pLevel->bRev = bestRev; loopMask |= mask; if( pBestIdx ){ pLevel->iCur = pParse->nTab++; @@ -784,7 +978,7 @@ WhereInfo *sqlite3WhereBegin( */ *ppOrderBy = 0; pLevel0->bRev = bRev; - }else if( pLevel0->score==4 ){ + }else if( pLevel0->score==16 ){ /* If there is already an IN index on the left-most table, ** it will not give the correct sort order. ** So, pretend that no suitable index is found. @@ -795,7 +989,7 @@ WhereInfo *sqlite3WhereBegin( ** if it is redundant. */ }else{ - int nEqCol = (pLevel0->score+4)/8; + int nEqCol = (pLevel0->score+16)/32; pSortIdx = findSortingIndex(pParse, pTab, iCur, *ppOrderBy, pIdx, nEqCol, &bRev); } @@ -867,12 +1061,12 @@ WhereInfo *sqlite3WhereBegin( haveKey = 0; sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk); pLevel->op = OP_Noop; - }else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ){ + }else if( pIdx!=0 && pLevel->score>0 && (pLevel->score&0x0c)==0 ){ /* Case 2: There is an index and all terms of the WHERE clause that ** refer to the index using the "==" or "IN" operators. */ int start; - int nColumn = (pLevel->score+4)/8; + int nColumn = (pLevel->score+16)/32; brk = pLevel->brk = sqlite3VdbeMakeLabel(v); /* For each column of the index, find the term of the WHERE clause that @@ -1019,7 +1213,7 @@ WhereInfo *sqlite3WhereBegin( ** to force the output order to conform to an ORDER BY. */ int score = pLevel->score; - int nEqColumn = score/8; + int nEqColumn = score/32; int start; int leFlag=0, geFlag=0; int testOp; @@ -1063,7 +1257,7 @@ WhereInfo *sqlite3WhereBegin( ** 2002-Dec-04: On a reverse-order scan, the so-called "termination" ** key computed here really ends up being the start key. */ - if( (score & 1)!=0 ){ + if( (score & 4)!=0 ){ for(pTerm=aExpr, k=0; kp; if( pX==0 ) continue; @@ -1084,7 +1278,7 @@ WhereInfo *sqlite3WhereBegin( leFlag = 1; } if( testOp!=OP_Noop ){ - int nCol = nEqColumn + (score & 1); + int nCol = nEqColumn + ((score & 4)!=0); pLevel->iMem = pParse->nMem++; buildIndexProbe(v, nCol, brk, pIdx); if( pLevel->bRev ){ @@ -1106,7 +1300,7 @@ WhereInfo *sqlite3WhereBegin( ** 2002-Dec-04: In the case of a reverse-order search, the so-called ** "start" key really ends up being used as the termination key. */ - if( (score & 2)!=0 ){ + if( (score & 8)!=0 ){ for(pTerm=aExpr, k=0; kp; if( pX==0 ) continue; @@ -1124,8 +1318,8 @@ WhereInfo *sqlite3WhereBegin( }else{ geFlag = 1; } - if( nEqColumn>0 || (score&2)!=0 ){ - int nCol = nEqColumn + ((score&2)!=0); + if( nEqColumn>0 || (score&8)!=0 ){ + int nCol = nEqColumn + ((score&8)!=0); buildIndexProbe(v, nCol, brk, pIdx); if( pLevel->bRev ){ pLevel->iMem = pParse->nMem++; @@ -1154,7 +1348,7 @@ WhereInfo *sqlite3WhereBegin( } } sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0); - sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont); + sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + ((score&4)!=0), cont); sqlite3VdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); if( i==pTabList->nSrc-1 && pushKey ){ haveKey = 1; diff --git a/test/where.test b/test/where.test index 17533fac48..14257361e5 100644 --- a/test/where.test +++ b/test/where.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the use of indices in WHERE clases. # -# $Id: where.test,v 1.24 2004/11/22 19:12:21 drh Exp $ +# $Id: where.test,v 1.25 2004/12/18 18:40:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -417,7 +417,7 @@ do_test where-6.8 { cksort { SELECT * FROM t3 WHERE a IN (3,5,7,1,9,4,2) ORDER BY a LIMIT 3 } -} {1 100 4 2 99 9 3 98 16 sort} +} {1 100 4 2 99 9 3 98 16 nosort} do_test where-6.9.1 { cksort { SELECT * FROM t3 WHERE a=1 AND c>0 ORDER BY a LIMIT 3