?? where.c
字號:
** the wrong answer. See ticket #813.
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
if( pTerm
&& (pTerm->flags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
){
pTerm->flags |= TERM_CODED;
if( pTerm->iParent>=0 ){
WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent];
if( (--pOther->nChild)==0 ){
disableTerm(pLevel, pOther);
}
}
}
}
/*
** Generate code that builds a probe for an index. Details:
**
** * Check the top nColumn entries on the stack. If any
** of those entries are NULL, jump immediately to brk,
** which is the loop exit, since no index entry will match
** if any part of the key is NULL. Pop (nColumn+nExtra)
** elements from the stack.
**
** * Construct a probe entry from the top nColumn entries in
** the stack with affinities appropriate for index pIdx.
** Only nColumn elements are popped from the stack in this case
** (by OP_MakeRecord).
**
*/
static void buildIndexProbe(
Vdbe *v,
int nColumn,
int nExtra,
int brk,
Index *pIdx
){
sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx);
}
/*
** 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 */
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
int brk, /* Jump here to abandon the loop */
WhereLevel *pLevel /* When level of the FROM clause we are working on */
){
Expr *pX = pTerm->pExpr;
if( pX->op!=TK_IN ){
assert( pX->op==TK_EQ );
sqlite3ExprCode(pParse, pX->pRight);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
int iTab;
int *aIn;
Vdbe *v = pParse->pVdbe;
sqlite3CodeSubselect(pParse, pX);
iTab = pX->iTable;
sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
pLevel->nIn++;
sqliteReallocOrFree((void**)&pLevel->aInLoop,
sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
aIn = pLevel->aInLoop;
if( aIn ){
aIn += pLevel->nIn*2 - 2;
aIn[0] = iTab;
aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
}else{
pLevel->nIn = 0;
}
#endif
}
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; j<pIdx->nColumn; 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);
}
}
}
#if defined(SQLITE_TEST)
/*
** The following variable holds a text description of query plan generated
** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin
** overwrites the previous. This information is used for testing and
** analysis only.
*/
char sqlite3_query_plan[BMS*2*40]; /* Text of the join */
static int nQPlan = 0; /* Next free slow in _query_plan[] */
#endif /* SQLITE_TEST */
/*
** Free a WhereInfo structure
*/
static void whereInfoFree(WhereInfo *pWInfo){
if( pWInfo ){
int i;
for(i=0; i<pWInfo->nLevel; i++){
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
if( pInfo ){
if( pInfo->needToFreeIdxStr ){
sqlite3_free(pInfo->idxStr);
}
sqliteFree(pInfo);
}
}
sqliteFree(pWInfo);
}
}
/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
** should invoke sqlite3WhereEnd() with the return value of this function
** in order to complete the WHERE clause processing.
**
** If an error occurs, this routine returns NULL.
**
** The basic idea is to do a nested loop, one loop for each table in
** the FROM clause of a select. (INSERT and UPDATE statements are the
** same as a SELECT with only a single table in the FROM clause.) For
** example, if the SQL is this:
**
** SELECT * FROM t1, t2, t3 WHERE ...;
**
** Then the code generated is conceptually like the following:
**
** foreach row1 in t1 do \ Code generated
** foreach row2 in t2 do |-- by sqlite3WhereBegin()
** foreach row3 in t3 do /
** ...
** end \ Code generated
** end |-- by sqlite3WhereEnd()
** end /
**
** 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. 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.
** And so forth. This routine generates code to open those VDBE cursors
** and sqlite3WhereEnd() generates the code to close them.
**
** The code that sqlite3WhereBegin() generates leaves the cursors named
** in pTabList pointing at their appropriate entries. The [...] code
** can use OP_Column and OP_Rowid opcodes on these cursors to extract
** data from the various tables of the loop.
**
** If the WHERE clause is empty, the foreach loops must each scan their
** entire tables. Thus a three-way join is an O(N^3) operation. But if
** the tables have indices and there are terms in the WHERE clause that
** refer to those indices, a complete table scan can be avoided and the
** code will run much faster. Most of the work of this routine is checking
** to see if there are indices that can be used to speed up the loop.
**
** Terms of the WHERE clause are also used to limit which rows actually
** make it to the "..." in the middle of the loop. After each "foreach",
** terms of the WHERE clause that use only terms in that loop and outer
** loops are evaluated and if false a jump is made around all subsequent
** inner loops (or around the "..." if the test occurs within the inner-
** most loop)
**
** OUTER JOINS
**
** An outer join of tables t1 and t2 is conceptally coded as follows:
**
** foreach row1 in t1 do
** flag = 0
** foreach row2 in t2 do
** start:
** ...
** flag = 1
** end
** if flag==0 then
** move the row2 cursor to a null row
** goto start
** fi
** end
**
** ORDER BY CLAUSE PROCESSING
**
** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
** if there is one. If there is no ORDER BY clause or if this routine
** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL.
**
** If an index can be used so that the natural output order of the table
** scan is correct for the ORDER BY clause, then that index is used and
** *ppOrderBy is set to NULL. This is an optimization that prevents an
** unnecessary sort of the result set if an index appropriate for the
** ORDER BY clause already exists.
**
** If the where clause loops cannot be arranged to provide the correct
** output order, then the *ppOrderBy is unchanged.
*/
WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
){
int i; /* Loop counter */
WhereInfo *pWInfo; /* Will become the return value of this function */
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
int brk, cont = 0; /* Addresses used during code generation */
Bitmask notReady; /* Cursors that are not yet positioned */
WhereTerm *pTerm; /* A single term in the WHERE clause */
ExprMaskSet maskSet; /* The expression mask set */
WhereClause wc; /* The WHERE clause is divided into these terms */
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 */
int andFlags; /* AND-ed combination of all wc.a[].flags */
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
*/
if( pTabList->nSrc>BMS ){
sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
return 0;
}
/* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator.
*/
initMaskSet(&maskSet);
whereClauseInit(&wc, pParse);
whereSplit(&wc, pWhere, TK_AND);
/* Allocate and initialize the WhereInfo structure that will become the
** return value.
*/
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
if( sqlite3MallocFailed() ){
goto whereBeginNoMem;
}
pWInfo->nLevel = pTabList->nSrc;
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
/* Special case: a WHERE clause that is constant. Evaluate the
** expression and either jump over all of the code or fall thru.
*/
if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstant(pWhere)) ){
sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
pWhere = 0;
}
/* Analyze all of the subexpressions. Note that exprAnalyze() might
** add new virtual terms onto the end of the WHERE clause. We do not
** want to analyze these virtual terms, so start analyzing at the end
** and work forward so that the added virtual terms are never processed.
*/
for(i=0; i<pTabList->nSrc; i++){
createMask(&maskSet, pTabList->a[i].iCursor);
}
exprAnalyzeAll(pTabList, &maskSet, &wc);
if( sqlite3MallocFailed() ){
goto whereBeginNoMem;
}
/* Chose the best index to use for each table in the FROM clause.
**
** 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
** pWIn
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -