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
This commit is contained in:
drh
2005-07-23 22:59:55 +00:00
parent 17a18f2f36
commit 51147baa6d
7 changed files with 407 additions and 293 deletions
+10 -10
View File
@@ -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
+1 -1
View File
@@ -1 +1 @@
868279c78e056d27b2d1bea81127fe689b2ce478
86ce56ccea8297b1fba2b9ee53b5f1a3f228662f
+2 -5
View File
@@ -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 */
+17 -2
View File
@@ -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 <ctype.h>
@@ -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.
+4 -2
View File
@@ -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"
+4 -1
View File
@@ -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",
+369 -272
View File
@@ -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 <op> 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 <op> 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 <op> <expr>" */
i16 leftColumn; /* Column number of X in "X <op> <expr>" */
u8 operator; /* A WO_xx value describing <op> */
u16 operator; /* A WO_xx value describing <op> */
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 <expr> 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 /* rowid<EXPR and/or rowid>EXPR */
#define WHERE_COLUMN_EQ 0x0010 /* x=EXPR or x IN (...) */
#define WHERE_COLUMN_RANGE 0x0020 /* x<EXPR and/or x>EXPR */
#define WHERE_COLUMN_IN 0x0040 /* x IN (...) */
#define WHERE_TOP_LIMIT 0x0100 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x0200 /* x>EXPR 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 "<expr> <op> X" it gets commuted
** to the standard form of "X <op> <expr>". If the expression is of
** the form "X <op> Y" where both X and Y are columns, then the original
** expression is unchanged and a new virtual expression of the form
** "Y <op> 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 /* rowid<EXPR and/or rowid>EXPR */
#define WHERE_COLUMN_EQ 0x0004 /* x=EXPR or x IN (...) */
#define WHERE_COLUMN_RANGE 0x0008 /* x<EXPR and/or x>EXPR */
#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 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x0200 /* x>EXPR 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;
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 */
/* Check for a rowid=EXPR or rowid IN (...) constraint
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 rowid<EXPR eliminates 75% of the search */
}
if( pOrderBy && sortableByRowid(iCur, pOrderBy, &rev) ){
flags |= WHERE_ORDERBY;
if( rev ) flags |= WHERE_REVERSE;
if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){
flags |= WHERE_BTM_LIMIT;
cost *= 0.25; /* Guess that rowid>EXPR eliminates 75% of the search */
}
bestScore = 99.0;
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;
}
TRACE(("... order by reduces cost to %g\n", cost));
}
if( cost<lowestCost ){
lowestCost = cost;
bestFlags = flags;
}
/* Look at each index.
*/
for(pProbe=pSrc->pTab->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; i<pProbe->nColumn; 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;
}
}
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
/* Look for range constraints
*/
if( !usesIN && nEq<pProbe->nColumn ){
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) ){
flags |= WHERE_TOP_LIMIT;
if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){
flags |= WHERE_BTM_LIMIT;
score += 20.0;
}
}else{
flags |= WHERE_BTM_LIMIT;
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
flags |= WHERE_TOP_LIMIT;
score += 20;
}
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;
}
}
}
cost = pProbe->aiRowEst[i] * inMultiplier;
nEq = i;
TRACE(("...... nEq=%d inMult=%g cost=%g\n", nEq, inMultiplier, cost));
/* Add extra points if this index can be used to satisfy the ORDER BY
** clause
/* Look for range constraints
*/
if( pOrderBy && !usesIN &&
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pProbe);
if( pTerm ){
flags = WHERE_COLUMN_RANGE;
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
flags |= WHERE_TOP_LIMIT;
cost *= 0.5;
}
if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){
flags |= WHERE_BTM_LIMIT;
cost *= 0.5;
}
TRACE(("...... range reduces cost to %g\n", cost));
}
}
/* Reduce the cost substantially if this index can be used to satisfy
** the ORDER BY clause
*/
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; j<pProbe->nColumn; 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; j<nEq; j++){
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem+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; i<pTabList->nSrc; 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( cost<lowestCost ){
lowestCost = cost;
pBest = pIdx;
bestFlags = flags;
bestNEq = nEq;
bestJ = j;
}
if( (pTabItem->jointype & 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; j<nEqColumn; j++){
sqlite3VdbeAddOp(v, OP_Dup, nEqColumn-1, 0);
for(j=0; j<nEq; j++){
sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0);
}
/* Generate the termination key. This is the key value that
@@ -1374,11 +1428,11 @@ WhereInfo *sqlite3WhereBegin(
disableTerm(pLevel, pTerm);
testOp = OP_IdxGE;
}else{
testOp = nEqColumn>0 ? 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 */