From: drh Date: Sat, 23 Jul 2005 22:59:55 +0000 (+0000) Subject: A new optimizer that breaks a lot of tests. But none of them critically, I X-Git-Tag: version-3.6.10~3595 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=51147baa6ddf3afe738161c2d9c74a65eb26b8e7;p=thirdparty%2Fsqlite.git A new optimizer that breaks a lot of tests. But none of them critically, I think. Nevertheless, there is a lot of work ahead to stabilize the code. (CVS 2564) FossilOrigin-Name: 86ce56ccea8297b1fba2b9ee53b5f1a3f228662f --- diff --git a/manifest b/manifest index 7a6f83a16e..aa85641fc2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Store\sthe\stotal\snumber\sof\srows\sas\spart\sof\sthe\sANALYZE\sstatistics.\s(CVS\s2563) -D 2005-07-23T14:52:12 +C A\snew\soptimizer\sthat\sbreaks\sa\slot\sof\stests.\s\sBut\snone\sof\sthem\scritically,\sI\nthink.\s\sNevertheless,\sthere\sis\sa\slot\sof\swork\sahead\sto\sstabilize\sthe\scode.\s(CVS\s2564) +D 2005-07-23T22:59:56 F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -28,12 +28,12 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def c413e514217736884254739a105c8c942fdf0c2f F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/alter.c 03041f2464e22532601254f87cb49997fa21dcdf -F src/analyze.c a0d88c2278f0cabadfd3dfdb464f38cc63b9897c +F src/analyze.c 3ab32927f4d3067ead10e4c4f6fb61b2a93479cc F src/attach.c 3615dbe960cbee4aa5ea300b8a213dad36527b0f F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f F src/btree.c ec55bd70052cdd0958f3a0e79ad58d93561acb20 F src/btree.h 41a71ce027db9ddee72cb43df2316bbe3a1d92af -F src/build.c 59a3ffe94df2c58f223a66644ea7ffd8eba28bc7 +F src/build.c b78e95dcfcbbe285969e9563560f3e20a23cc8c0 F src/callback.c 0910b611e0c158f107ee3ff86f8a371654971e2b F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940 F src/delete.c be1fc25c9e109cd8cbab42a43ee696263da7c04b @@ -64,10 +64,10 @@ F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4 F src/select.c c611471052773b94af771693686bd5bcdbbb0dba F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26 F src/sqlite.h.in 7ccf2f61de2a0dca515e73708e561362e6c3d1e3 -F src/sqliteInt.h ebcf33fa4380cfcb9385bd739037a5445c36fd5a +F src/sqliteInt.h 4cacefaca973cbf8e6a82910c704bf9b4a32fdf1 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c ef3276d0967cc0042bedcc1a7f09e0eb95cd3a8c -F src/test1.c 722c1444b5774705eb6eb11163343fc94ffe17f7 +F src/test1.c 4268e81180a7f9b396a4cf2aa7f268d828cfdf74 F src/test2.c 716c1809dba8e5be6093703e9cada99d627542dc F src/test3.c 683e1e3819152ffd35da2f201e507228921148d0 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df @@ -85,7 +85,7 @@ F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6 F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03 -F src/where.c 70b2195b4732ce785be32140f982b2ed471d205d +F src/where.c 3e9f8336bac3bbc829b85381227f1341f3fd4362 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6 @@ -287,7 +287,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b -P 1996bacfb97180965304e2a6d6784b6ecbbf8575 -R ce8b845e83c2fe78f71fc8660f861c81 +P 868279c78e056d27b2d1bea81127fe689b2ce478 +R 5bb82d998a20777c2205e35147889290 U drh -Z fe452359cfb2b9a0187816cb97118aaf +Z 9d14e39e2e0ab0d8adb6f266b567831d diff --git a/manifest.uuid b/manifest.uuid index d3984aeb8f..9d523ca771 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -868279c78e056d27b2d1bea81127fe689b2ce478 \ No newline at end of file +86ce56ccea8297b1fba2b9ee53b5f1a3f228662f \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 9a6d99e5f3..dc1338aad5 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.5 2005/07/23 14:52:12 drh Exp $ +** @(#) $Id: analyze.c,v 1.6 2005/07/23 22:59:56 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -364,10 +364,7 @@ void sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Clear any prior statistics */ for(i=sqliteHashFirst(&db->aDb[iDb].idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); - int j; - for(j=0; j<=pIdx->nColumn; j++){ - pIdx->aiRowEst[j] = j<100 ? 1000*(100-j) : 100; - } + sqlite3DefaultRowEst(pIdx); } /* Check to make sure the sqlite_stat1 table existss */ diff --git a/src/build.c b/src/build.c index a44897d782..93e94b6679 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.335 2005/07/23 14:52:12 drh Exp $ +** $Id: build.c,v 1.336 2005/07/23 22:59:56 drh Exp $ */ #include "sqliteInt.h" #include @@ -2206,7 +2206,6 @@ void sqlite3CreateIndex( goto exit_create_index; } pIndex->aiColumn[i] = j; - pIndex->aiRowEst[i] = 100; if( pList->a[i].pExpr ){ assert( pList->a[i].pExpr->pColl ); pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl; @@ -2221,6 +2220,7 @@ void sqlite3CreateIndex( } } pIndex->keyInfo.nField = pList->nExpr; + sqlite3DefaultRowEst(pIndex); if( pTab==pParse->pNewTable ){ /* This routine has been called to create an automatic index as a @@ -2387,6 +2387,21 @@ exit_create_index: return; } +/* +** Fill the Index.aiRowEst[] array with default information - information +** to be used when we have no ANALYZE command to run. +*/ +void sqlite3DefaultRowEst(Index *pIdx){ + int i; + int n = pIdx->nColumn; + int j = 1000000; + int f = (1000000-1-100*(pIdx->onError==OE_None))/n; + for(i=0; i<=n; i++, j-=f){ + assert( j>0 ); + pIdx->aiRowEst[i] = j; + } +} + /* ** This routine will drop an existing named index. This routine ** implements the DROP INDEX statement. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d8a0bedeb1..e80af77ea7 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.399 2005/07/23 03:18:40 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.400 2005/07/23 22:59:56 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -952,7 +952,7 @@ struct SrcList { struct WhereLevel { int iFrom; /* Which entry in the FROM clause */ int flags; /* Flags associated with this level */ - int iMem; /* Memory cell used by this level */ + int iMem; /* First memory cell used by this level */ int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ Index *pIdx; /* Index used. NULL if no index */ int iTabCur; /* The VDBE cursor used to access the table */ @@ -961,6 +961,7 @@ struct WhereLevel { int cont; /* Jump here to continue with the next loop cycle */ int top; /* First instruction of interior of the loop */ int op, p1, p2; /* Opcode used to terminate the loop */ + int nEq; /* Number of == or IN constraints on this loop */ int nIn; /* Number of IN operators constraining this loop */ int *aInLoop; /* Loop terminators for IN operators */ }; @@ -1572,6 +1573,7 @@ void sqlite3Analyze(Parse*, Token*, Token*); int sqlite3InvokeBusyHandler(BusyHandler*); int sqlite3FindDb(sqlite3*, Token*); void sqlite3AnalysisLoad(sqlite3*,int iDB); +void sqlite3DefaultRowEst(Index*); #ifdef SQLITE_SSE #include "sseInt.h" diff --git a/src/test1.c b/src/test1.c index ae609edee0..4ca3f0438e 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.150 2005/07/20 14:31:53 drh Exp $ +** $Id: test1.c,v 1.151 2005/07/23 22:59:56 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -3091,6 +3091,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_os_trace; + extern int sqlite3_where_trace; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_memUsed; @@ -3117,6 +3118,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ (char*)&sqlite3_current_time, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_os_trace", (char*)&sqlite3_os_trace, TCL_LINK_INT); + Tcl_LinkVar(interp, "sqlite_where_trace", + (char*)&sqlite3_where_trace, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_memused", (char*)&sqlite3_memUsed, TCL_LINK_INT | TCL_LINK_READ_ONLY); Tcl_LinkVar(interp, "sqlite_memmax", diff --git a/src/where.c b/src/where.c index 5082cdd24a..2dbcf2ea51 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.151 2005/07/22 00:31:40 drh Exp $ +** $Id: where.c,v 1.152 2005/07/23 22:59:56 drh Exp $ */ #include "sqliteInt.h" @@ -30,6 +30,16 @@ */ #define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0])) +/* +** Trace output macros +*/ +#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) +int sqlite3_where_trace = 0; +# define TRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X +#else +# define TRACE(X) +#endif + /* Forward reference */ typedef struct WhereClause WhereClause; @@ -50,7 +60,10 @@ typedef struct WhereClause WhereClause; ** ** where X is a column name and is one of certain operators, ** then WhereTerm.leftCursor and WhereTerm.leftColumn record the -** cursor number and column number for X. +** cursor number and column number for X. WhereTerm.operator records +** the using a bitmask encoding defined by WO_xxx below. The +** use of a bitmask encoding for the operator allows us to search +** quickly for terms that match any of several different operators. ** ** prereqRight and prereqAll record sets of cursor numbers, ** but they do so indirectly. A single ExprMaskSet structure translates @@ -72,7 +85,7 @@ struct WhereTerm { u16 flags; /* Bit flags. See below */ i16 leftCursor; /* Cursor number of X in "X " */ i16 leftColumn; /* Column number of X in "X " */ - u8 operator; /* A WO_xx value describing */ + u16 operator; /* A WO_xx value describing */ WhereClause *pWC; /* The clause this term is part of */ Bitmask prereqRight; /* Bitmask of tables used by pRight */ Bitmask prereqAll; /* Bitmask of tables referenced by p */ @@ -81,7 +94,7 @@ struct WhereTerm { /* ** Allowed values of WhereTerm.flags */ -#define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(p) */ +#define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(pExpr) */ #define TERM_VIRTUAL 0x0002 /* Added by the optimizer. Do not code */ #define TERM_CODED 0x0004 /* This term is already coded */ @@ -93,37 +106,8 @@ struct WhereClause { Parse *pParse; /* The parser context */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ - WhereTerm *a; /* Pointer to an array of terms */ - WhereTerm aStatic[10]; /* Initial static space for the terms */ -}; - -/* -** When WhereTerms are used to select elements from an index, we -** call those terms "constraints". For example, consider the following -** SQL: -** -** CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d); -** CREATE INDEX t1i1 ON t1(b,c); -** -** SELECT * FROM t1 WHERE d=5 AND b=7 AND c>11; -** -** In the SELECT statement, the "b=7" and "c>11" terms are constraints -** because they can be used to choose rows out of the t1i1 index. But -** the "d=5" term is not a constraint because it is not indexed. -** -** When generating code to access an index, we have to keep track of -** all of the constraints associated with that index. This is done -** using an array of instanaces of the following structure. There is -** one instance of this structure for each constraint on the index. -** -** Actually, we allocate the array of this structure based on the total -** number of terms in the entire WHERE clause (because the number of -** constraints can never be more than that) and reuse it when coding -** each index. -*/ -typedef struct WhereConstraint WhereConstraint; -struct WhereConstraint { - int iMem; /* Mem cell used to hold part of constraint */ + WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ + WhereTerm aStatic[10]; /* Initial static space for a[] */ }; /* @@ -159,6 +143,34 @@ struct ExprMaskSet { }; +/* +** Bitmasks for the operators that indices are able to exploit. An +** OR-ed combination of these values can be used when searching for +** terms in the where clause. +*/ +#define WO_IN 1 +#define WO_LIST 2 +#define WO_SELECT 4 +#define WO_EQ 8 +#define WO_LT (WO_EQ<<(TK_LT-TK_EQ)) +#define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) +#define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) +#define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) + +/* +** Value for flags returned by bestIndex() +*/ +#define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */ +#define WHERE_ROWID_RANGE 0x0002 /* rowidEXPR */ +#define WHERE_COLUMN_EQ 0x0010 /* x=EXPR or x IN (...) */ +#define WHERE_COLUMN_RANGE 0x0020 /* xEXPR */ +#define WHERE_COLUMN_IN 0x0040 /* x IN (...) */ +#define WHERE_TOP_LIMIT 0x0100 /* xEXPR or x>=EXPR constraint */ +#define WHERE_IDX_ONLY 0x0800 /* Use index only - omit table */ +#define WHERE_ORDERBY 0x1000 /* Output will appear in correct order */ +#define WHERE_REVERSE 0x2000 /* Scan in reverse order */ + /* ** Initialize a preallocated WhereClause structure. */ @@ -222,12 +234,11 @@ static WhereTerm *whereClauseInsert(WhereClause *pWC, Expr *p, int flags){ ** 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. +** does is make slot[] entries point to substructure within pExpr. ** -** 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. +** In the previous sentence and in the diagram, "slot[]" refers to +** the WhereClause.a[] array. This array grows as needed to contain +** all terms of the WHERE clause. */ static void whereSplit(WhereClause *pWC, Expr *pExpr){ if( pExpr==0 ) return; @@ -281,7 +292,9 @@ static void createMask(ExprMaskSet *pMaskSet, int iCursor){ ** the header comment on that routine for additional information. ** The sqlite3ExprResolveNames() routines looks for column names and ** sets their opcodes to TK_COLUMN and their Expr.iTable fields to -** the VDBE cursor number of the table. +** the VDBE cursor number of the table. This routine just has to +** translate the cursor numbers into bitmask values and OR all +** the bitmasks together. */ static Bitmask exprListTableUsage(ExprMaskSet *, ExprList *); static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){ @@ -351,28 +364,24 @@ static void exprCommute(Expr *pExpr){ } } -/* -** Bitmasks for the operators that indices are able to exploit. An -** OR-ed combination of these values can be used when searching for -** terms in the where clause. -*/ -#define WO_IN 1 -#define WO_EQ 2 -#define WO_LT (2<<(TK_LT-TK_EQ)) -#define WO_LE (2<<(TK_LE-TK_EQ)) -#define WO_GT (2<<(TK_GT-TK_EQ)) -#define WO_GE (2<<(TK_GE-TK_EQ)) - /* ** Translate from TK_xx operator to WO_xx bitmask. */ static int operatorMask(int op){ + int c; assert( allowedOp(op) ); if( op==TK_IN ){ - return WO_IN; + c = WO_IN; }else{ - return 1<<(op+1-TK_EQ); + c = WO_EQ<<(op-TK_EQ); } + assert( op!=TK_IN || c==WO_IN ); + assert( op!=TK_EQ || c==WO_EQ ); + assert( op!=TK_LT || c==WO_LT ); + assert( op!=TK_LE || c==WO_LE ); + assert( op!=TK_GT || c==WO_GT ); + assert( op!=TK_GE || c==WO_GE ); + return c; } /* @@ -386,7 +395,7 @@ static WhereTerm *findTerm( int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ - u8 op, /* Mask of WO_xx values describing operator */ + u16 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ){ WhereTerm *pTerm; @@ -427,9 +436,15 @@ static WhereTerm *findTerm( /* ** The input to this routine is an WhereTerm structure with only the -** "p" field filled in. The job of this routine is to analyze the +** "pExpr" field filled in. The job of this routine is to analyze the ** subexpression and populate all the other fields of the WhereTerm ** structure. +** +** If the expression is of the form " X" it gets commuted +** to the standard form of "X ". If the expression is of +** the form "X Y" where both X and Y are columns, then the original +** expression is unchanged and a new virtual expression of the form +** "Y X" is added to the WHERE clause. */ static void exprAnalyze( SrcList *pSrc, /* the FROM clause */ @@ -455,6 +470,13 @@ static void exprAnalyze( pTerm->leftCursor = pLeft->iTable; pTerm->leftColumn = pLeft->iColumn; pTerm->operator = operatorMask(pExpr->op); + if( pTerm->operator==WO_IN ){ + if( pExpr->pSelect ){ + pTerm->operator |= WO_SELECT; + }else if( pExpr->pList ){ + pTerm->operator |= WO_LIST; + } + } } if( pRight && pRight->op==TK_COLUMN ){ WhereTerm *pNew; @@ -598,25 +620,22 @@ static int sortableByRowid( } /* -** Value for flags returned by bestIndex() -*/ -#define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */ -#define WHERE_ROWID_RANGE 0x0002 /* rowidEXPR */ -#define WHERE_COLUMN_EQ 0x0004 /* x=EXPR or x IN (...) */ -#define WHERE_COLUMN_RANGE 0x0008 /* xEXPR */ -#define WHERE_SCAN 0x0010 /* Do a full table scan */ -#define WHERE_REVERSE 0x0020 /* Scan in reverse order */ -#define WHERE_ORDERBY 0x0040 /* Output will appear in correct order */ -#define WHERE_IDX_ONLY 0x0080 /* Use index only - omit table */ -#define WHERE_TOP_LIMIT 0x0100 /* xEXPR or x>=EXPR constraint */ -#define WHERE_USES_IN 0x0400 /* True if the IN operator is used */ -#define WHERE_UNIQUE 0x0800 /* True if fully specifies a unique idx */ - -/* -** Find the best index for accessing a particular table. Return the index, -** flags that describe how the index should be used, and the "score" for -** this index. +** Find the best index for accessing a particular table. Return a pointer +** to the index, flags that describe how the index should be used, the +** number of equality constraints and the "cost" for this index. +** +** The lowest cost index wins. The cost is an estimate of the amount of +** CPU and disk I/O need to process the request using the selected index. +** Factors that influence cost include: +** +** * The estimated number of rows that will be retrieved. (The +** fewer the better.) +** +** * Whether or not sorting must occur. +** +** * Whether or not there must be separate lookups in the +** index and in the main table. +** */ static double bestIndex( Parse *pParse, /* The parsing context */ @@ -625,137 +644,146 @@ static double bestIndex( Bitmask notReady, /* Mask of cursors that are not available */ ExprList *pOrderBy, /* The order by clause */ Index **ppIndex, /* Make *ppIndex point to the best index */ - int *pFlags /* Put flags describing this choice in *pFlags */ + int *pFlags, /* Put flags describing this choice in *pFlags */ + int *pnEq /* Put the number of == or IN constraints here */ ){ WhereTerm *pTerm; - Index *pProbe; - Index *bestIdx = 0; - double bestScore = 0.0; - int bestFlags = 0; - int iCur = pSrc->iCursor; - int rev; - - /* Check for a rowid=EXPR or rowid IN (...) constraint + Index *bestIdx = 0; /* Index that gives the lowest cost */ + double lowestCost = 1.0e99; /* The cost of using bestIdx */ + int bestFlags = 0; /* Flags associated with bestIdx */ + int bestNEq = 0; /* Best value for nEq */ + int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ + Index *pProbe; /* An index we are evaluating */ + int rev; /* True to scan in reverse order */ + int flags; /* Flags associated with pProbe */ + int nEq; /* Number of == or IN constraints */ + double cost; /* Cost of using pProbe */ + + TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady)); + + /* Check for a rowid=EXPR or rowid IN (...) constraints */ pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); if( pTerm ){ *ppIndex = 0; + bestFlags = WHERE_ROWID_EQ; if( pTerm->operator & WO_EQ ){ *pFlags = WHERE_ROWID_EQ; + *pnEq = 1; if( pOrderBy ) *pFlags |= WHERE_ORDERBY; - return 1.0e10; + TRACE(("... best is rowid\n")); + return 0.0; + }else if( pTerm->operator & WO_LIST ){ + lowestCost = pTerm->pExpr->pList->nExpr; }else{ - *pFlags = WHERE_ROWID_EQ | WHERE_USES_IN; - return 1.0e9; + lowestCost = 100.0; } + TRACE(("... rowid IN cost: %g\n", lowestCost)); } - /* Check for constraints on a range of rowids + /* Check for constraints on a range of rowids or a full table scan. */ + pProbe = pSrc->pTab->pIndex; + cost = pProbe ? pProbe->aiRowEst[0] : 100000.0; + TRACE(("... base cost: %g\n", cost)); pTerm = findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE|WO_GT|WO_GE, 0); if( pTerm ){ - int flags; - *ppIndex = 0; - if( pTerm->operator & (WO_LT|WO_LE) ){ - flags = WHERE_ROWID_RANGE | WHERE_TOP_LIMIT; - if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){ - flags |= WHERE_BTM_LIMIT; - } - }else{ - flags = WHERE_ROWID_RANGE | WHERE_BTM_LIMIT; - if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){ - flags |= WHERE_TOP_LIMIT; - } + flags = WHERE_ROWID_RANGE; + if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){ + flags |= WHERE_TOP_LIMIT; + cost *= 0.25; /* Guess that rowidEXPR eliminates 75% of the search */ + } + TRACE(("... rowid range cost: %g\n", cost)); + }else{ + flags = 0; + } + if( pOrderBy && sortableByRowid(iCur, pOrderBy, &rev) ){ + flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE; + cost *= 0.5; + if( rev ){ + flags |= WHERE_REVERSE; } - bestScore = 99.0; + TRACE(("... order by reduces cost to %g\n", cost)); + } + if( costpTab->pIndex; pProbe; pProbe=pProbe->pNext){ - int i; - int nEq; - int usesIN = 0; - int flags; - double score = 0.0; + for(; pProbe; pProbe=pProbe->pNext){ + int i; /* Loop counter */ + double inMultiplier = 2.0; /* Includes built-in index lookup penalty */ + + TRACE(("... index %s:\n", pProbe->zName)); /* Count the number of columns in the index that are satisfied ** by x=EXPR constraints or x IN (...) constraints. */ + flags = 0; for(i=0; inColumn; i++){ int j = pProbe->aiColumn[i]; pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe); if( pTerm==0 ) break; - if( pTerm->operator==WO_IN ){ - if( i==0 ) usesIN = 1; - break; + flags |= WHERE_COLUMN_EQ; + if( pTerm->operator & WO_IN ){ + flags |= WHERE_COLUMN_IN; + if( pTerm->operator & WO_SELECT ){ + inMultiplier *= 100.0; + }else if( pTerm->operator & WO_LIST ){ + inMultiplier *= pTerm->pExpr->pList->nExpr + 1.0; + } } } - nEq = i + usesIN; - score = i*100.0 + usesIN*50.0; - - /* The optimization type is RANGE if there are no == or IN constraints - */ - if( usesIN ){ - flags = WHERE_COLUMN_EQ | WHERE_USES_IN; - }else if( nEq ){ - flags = WHERE_COLUMN_EQ; - }else{ - flags = WHERE_COLUMN_RANGE; - } - - /* Check for a uniquely specified row - */ -#if 0 - if( nEq==pProbe->nColumn && pProbe->isUnique ){ - flags |= WHERE_UNIQUE; - } -#endif + cost = pProbe->aiRowEst[i] * inMultiplier; + nEq = i; + TRACE(("...... nEq=%d inMult=%g cost=%g\n", nEq, inMultiplier, cost)); /* Look for range constraints */ - if( !usesIN && nEqnColumn ){ + if( nEqnColumn ){ int j = pProbe->aiColumn[nEq]; pTerm = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pProbe); if( pTerm ){ - score += 20.0; flags = WHERE_COLUMN_RANGE; - if( pTerm->operator & (WO_LT|WO_LE) ){ + if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){ flags |= WHERE_TOP_LIMIT; - if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){ - flags |= WHERE_BTM_LIMIT; - score += 20.0; - } - }else{ + cost *= 0.5; + } + if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){ flags |= WHERE_BTM_LIMIT; - if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){ - flags |= WHERE_TOP_LIMIT; - score += 20; - } + cost *= 0.5; } + TRACE(("...... range reduces cost to %g\n", cost)); } } - /* Add extra points if this index can be used to satisfy the ORDER BY - ** clause + /* Reduce the cost substantially if this index can be used to satisfy + ** the ORDER BY clause */ - if( pOrderBy && !usesIN && + if( pOrderBy && (flags & WHERE_COLUMN_IN)==0 && isSortingIndex(pParse, pProbe, pSrc->pTab, iCur, pOrderBy, nEq, &rev) ){ + if( flags==0 ){ + flags = WHERE_COLUMN_RANGE; + } flags |= WHERE_ORDERBY; - score += 10.0; - if( rev ) flags |= WHERE_REVERSE; + cost *= 0.5; + if( rev ){ + flags |= WHERE_REVERSE; + } + TRACE(("...... orderby reduces cost to %g\n", cost)); } /* Check to see if we can get away with using just the index without - ** ever reading the table. If that is the case, then add one bonus - ** point to the score. + ** ever reading the table. If that is the case, then halve the + ** cost of this index. */ - if( score>0.0 && pSrc->colUsed < (((Bitmask)1)<<(BMS-1)) ){ + if( flags && pSrc->colUsed < (((Bitmask)1)<<(BMS-1)) ){ Bitmask m = pSrc->colUsed; int j; for(j=0; jnColumn; j++){ @@ -766,32 +794,32 @@ static double bestIndex( } if( m==0 ){ flags |= WHERE_IDX_ONLY; - score += 5; + cost *= 0.5; + TRACE(("...... idx-only reduces cost to %g\n", cost)); } } - /* If this index has achieved the best score so far, then use it. + /* If this index has achieved the lowest cost so far, then use it. */ - if( score>bestScore ){ + if( cost < lowestCost ){ bestIdx = pProbe; - bestScore = score; + lowestCost = cost; + if( flags==0 ){ + flags = WHERE_COLUMN_RANGE; + } bestFlags = flags; + bestNEq = nEq; } } - /* Disable sorting if we are coming out in rowid order - */ - if( bestIdx==0 && pOrderBy && sortableByRowid(iCur, pOrderBy, &rev) ){ - bestFlags |= WHERE_ORDERBY; - if( rev ) bestFlags |= WHERE_REVERSE; - } - - /* Report the best result */ *ppIndex = bestIdx; + TRACE(("best index is %s, cost=%g, flags=%x, nEq=%d\n", + bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq)); *pFlags = bestFlags; - return bestScore; + *pnEq = bestNEq; + return lowestCost; } @@ -850,8 +878,15 @@ static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){ /* -** Generate code for an equality term of the WHERE clause. An equality -** term can be either X=expr or X IN (...). pTerm is the X. +** Generate code for a single equality term of the WHERE clause. An equality +** term can be either X=expr or X IN (...). pTerm is the term to be +** coded. +** +** The current value for the constraint is left on the top of the stack. +** +** For a constraint of the form X=expr, the expression is evaluated and its +** result is left on the stack. For constraints of the form X IN (...) +** this routine sets up a loop that will iterate over all values of X. */ static void codeEqualityTerm( Parse *pParse, /* The parsing context */ @@ -887,6 +922,78 @@ static void codeEqualityTerm( disableTerm(pLevel, pTerm); } +/* +** Generate code that will evaluate all == and IN constraints for an +** index. The values for all constraints are left on the stack. +** +** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c). +** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10 +** The index has as many as three equality constraints, but in this +** example, the third "c" value is an inequality. So only two +** constraints are coded. This routine will generate code to evaluate +** a==5 and b IN (1,2,3). The current values for a and b will be left +** on the stack - a is the deepest and b the shallowest. +** +** In the example above nEq==2. But this subroutine works for any value +** of nEq including 0. If nEq==0, this routine is nearly a no-op. +** The only thing it does is allocate the pLevel->iMem memory cell. +** +** This routine always allocates at least one memory cell and puts +** the address of that memory cell in pLevel->iMem. The code that +** calls this routine will use pLevel->iMem to store the termination +** key value of the loop. If one or more IN operators appear, then +** this routine allocates an additional nEq memory cells for internal +** use. +*/ +static void codeAllEqualityTerms( + Parse *pParse, /* Parsing context */ + WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ + WhereClause *pWC, /* The WHERE clause */ + Bitmask notReady, /* Which parts of FROM have not yet been coded */ + int brk /* Jump here to end the loop */ +){ + int nEq = pLevel->nEq; /* The number of == or IN constraints to code */ + int termsInMem = 0; /* If true, store value in mem[] cells */ + Vdbe *v = pParse->pVdbe; /* The virtual machine under construction */ + Index *pIdx = pLevel->pIdx; /* The index being used for this loop */ + int iCur = pLevel->iTabCur; /* The cursor of the table */ + WhereTerm *pTerm; /* A single constraint term */ + int j; /* Loop counter */ + + /* Figure out how many memory cells we will need then allocate them. + ** We always need at least one used to store the loop terminator + ** value. If there are IN operators we'll need one for each == or + ** IN constraint. + */ + pLevel->iMem = pParse->nMem++; + if( pLevel->flags & WHERE_COLUMN_IN ){ + pParse->nMem += pLevel->nEq; + termsInMem = 1; + } + + /* Evaluate the equality constraints + */ + for(j=0; 1; j++){ + int k = pIdx->aiColumn[j]; + pTerm = findTerm(pWC, iCur, k, notReady, WO_EQ|WO_IN, pIdx); + if( pTerm==0 ) break; + assert( (pTerm->flags & TERM_CODED)==0 ); + codeEqualityTerm(pParse, pTerm, brk, pLevel); + if( termsInMem ){ + sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1); + } + } + assert( j==nEq ); + + /* Make sure all the constraint values are on the top of the stack + */ + if( termsInMem ){ + for(j=0; jiMem+j+1, 0); + } + } +} + #ifdef SQLITE_TEST /* ** The following variable holds a text description of query plan generated @@ -929,7 +1036,9 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */ ** ** Note that the loops might not be nested in the order in which they ** appear in the FROM clause if a different order is better able to make -** use of indices. +** use of indices. Note also that when the IN operator appears in +** the WHERE clause, it might result in additional nested loops for +** scanning through all values on the right-hand side of the IN. ** ** There are Btree cursors associated with each table. t1 uses cursor ** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor. @@ -1004,7 +1113,6 @@ WhereInfo *sqlite3WhereBegin( struct SrcList_item *pTabItem; /* A single entry from pTabList */ WhereLevel *pLevel; /* A single level in the pWInfo list */ int iFrom; /* First unused FROM clause element */ - WhereConstraint *aConstraint; /* Information on constraints */ /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask @@ -1051,17 +1159,20 @@ WhereInfo *sqlite3WhereBegin( for(i=wc.nTerm-1; i>=0; i--){ exprAnalyze(pTabList, &maskSet, &wc.a[i]); } - aConstraint = sqliteMalloc( wc.nTerm*sizeof(aConstraint[0]) ); - if( aConstraint==0 && wc.nTerm>0 ){ - goto whereBeginNoMem; - } /* Chose the best index to use for each table in the FROM clause. ** - ** This loop fills in the pWInfo->a[].pIdx and pWInfo->a[].flags fields - ** with information - ** Reorder tables if necessary in order to choose a good ordering. - ** However, LEFT JOIN tables cannot be reordered. + ** This loop fills in the following fields: + ** + ** 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[].iTabCur The VDBE cursor for the database table + ** pWInfo->a[].iIdxCur The VDBE cursor for the index + ** + ** This loop also figures out the nesting order of tables in the FROM + ** clause. */ notReady = ~(Bitmask)0; pTabItem = pTabList->a; @@ -1069,11 +1180,13 @@ WhereInfo *sqlite3WhereBegin( for(i=iFrom=0, pLevel=pWInfo->a; inSrc; i++, pLevel++){ Index *pIdx; /* Index for FROM table at pTabItem */ int flags; /* Flags asssociated with pIdx */ - double score; /* The score for pIdx */ + int nEq; /* Number of == or IN constraints */ + double cost; /* The cost for pIdx */ int j; /* For looping over FROM tables */ Index *pBest = 0; /* The best index seen so far */ int bestFlags = 0; /* Flags associated with pBest */ - double bestScore = -1.0; /* The score of pBest */ + int bestNEq = 0; /* nEq associated with pBest */ + double lowestCost = 1.0e99; /* Cost of the pBest */ int bestJ; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ @@ -1083,13 +1196,14 @@ WhereInfo *sqlite3WhereBegin( if( j==iFrom ) iFrom++; continue; } - score = bestIndex(pParse, &wc, pTabItem, notReady, - (j==0 && ppOrderBy) ? *ppOrderBy : 0, - &pIdx, &flags); - if( score>bestScore ){ - bestScore = score; + cost = bestIndex(pParse, &wc, pTabItem, notReady, + (j==0 && ppOrderBy) ? *ppOrderBy : 0, + &pIdx, &flags, &nEq); + if( costjointype & JT_LEFT)!=0 @@ -1103,6 +1217,7 @@ WhereInfo *sqlite3WhereBegin( } pLevel->flags = bestFlags; pLevel->pIdx = pBest; + pLevel->nEq = bestNEq; pLevel->aInLoop = 0; pLevel->nIn = 0; if( pBest ){ @@ -1200,61 +1315,8 @@ WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk); VdbeComment((v, "pk")); pLevel->op = OP_Noop; - }else if( pLevel->flags & WHERE_COLUMN_EQ ){ - /* 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; - - /* For each column of the index, find the term of the WHERE clause that - ** constraints that column. If the WHERE clause term is X=expr, then - ** generate code to evaluate expr and leave the result on the stack */ - for(j=0; 1; j++){ - int k = pIdx->aiColumn[j]; - pTerm = findTerm(&wc, iCur, k, notReady, WO_EQ|WO_IN, pIdx); - if( pTerm==0 ) break; - if( pTerm->operator==WO_IN && j>0 ) break; - assert( (pTerm->flags & TERM_CODED)==0 ); - codeEqualityTerm(pParse, pTerm, brk, pLevel); - if( pTerm->operator==WO_IN ){ - j++; - break; - } - } - nColumn = j; - pLevel->iMem = pParse->nMem++; - buildIndexProbe(v, nColumn, brk, pIdx); - sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0); - - /* Generate code (1) to move to the first matching element of the table. - ** Then generate code (2) that jumps to "brk" after the cursor is past - ** the last matching element of the table. The code (1) is executed - ** once to initialize the search, the code (2) is executed before each - ** iteration of the scan to see if the scan has finished. */ - if( bRev ){ - /* Scan in reverse order */ - sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk); - start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); - sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, brk); - pLevel->op = OP_Prev; - }else{ - /* Scan in the forward order */ - sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, brk); - start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); - sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC); - pLevel->op = OP_Next; - } - sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0); - sqlite3VdbeAddOp(v, OP_IdxIsNull, nColumn, cont); - if( !omitTable ){ - sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0); - sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); - } - pLevel->p1 = iIdxCur; - pLevel->p2 = start; }else if( pLevel->flags & WHERE_ROWID_RANGE ){ - /* Case 3: We have an inequality comparison against the ROWID field. + /* Case 2: We have an inequality comparison against the ROWID field. */ int testOp = OP_Noop; int start; @@ -1273,7 +1335,6 @@ WhereInfo *sqlite3WhereBegin( }else{ pEnd = 0; } - assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; pStart = pEnd; @@ -1317,42 +1378,35 @@ WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp(v, testOp, 'n', brk); } }else if( pLevel->flags & WHERE_COLUMN_RANGE ){ - /* Case 4: The WHERE clause term that refers to the right-most + /* Case 3: The WHERE clause term that refers to the right-most ** column of the index is an inequality. For example, if ** the index is on (x,y,z) and the WHERE clause is of the ** form "x=5 AND y<10" then this case is used. Only the ** right-most column can be an inequality - the rest must - ** use the "==" operator. + ** use the "==" and "IN" operators. ** ** This case is also used when there are no WHERE clause ** constraints but an index is selected anyway, in order ** to force the output order to conform to an ORDER BY. */ - int nEqColumn; int start; + int nEq = pLevel->nEq; int leFlag=0, geFlag=0; int testOp; int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0; int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0; - /* Evaluate the equality constraints + /* Generate code to evaluate all constraint terms using == or IN + ** and level the values of those terms on the stack. */ - for(j=0; 1; j++){ - int k = pIdx->aiColumn[j]; - pTerm = findTerm(&wc, iCur, k, notReady, WO_EQ, pIdx); - if( pTerm==0 ) break; - assert( (pTerm->flags & TERM_CODED)==0 ); - sqlite3ExprCode(pParse, pTerm->pExpr->pRight); - disableTerm(pLevel, pTerm); - } - nEqColumn = j; + codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk); /* Duplicate the equality term values because they will all be ** used twice: once to make the termination key and once to make the ** start key. */ - for(j=0; j0 ? OP_IdxGE : OP_Noop; + testOp = nEq>0 ? OP_IdxGE : OP_Noop; leFlag = 1; } if( testOp!=OP_Noop ){ - int nCol = nEqColumn + topLimit; + int nCol = nEq + topLimit; pLevel->iMem = pParse->nMem++; buildIndexProbe(v, nCol, brk, pIdx); if( bRev ){ @@ -1413,8 +1467,8 @@ WhereInfo *sqlite3WhereBegin( }else{ geFlag = 1; } - if( nEqColumn>0 || btmLimit ){ - int nCol = nEqColumn + btmLimit; + if( nEq>0 || btmLimit ){ + int nCol = nEq + btmLimit; buildIndexProbe(v, nCol, brk, pIdx); if( bRev ){ pLevel->iMem = pParse->nMem++; @@ -1443,7 +1497,7 @@ WhereInfo *sqlite3WhereBegin( } } sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0); - sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + topLimit, cont); + sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq + topLimit, cont); if( !omitTable ){ sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0); sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); @@ -1454,6 +1508,50 @@ WhereInfo *sqlite3WhereBegin( pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iIdxCur; pLevel->p2 = start; + }else if( pLevel->flags & WHERE_COLUMN_EQ ){ + /* Case 4: There is an index and all terms of the WHERE clause that + ** refer to the index using the "==" or "IN" operators. + */ + int start; + int nEq = pLevel->nEq; + + /* Generate code to evaluate all constraint terms using == or IN + ** and level the values of those terms on the stack. + */ + codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk); + + /* Generate a single key that will be used to both start and terminate + ** the search + */ + buildIndexProbe(v, nEq, brk, pIdx); + sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0); + + /* Generate code (1) to move to the first matching element of the table. + ** Then generate code (2) that jumps to "brk" after the cursor is past + ** the last matching element of the table. The code (1) is executed + ** once to initialize the search, the code (2) is executed before each + ** iteration of the scan to see if the scan has finished. */ + if( bRev ){ + /* Scan in reverse order */ + sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk); + start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); + sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, brk); + pLevel->op = OP_Prev; + }else{ + /* Scan in the forward order */ + sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, brk); + start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); + sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC); + pLevel->op = OP_Next; + } + sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0); + sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq, cont); + if( !omitTable ){ + sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0); + sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); + } + pLevel->p1 = iIdxCur; + pLevel->p2 = start; }else{ /* Case 5: There is no usable index. We must do a complete ** scan of the entire table. @@ -1559,7 +1657,6 @@ WhereInfo *sqlite3WhereBegin( */ pWInfo->iContinue = cont; whereClauseClear(&wc); - sqliteFree(aConstraint); return pWInfo; /* Jump here if malloc fails */