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:
@@ -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
@@ -1 +1 @@
|
||||
868279c78e056d27b2d1bea81127fe689b2ce478
|
||||
86ce56ccea8297b1fba2b9ee53b5f1a3f228662f
|
||||
+2
-5
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user