mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-09 14:21:03 +03:00
Refactoring of the query optimizer in advance of adding better optimization. (CVS 2551)
FossilOrigin-Name: 57c6bd3760163c174be4a2ece58f414e82b55938
This commit is contained in:
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Allow\san\sunlimited\snumber\sof\sterms\sin\sthe\sWHERE\sclause.\s\sThe\sold\slimit\swas\s100.\s(CVS\s2550)
|
C Refactoring\sof\sthe\squery\soptimizer\sin\sadvance\sof\sadding\sbetter\soptimization.\s(CVS\s2551)
|
||||||
D 2005-07-16T13:33:21
|
D 2005-07-19T17:38:23
|
||||||
F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
|
F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
|
||||||
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
|
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
@@ -64,7 +64,7 @@ F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
|
|||||||
F src/select.c c611471052773b94af771693686bd5bcdbbb0dba
|
F src/select.c c611471052773b94af771693686bd5bcdbbb0dba
|
||||||
F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
|
F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
|
||||||
F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe
|
F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe
|
||||||
F src/sqliteInt.h af65e8fac1fe8f6f78a65551081bafd49f6e0650
|
F src/sqliteInt.h 97d50f5714a5f5a8190b871305e33a96c4638a8a
|
||||||
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
||||||
F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830
|
F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830
|
||||||
F src/test1.c 1dea8df4abb846cb3a2ce8a6e13d8b32dbd31b16
|
F src/test1.c 1dea8df4abb846cb3a2ce8a6e13d8b32dbd31b16
|
||||||
@@ -85,7 +85,7 @@ F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6
|
|||||||
F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
|
F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
|
||||||
F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
|
F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
|
||||||
F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
|
F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
|
||||||
F src/where.c 9b02e75ef86f057cee5e93150b10cbc1092d7de6
|
F src/where.c 1da2268f5e37257276dff46ebbc1cc596a9efaa1
|
||||||
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
|
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
|
||||||
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
|
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
|
||||||
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
|
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
|
||||||
@@ -286,7 +286,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
||||||
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
|
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
|
||||||
P 578490c91331a386f84652db0b3bfd74c82046e1
|
P ca69f36832d57775e73ac5cdbe0a32d7b759432b
|
||||||
R 544e009ea316e2cccd816cc597a10aab
|
R 9a4258be8ecf1889fef260cdd1d2d34b
|
||||||
U drh
|
U drh
|
||||||
Z 0b48c3e07c6ac902e7fb79f1e0cbf3a1
|
Z a631f1b7791a9c3a4f6bac427d47518f
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
ca69f36832d57775e73ac5cdbe0a32d7b759432b
|
57c6bd3760163c174be4a2ece58f414e82b55938
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.393 2005/07/09 02:16:03 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.394 2005/07/19 17:38:23 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -845,7 +845,6 @@ struct Expr {
|
|||||||
#define EP_Error 0x08 /* Expression contains one or more errors */
|
#define EP_Error 0x08 /* Expression contains one or more errors */
|
||||||
#define EP_Not 0x10 /* Operator preceeded by NOT */
|
#define EP_Not 0x10 /* Operator preceeded by NOT */
|
||||||
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
|
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
|
||||||
#define EP_OptOnly 0x40 /* A constraint used by the optimizer only */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** These macros can be used to test, set, or clear bits in the
|
** These macros can be used to test, set, or clear bits in the
|
||||||
|
|||||||
341
src/where.c
341
src/where.c
@@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** indices, you might also think of this module as the "query optimizer".
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.145 2005/07/16 13:33:21 drh Exp $
|
** $Id: where.c,v 1.146 2005/07/19 17:38:23 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -30,22 +30,29 @@
|
|||||||
*/
|
*/
|
||||||
#define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
|
#define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
|
||||||
|
|
||||||
|
/* Forward reference
|
||||||
|
*/
|
||||||
|
typedef struct WhereClause WhereClause;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The query generator uses an array of instances of this structure to
|
** The query generator uses an array of instances of this structure to
|
||||||
** help it analyze the subexpressions of the WHERE clause. Each WHERE
|
** help it analyze the subexpressions of the WHERE clause. Each WHERE
|
||||||
** clause subexpression is separated from the others by an AND operator.
|
** clause subexpression is separated from the others by an AND operator.
|
||||||
**
|
**
|
||||||
** The idxLeft and idxRight fields are the VDBE cursor numbers for the
|
** All WhereTerms are collected into a single WhereClause structure.
|
||||||
** table that contains the column that appears on the left-hand and
|
** The following identity holds:
|
||||||
** right-hand side of WhereTerm.p. If either side of WhereTerm.p is
|
|
||||||
** something other than a simple column reference, then idxLeft or
|
|
||||||
** idxRight are -1.
|
|
||||||
**
|
**
|
||||||
** It is the VDBE cursor number is the value stored in Expr.iTable
|
** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm
|
||||||
** when Expr.op==TK_COLUMN and the value stored in SrcList.a[].iCursor.
|
|
||||||
**
|
**
|
||||||
** prereqLeft, prereqRight, and prereqAll record sets of cursor numbers,
|
** When a term is of the form:
|
||||||
|
**
|
||||||
|
** X <op> <expr>
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** prereqRight and prereqAll record sets of cursor numbers,
|
||||||
** but they do so indirectly. A single ExprMaskSet structure translates
|
** but they do so indirectly. A single ExprMaskSet structure translates
|
||||||
** cursor number into bits and the translated bit is stored in the prereq
|
** cursor number into bits and the translated bit is stored in the prereq
|
||||||
** fields. The translation is used in order to maximize the number of
|
** fields. The translation is used in order to maximize the number of
|
||||||
@@ -56,34 +63,17 @@
|
|||||||
** beginning with 0 in order to make the best possible use of the available
|
** beginning with 0 in order to make the best possible use of the available
|
||||||
** bits in the Bitmask. So, in the example above, the cursor numbers
|
** bits in the Bitmask. So, in the example above, the cursor numbers
|
||||||
** would be mapped into integers 0 through 7.
|
** would be mapped into integers 0 through 7.
|
||||||
**
|
|
||||||
** prereqLeft tells us every VDBE cursor that is referenced on the
|
|
||||||
** left-hand side of WhereTerm.p. prereqRight does the same for the
|
|
||||||
** right-hand side of the expression. The following identity always
|
|
||||||
** holds:
|
|
||||||
**
|
|
||||||
** prereqAll = prereqLeft | prereqRight
|
|
||||||
**
|
|
||||||
** The WhereTerm.indexable field is true if the WhereTerm.p expression
|
|
||||||
** is of a form that might control an index. Indexable expressions
|
|
||||||
** look like this:
|
|
||||||
**
|
|
||||||
** <column> <op> <expr>
|
|
||||||
**
|
|
||||||
** Where <column> is a simple column name and <op> is on of the operators
|
|
||||||
** that allowedOp() recognizes.
|
|
||||||
*/
|
*/
|
||||||
typedef struct WhereTerm WhereTerm;
|
typedef struct WhereTerm WhereTerm;
|
||||||
struct WhereTerm {
|
struct WhereTerm {
|
||||||
Expr *p; /* Pointer to the subexpression */
|
Expr *pExpr; /* Pointer to the subexpression */
|
||||||
|
u16 idx; /* Index of this term in pWC->a[] */
|
||||||
|
i16 iPartner; /* Disable pWC->a[iPartner] when this term disabled */
|
||||||
u16 flags; /* Bit flags. See below */
|
u16 flags; /* Bit flags. See below */
|
||||||
u8 indexable; /* True if this subexprssion is usable by an index */
|
i16 leftCursor; /* Cursor number of X in "X <op> <expr>" */
|
||||||
short int idxLeft; /* p->pLeft is a column in this table number. -1 if
|
i16 leftColumn; /* Column number of X in "X <op> <expr>" */
|
||||||
** p->pLeft is not a column of any table */
|
WhereClause *pWC; /* The clause this term is part of */
|
||||||
short int idxRight; /* p->pRight is a column in this table number. -1 if
|
Bitmask prereqRight; /* Bitmask of tables used by pRight */
|
||||||
** p->pRight is not a column of any table */
|
|
||||||
Bitmask prereqLeft; /* Bitmask of tables referenced by p->pLeft */
|
|
||||||
Bitmask prereqRight; /* Bitmask of tables referenced by p->pRight */
|
|
||||||
Bitmask prereqAll; /* Bitmask of tables referenced by p */
|
Bitmask prereqAll; /* Bitmask of tables referenced by p */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,12 +82,12 @@ struct WhereTerm {
|
|||||||
*/
|
*/
|
||||||
#define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(p) */
|
#define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(p) */
|
||||||
#define TERM_VIRTUAL 0x0002 /* Added by the optimizer. Do not code */
|
#define TERM_VIRTUAL 0x0002 /* Added by the optimizer. Do not code */
|
||||||
|
#define TERM_CODED 0x0004 /* This term is already coded */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An instance of the following structure holds all information about a
|
** An instance of the following structure holds all information about a
|
||||||
** WHERE clause. Mostly this is a container for one or more WhereTerms.
|
** WHERE clause. Mostly this is a container for one or more WhereTerms.
|
||||||
*/
|
*/
|
||||||
typedef struct WhereClause WhereClause;
|
|
||||||
struct WhereClause {
|
struct WhereClause {
|
||||||
int nTerm; /* Number of terms */
|
int nTerm; /* Number of terms */
|
||||||
int nSlot; /* Number of entries in a[] */
|
int nSlot; /* Number of entries in a[] */
|
||||||
@@ -156,7 +146,7 @@ static void whereClauseClear(WhereClause *pWC){
|
|||||||
WhereTerm *a;
|
WhereTerm *a;
|
||||||
for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
|
for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
|
||||||
if( a->flags & TERM_DYNAMIC ){
|
if( a->flags & TERM_DYNAMIC ){
|
||||||
sqlite3ExprDelete(a->p);
|
sqlite3ExprDelete(a->pExpr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( pWC->a!=pWC->aStatic ){
|
if( pWC->a!=pWC->aStatic ){
|
||||||
@@ -168,21 +158,26 @@ static void whereClauseClear(WhereClause *pWC){
|
|||||||
** Add a new entries to the WhereClause structure. Increase the allocated
|
** Add a new entries to the WhereClause structure. Increase the allocated
|
||||||
** space as necessary.
|
** space as necessary.
|
||||||
*/
|
*/
|
||||||
static void whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
|
static WhereTerm *whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
|
||||||
WhereTerm *pTerm;
|
WhereTerm *pTerm;
|
||||||
if( pWC->nTerm>=pWC->nSlot ){
|
if( pWC->nTerm>=pWC->nSlot ){
|
||||||
WhereTerm *pOld = pWC->a;
|
WhereTerm *pOld = pWC->a;
|
||||||
pWC->a = sqliteMalloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
|
pWC->a = sqliteMalloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
|
||||||
if( pWC->a==0 ) return;
|
if( pWC->a==0 ) return 0;
|
||||||
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
|
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
|
||||||
if( pOld!=pWC->aStatic ){
|
if( pOld!=pWC->aStatic ){
|
||||||
sqliteFree(pOld);
|
sqliteFree(pOld);
|
||||||
}
|
}
|
||||||
pWC->nSlot *= 2;
|
pWC->nSlot *= 2;
|
||||||
}
|
}
|
||||||
pTerm = &pWC->a[pWC->nTerm++];
|
pTerm = &pWC->a[pWC->nTerm];
|
||||||
pTerm->p = p;
|
pTerm->idx = pWC->nTerm;
|
||||||
|
pWC->nTerm++;
|
||||||
|
pTerm->pExpr = p;
|
||||||
pTerm->flags = flags;
|
pTerm->flags = flags;
|
||||||
|
pTerm->pWC = pWC;
|
||||||
|
pTerm->iPartner = -1;
|
||||||
|
return pTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -233,11 +228,15 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Create a new mask for cursor iCursor.
|
** Create a new mask for cursor iCursor.
|
||||||
|
**
|
||||||
|
** There is one cursor per table in the FROM clause. The number of
|
||||||
|
** tables in the FROM clause is limited by a test early in the
|
||||||
|
** sqlite3WhereBegin() routien. So we know that the pMaskSet->ix[]
|
||||||
|
** array will never overflow.
|
||||||
*/
|
*/
|
||||||
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
|
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
|
||||||
if( pMaskSet->n<ARRAYSIZE(pMaskSet->ix) ){
|
assert( pMaskSet->n < ARRAYSIZE(pMaskSet->ix) );
|
||||||
pMaskSet->ix[pMaskSet->n++] = iCursor;
|
pMaskSet->ix[pMaskSet->n++] = iCursor;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -305,59 +304,18 @@ static int allowedOp(int op){
|
|||||||
#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
|
#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the index in the SrcList that uses cursor iCur. If iCur is
|
** Commute a comparision operator. Expressions of the form "X op Y"
|
||||||
** used by the first entry in SrcList return 0. If iCur is used by
|
** are converted into "Y op X".
|
||||||
** the second entry return 1. And so forth.
|
|
||||||
**
|
|
||||||
** SrcList is the set of tables in the FROM clause in the order that
|
|
||||||
** they will be processed. The value returned here gives us an index
|
|
||||||
** of which tables will be processed first.
|
|
||||||
*/
|
*/
|
||||||
static int tableOrder(SrcList *pList, int iCur){
|
static void exprCommute(Expr *pExpr){
|
||||||
int i;
|
assert(
|
||||||
struct SrcList_item *pItem;
|
pExpr->op==TK_EQ ||
|
||||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
pExpr->op==TK_NE ||
|
||||||
if( pItem->iCursor==iCur ) return i;
|
pExpr->op==TK_LT ||
|
||||||
}
|
pExpr->op==TK_LE ||
|
||||||
return -1;
|
pExpr->op==TK_GT ||
|
||||||
}
|
pExpr->op==TK_GE
|
||||||
|
);
|
||||||
/*
|
|
||||||
** 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
|
|
||||||
** subexpression and populate all the other fields of the WhereTerm
|
|
||||||
** structure.
|
|
||||||
*/
|
|
||||||
static void exprAnalyze(SrcList *pSrc, ExprMaskSet *pMaskSet, WhereTerm *pInfo){
|
|
||||||
Expr *pExpr = pInfo->p;
|
|
||||||
pInfo->prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
|
|
||||||
pInfo->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
|
|
||||||
pInfo->prereqAll = exprTableUsage(pMaskSet, pExpr);
|
|
||||||
pInfo->indexable = 0;
|
|
||||||
pInfo->idxLeft = -1;
|
|
||||||
pInfo->idxRight = -1;
|
|
||||||
if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
|
|
||||||
if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){
|
|
||||||
pInfo->idxRight = pExpr->pRight->iTable;
|
|
||||||
pInfo->indexable = 1;
|
|
||||||
}
|
|
||||||
if( pExpr->pLeft->op==TK_COLUMN ){
|
|
||||||
pInfo->idxLeft = pExpr->pLeft->iTable;
|
|
||||||
pInfo->indexable = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( pInfo->indexable ){
|
|
||||||
assert( pInfo->idxLeft!=pInfo->idxRight );
|
|
||||||
|
|
||||||
/* We want the expression to be of the form "X = expr", not "expr = X".
|
|
||||||
** So flip it over if necessary. If the expression is "X = Y", then
|
|
||||||
** we want Y to come from an earlier table than X.
|
|
||||||
**
|
|
||||||
** The collating sequence rule is to always choose the left expression.
|
|
||||||
** So if we do a flip, we also have to move the collating sequence.
|
|
||||||
*/
|
|
||||||
if( tableOrder(pSrc,pInfo->idxLeft)<tableOrder(pSrc,pInfo->idxRight) ){
|
|
||||||
assert( pExpr->op!=TK_IN );
|
|
||||||
SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
|
SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
|
||||||
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
|
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
|
||||||
if( pExpr->op>=TK_GT ){
|
if( pExpr->op>=TK_GT ){
|
||||||
@@ -368,13 +326,60 @@ static void exprAnalyze(SrcList *pSrc, ExprMaskSet *pMaskSet, WhereTerm *pInfo){
|
|||||||
assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
|
assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
|
||||||
pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
|
pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
|
||||||
}
|
}
|
||||||
SWAP(unsigned, pInfo->prereqLeft, pInfo->prereqRight);
|
|
||||||
SWAP(short int, pInfo->idxLeft, pInfo->idxRight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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
|
||||||
|
** subexpression and populate all the other fields of the WhereTerm
|
||||||
|
** structure.
|
||||||
|
*/
|
||||||
|
static void exprAnalyze(
|
||||||
|
SrcList *pSrc, /* the FROM clause */
|
||||||
|
ExprMaskSet *pMaskSet, /* table masks */
|
||||||
|
WhereTerm *pTerm /* the WHERE clause term to be analyzed */
|
||||||
|
){
|
||||||
|
Expr *pExpr = pTerm->pExpr;
|
||||||
|
Bitmask prereqLeft;
|
||||||
|
Bitmask prereqAll;
|
||||||
|
int idxRight;
|
||||||
|
|
||||||
|
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
|
||||||
|
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
|
||||||
|
pTerm->prereqAll = prereqAll = exprTableUsage(pMaskSet, pExpr);
|
||||||
|
pTerm->leftCursor = -1;
|
||||||
|
pTerm->iPartner = -1;
|
||||||
|
idxRight = -1;
|
||||||
|
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
|
||||||
|
Expr *pLeft = pExpr->pLeft;
|
||||||
|
Expr *pRight = pExpr->pRight;
|
||||||
|
if( pLeft->op==TK_COLUMN ){
|
||||||
|
pTerm->leftCursor = pLeft->iTable;
|
||||||
|
pTerm->leftColumn = pLeft->iColumn;
|
||||||
|
}
|
||||||
|
if( pRight && pRight->op==TK_COLUMN ){
|
||||||
|
WhereTerm *pNew;
|
||||||
|
Expr *pDup;
|
||||||
|
if( pTerm->leftCursor>=0 ){
|
||||||
|
pDup = sqlite3ExprDup(pExpr);
|
||||||
|
pNew = whereClauseInsert(pTerm->pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||||
|
if( pNew==0 ) return;
|
||||||
|
pNew->iPartner = pTerm->idx;
|
||||||
|
}else{
|
||||||
|
pDup = pExpr;
|
||||||
|
pNew = pTerm;
|
||||||
|
}
|
||||||
|
exprCommute(pDup);
|
||||||
|
pLeft = pDup->pLeft;
|
||||||
|
pNew->leftCursor = pLeft->iTable;
|
||||||
|
pNew->leftColumn = pLeft->iColumn;
|
||||||
|
pNew->prereqRight = prereqLeft;
|
||||||
|
pNew->prereqAll = prereqAll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine decides if pIdx can be used to satisfy the ORDER BY
|
** This routine decides if pIdx can be used to satisfy the ORDER BY
|
||||||
** clause. If it can, it returns 1. If pIdx cannot satisfy the
|
** clause. If it can, it returns 1. If pIdx cannot satisfy the
|
||||||
@@ -515,10 +520,15 @@ static int sortableByRowid(
|
|||||||
** too much. If we disabled in (1), we'd get the wrong answer.
|
** too much. If we disabled in (1), we'd get the wrong answer.
|
||||||
** See ticket #813.
|
** See ticket #813.
|
||||||
*/
|
*/
|
||||||
static void disableTerm(WhereLevel *pLevel, Expr **ppExpr){
|
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||||
Expr *pExpr = *ppExpr;
|
if( pTerm
|
||||||
if( pLevel->iLeftJoin==0 || ExprHasProperty(pExpr, EP_FromJoin) ){
|
&& (pTerm->flags & TERM_CODED)==0
|
||||||
*ppExpr = 0;
|
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
||||||
|
){
|
||||||
|
pTerm->flags |= TERM_CODED;
|
||||||
|
if( pTerm->iPartner>=0 ){
|
||||||
|
disableTerm(pLevel, &pTerm->pWC->a[pTerm->iPartner]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,7 +561,7 @@ static void codeEqualityTerm(
|
|||||||
int brk, /* Jump here to abandon the loop */
|
int brk, /* Jump here to abandon the loop */
|
||||||
WhereLevel *pLevel /* When level of the FROM clause we are working on */
|
WhereLevel *pLevel /* When level of the FROM clause we are working on */
|
||||||
){
|
){
|
||||||
Expr *pX = pTerm->p;
|
Expr *pX = pTerm->pExpr;
|
||||||
if( pX->op!=TK_IN ){
|
if( pX->op!=TK_IN ){
|
||||||
assert( pX->op==TK_EQ );
|
assert( pX->op==TK_EQ );
|
||||||
sqlite3ExprCode(pParse, pX->pRight);
|
sqlite3ExprCode(pParse, pX->pRight);
|
||||||
@@ -569,7 +579,7 @@ static void codeEqualityTerm(
|
|||||||
pLevel->inP1 = iTab;
|
pLevel->inP1 = iTab;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
disableTerm(pLevel, &pTerm->p);
|
disableTerm(pLevel, pTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
@@ -678,7 +688,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
WhereInfo *pWInfo; /* Will become the return value of this function */
|
WhereInfo *pWInfo; /* Will become the return value of this function */
|
||||||
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
|
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
|
||||||
int brk, cont = 0; /* Addresses used during code generation */
|
int brk, cont = 0; /* Addresses used during code generation */
|
||||||
Bitmask loopMask; /* One bit set for each outer loop */
|
Bitmask loopMask; /* One bit cleared for each outer loop */
|
||||||
WhereTerm *pTerm; /* A single term in the WHERE clause */
|
WhereTerm *pTerm; /* A single term in the WHERE clause */
|
||||||
ExprMaskSet maskSet; /* The expression mask set */
|
ExprMaskSet maskSet; /* The expression mask set */
|
||||||
int iDirectEq[BMS]; /* Term of the form ROWID==X for the N-th table */
|
int iDirectEq[BMS]; /* Term of the form ROWID==X for the N-th table */
|
||||||
@@ -732,8 +742,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
for(i=0; i<pTabList->nSrc; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
createMask(&maskSet, pTabList->a[i].iCursor);
|
createMask(&maskSet, pTabList->a[i].iCursor);
|
||||||
}
|
}
|
||||||
for(pTerm=wc.a, i=0; i<wc.nTerm; i++, pTerm++){
|
for(i=wc.nTerm-1; i>=0; i--){
|
||||||
exprAnalyze(pTabList, &maskSet, pTerm);
|
exprAnalyze(pTabList, &maskSet, &wc.a[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out what index to use (if any) for each nested loop.
|
/* Figure out what index to use (if any) for each nested loop.
|
||||||
@@ -752,7 +762,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
** first 32 tables are candidates for indices. This is (again) due
|
** first 32 tables are candidates for indices. This is (again) due
|
||||||
** to the limit of 32 bits in an integer bitmask.
|
** to the limit of 32 bits in an integer bitmask.
|
||||||
*/
|
*/
|
||||||
loopMask = 0;
|
loopMask = ~(Bitmask)0;
|
||||||
pTabItem = pTabList->a;
|
pTabItem = pTabList->a;
|
||||||
pLevel = pWInfo->a;
|
pLevel = pWInfo->a;
|
||||||
for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++,pTabItem++,pLevel++){
|
for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++,pTabItem++,pLevel++){
|
||||||
@@ -778,10 +788,9 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
iDirectLt[i] = -1;
|
iDirectLt[i] = -1;
|
||||||
iDirectGt[i] = -1;
|
iDirectGt[i] = -1;
|
||||||
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
||||||
Expr *pX = pTerm->p;
|
if( pTerm->leftCursor==iCur && pTerm->leftColumn<0
|
||||||
if( pTerm->idxLeft==iCur && pX->pLeft->iColumn<0
|
&& (pTerm->prereqRight & loopMask)==0 ){
|
||||||
&& (pTerm->prereqRight & loopMask)==pTerm->prereqRight ){
|
switch( pTerm->pExpr->op ){
|
||||||
switch( pX->op ){
|
|
||||||
case TK_IN:
|
case TK_IN:
|
||||||
case TK_EQ: iDirectEq[i] = j; break;
|
case TK_EQ: iDirectEq[i] = j; break;
|
||||||
case TK_LE:
|
case TK_LE:
|
||||||
@@ -798,7 +807,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
** an index. We will always use the ROWID over an index.
|
** an index. We will always use the ROWID over an index.
|
||||||
*/
|
*/
|
||||||
if( iDirectEq[i]>=0 ){
|
if( iDirectEq[i]>=0 ){
|
||||||
loopMask |= mask;
|
loopMask &= ~mask;
|
||||||
pLevel->pIdx = 0;
|
pLevel->pIdx = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -849,7 +858,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
continue; /* Ignore indices with too many columns to analyze */
|
continue; /* Ignore indices with too many columns to analyze */
|
||||||
}
|
}
|
||||||
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
||||||
Expr *pX = pTerm->p;
|
Expr *pX = pTerm->pExpr;
|
||||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pX->pLeft);
|
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pX->pLeft);
|
||||||
if( !pColl && pX->pRight ){
|
if( !pColl && pX->pRight ){
|
||||||
pColl = sqlite3ExprCollSeq(pParse, pX->pRight);
|
pColl = sqlite3ExprCollSeq(pParse, pX->pRight);
|
||||||
@@ -857,9 +866,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
if( !pColl ){
|
if( !pColl ){
|
||||||
pColl = pParse->db->pDfltColl;
|
pColl = pParse->db->pDfltColl;
|
||||||
}
|
}
|
||||||
if( pTerm->idxLeft==iCur
|
if( pTerm->leftCursor==iCur && (pTerm->prereqRight & loopMask)==0 ){
|
||||||
&& (pTerm->prereqRight & loopMask)==pTerm->prereqRight ){
|
int iColumn = pTerm->leftColumn;
|
||||||
int iColumn = pX->pLeft->iColumn;
|
|
||||||
int k;
|
int k;
|
||||||
char idxaff = iColumn>=0 ? pIdx->pTable->aCol[iColumn].affinity : 0;
|
char idxaff = iColumn>=0 ? pIdx->pTable->aCol[iColumn].affinity : 0;
|
||||||
for(k=0; k<pIdx->nColumn; k++){
|
for(k=0; k<pIdx->nColumn; k++){
|
||||||
@@ -952,7 +960,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
pLevel->pIdx = pBestIdx;
|
pLevel->pIdx = pBestIdx;
|
||||||
pLevel->score = bestScore;
|
pLevel->score = bestScore;
|
||||||
pLevel->bRev = bestRev;
|
pLevel->bRev = bestRev;
|
||||||
loopMask |= mask;
|
loopMask &= ~mask;
|
||||||
if( pBestIdx ){
|
if( pBestIdx ){
|
||||||
pLevel->iIdxCur = pParse->nTab++;
|
pLevel->iIdxCur = pParse->nTab++;
|
||||||
}
|
}
|
||||||
@@ -1070,7 +1078,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
|
|
||||||
/* Generate the code to do the search
|
/* Generate the code to do the search
|
||||||
*/
|
*/
|
||||||
loopMask = 0;
|
loopMask = ~(Bitmask)0;
|
||||||
pLevel = pWInfo->a;
|
pLevel = pWInfo->a;
|
||||||
pTabItem = pTabList->a;
|
pTabItem = pTabList->a;
|
||||||
for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){
|
for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){
|
||||||
@@ -1109,8 +1117,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
*/
|
*/
|
||||||
assert( k<wc.nTerm );
|
assert( k<wc.nTerm );
|
||||||
pTerm = &wc.a[k];
|
pTerm = &wc.a[k];
|
||||||
assert( pTerm->p!=0 );
|
assert( pTerm->pExpr!=0 );
|
||||||
assert( pTerm->idxLeft==iCur );
|
assert( pTerm->leftCursor==iCur );
|
||||||
assert( omitTable==0 );
|
assert( omitTable==0 );
|
||||||
brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
|
brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
|
||||||
codeEqualityTerm(pParse, pTerm, brk, pLevel);
|
codeEqualityTerm(pParse, pTerm, brk, pLevel);
|
||||||
@@ -1132,14 +1140,15 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
** generate code to evaluate expr and leave the result on the stack */
|
** generate code to evaluate expr and leave the result on the stack */
|
||||||
for(j=0; j<nColumn; j++){
|
for(j=0; j<nColumn; j++){
|
||||||
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
||||||
Expr *pX = pTerm->p;
|
Expr *pX = pTerm->pExpr;
|
||||||
if( pX==0 ) continue;
|
assert( pX );
|
||||||
if( pTerm->idxLeft==iCur
|
if( pTerm->leftCursor==iCur
|
||||||
&& (pTerm->prereqRight & loopMask)==pTerm->prereqRight
|
&& (pTerm->prereqRight & loopMask)==0
|
||||||
&& pX->pLeft->iColumn==pIdx->aiColumn[j]
|
&& pTerm->leftColumn==pIdx->aiColumn[j]
|
||||||
&& (pX->op==TK_EQ || pX->op==TK_IN)
|
&& (pX->op==TK_EQ || pX->op==TK_IN)
|
||||||
){
|
){
|
||||||
char idxaff = pIdx->pTable->aCol[pX->pLeft->iColumn].affinity;
|
char idxaff = pIdx->pTable->aCol[pTerm->leftColumn].affinity;
|
||||||
|
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||||
if( sqlite3IndexAffinityOk(pX, idxaff) ){
|
if( sqlite3IndexAffinityOk(pX, idxaff) ){
|
||||||
codeEqualityTerm(pParse, pTerm, brk, pLevel);
|
codeEqualityTerm(pParse, pTerm, brk, pLevel);
|
||||||
break;
|
break;
|
||||||
@@ -1198,14 +1207,14 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
k = iDirectGt[i];
|
k = iDirectGt[i];
|
||||||
assert( k<wc.nTerm );
|
assert( k<wc.nTerm );
|
||||||
pTerm = &wc.a[k];
|
pTerm = &wc.a[k];
|
||||||
pX = pTerm->p;
|
pX = pTerm->pExpr;
|
||||||
assert( pX!=0 );
|
assert( pX!=0 );
|
||||||
assert( pTerm->idxLeft==iCur );
|
assert( pTerm->leftCursor==iCur );
|
||||||
sqlite3ExprCode(pParse, pX->pRight);
|
sqlite3ExprCode(pParse, pX->pRight);
|
||||||
sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LE || pX->op==TK_GT, brk);
|
sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LE || pX->op==TK_GT, brk);
|
||||||
sqlite3VdbeAddOp(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk);
|
sqlite3VdbeAddOp(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk);
|
||||||
VdbeComment((v, "pk"));
|
VdbeComment((v, "pk"));
|
||||||
disableTerm(pLevel, &pTerm->p);
|
disableTerm(pLevel, pTerm);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp(v, bRev ? OP_Last : OP_Rewind, iCur, brk);
|
sqlite3VdbeAddOp(v, bRev ? OP_Last : OP_Rewind, iCur, brk);
|
||||||
}
|
}
|
||||||
@@ -1214,9 +1223,9 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
k = iDirectLt[i];
|
k = iDirectLt[i];
|
||||||
assert( k<wc.nTerm );
|
assert( k<wc.nTerm );
|
||||||
pTerm = &wc.a[k];
|
pTerm = &wc.a[k];
|
||||||
pX = pTerm->p;
|
pX = pTerm->pExpr;
|
||||||
assert( pX!=0 );
|
assert( pX!=0 );
|
||||||
assert( pTerm->idxLeft==iCur );
|
assert( pTerm->leftCursor==iCur );
|
||||||
sqlite3ExprCode(pParse, pX->pRight);
|
sqlite3ExprCode(pParse, pX->pRight);
|
||||||
pLevel->iMem = pParse->nMem++;
|
pLevel->iMem = pParse->nMem++;
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||||
@@ -1225,7 +1234,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
}else{
|
}else{
|
||||||
testOp = bRev ? OP_Lt : OP_Gt;
|
testOp = bRev ? OP_Lt : OP_Gt;
|
||||||
}
|
}
|
||||||
disableTerm(pLevel, &pTerm->p);
|
disableTerm(pLevel, pTerm);
|
||||||
}
|
}
|
||||||
start = sqlite3VdbeCurrentAddr(v);
|
start = sqlite3VdbeCurrentAddr(v);
|
||||||
pLevel->op = bRev ? OP_Prev : OP_Next;
|
pLevel->op = bRev ? OP_Prev : OP_Next;
|
||||||
@@ -1280,18 +1289,19 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
for(j=0; j<nEqColumn; j++){
|
for(j=0; j<nEqColumn; j++){
|
||||||
int iIdxCol = pIdx->aiColumn[j];
|
int iIdxCol = pIdx->aiColumn[j];
|
||||||
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
||||||
Expr *pX = pTerm->p;
|
Expr *pX;
|
||||||
if( pX==0 ) continue;
|
if( pTerm->leftCursor==iCur
|
||||||
if( pTerm->idxLeft==iCur
|
&& pTerm->leftColumn==iIdxCol
|
||||||
&& pX->op==TK_EQ
|
&& (pX = pTerm->pExpr)->op==TK_EQ
|
||||||
&& (pTerm->prereqRight & loopMask)==pTerm->prereqRight
|
&& (pTerm->prereqRight & loopMask)==0
|
||||||
&& pX->pLeft->iColumn==iIdxCol
|
|
||||||
){
|
){
|
||||||
|
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||||
sqlite3ExprCode(pParse, pX->pRight);
|
sqlite3ExprCode(pParse, pX->pRight);
|
||||||
disableTerm(pLevel, &pTerm->p);
|
disableTerm(pLevel, pTerm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert( k<wc.nTerm );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Duplicate the equality term values because they will all be
|
/* Duplicate the equality term values because they will all be
|
||||||
@@ -1316,19 +1326,21 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
*/
|
*/
|
||||||
if( (score & 4)!=0 ){
|
if( (score & 4)!=0 ){
|
||||||
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
||||||
Expr *pX = pTerm->p;
|
Expr *pX = pTerm->pExpr;
|
||||||
if( pX==0 ) continue;
|
assert( pX );
|
||||||
if( pTerm->idxLeft==iCur
|
if( pTerm->leftCursor==iCur
|
||||||
&& (pX->op==TK_LT || pX->op==TK_LE)
|
&& (pX->op==TK_LT || pX->op==TK_LE)
|
||||||
&& (pTerm->prereqRight & loopMask)==pTerm->prereqRight
|
&& (pTerm->prereqRight & loopMask)==0
|
||||||
&& pX->pLeft->iColumn==pIdx->aiColumn[j]
|
&& pTerm->leftColumn==pIdx->aiColumn[j]
|
||||||
){
|
){
|
||||||
|
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||||
sqlite3ExprCode(pParse, pX->pRight);
|
sqlite3ExprCode(pParse, pX->pRight);
|
||||||
leFlag = pX->op==TK_LE;
|
leFlag = pX->op==TK_LE;
|
||||||
disableTerm(pLevel, &pTerm->p);
|
disableTerm(pLevel, pTerm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert( k<wc.nTerm );
|
||||||
testOp = OP_IdxGE;
|
testOp = OP_IdxGE;
|
||||||
}else{
|
}else{
|
||||||
testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;
|
testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;
|
||||||
@@ -1359,16 +1371,17 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
*/
|
*/
|
||||||
if( (score & 8)!=0 ){
|
if( (score & 8)!=0 ){
|
||||||
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
|
||||||
Expr *pX = pTerm->p;
|
Expr *pX = pTerm->pExpr;
|
||||||
if( pX==0 ) continue;
|
assert( pX );
|
||||||
if( pTerm->idxLeft==iCur
|
if( pTerm->leftCursor==iCur
|
||||||
&& (pX->op==TK_GT || pX->op==TK_GE)
|
&& (pX->op==TK_GT || pX->op==TK_GE)
|
||||||
&& (pTerm->prereqRight & loopMask)==pTerm->prereqRight
|
&& (pTerm->prereqRight & loopMask)==0
|
||||||
&& pX->pLeft->iColumn==pIdx->aiColumn[j]
|
&& pTerm->leftColumn==pIdx->aiColumn[j]
|
||||||
){
|
){
|
||||||
|
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||||
sqlite3ExprCode(pParse, pX->pRight);
|
sqlite3ExprCode(pParse, pX->pRight);
|
||||||
geFlag = pX->op==TK_GE;
|
geFlag = pX->op==TK_GE;
|
||||||
disableTerm(pLevel, &pTerm->p);
|
disableTerm(pLevel, pTerm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1417,20 +1430,22 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
pLevel->p1 = iIdxCur;
|
pLevel->p1 = iIdxCur;
|
||||||
pLevel->p2 = start;
|
pLevel->p2 = start;
|
||||||
}
|
}
|
||||||
loopMask |= getMask(&maskSet, iCur);
|
loopMask &= ~getMask(&maskSet, iCur);
|
||||||
|
|
||||||
/* Insert code to test every subexpression that can be completely
|
/* Insert code to test every subexpression that can be completely
|
||||||
** computed using the current set of tables.
|
** computed using the current set of tables.
|
||||||
*/
|
*/
|
||||||
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){
|
||||||
Expr *pE = pTerm->p;
|
Expr *pE;
|
||||||
if( pE==0 || ExprHasProperty(pE, EP_OptOnly) ) continue;
|
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||||
if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;
|
if( (pTerm->prereqAll & loopMask)!=0 ) continue;
|
||||||
|
pE = pTerm->pExpr;
|
||||||
|
assert( pE!=0 );
|
||||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sqlite3ExprIfFalse(pParse, pE, cont, 1);
|
sqlite3ExprIfFalse(pParse, pE, cont, 1);
|
||||||
pTerm->p = 0;
|
pTerm->flags |= TERM_CODED;
|
||||||
}
|
}
|
||||||
brk = cont;
|
brk = cont;
|
||||||
|
|
||||||
@@ -1443,11 +1458,11 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
|
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
|
||||||
VdbeComment((v, "# record LEFT JOIN hit"));
|
VdbeComment((v, "# record LEFT JOIN hit"));
|
||||||
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
||||||
Expr *pE = pTerm->p;
|
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||||
if( pE==0 || ExprHasProperty(pE, EP_OptOnly) ) continue;
|
if( (pTerm->prereqAll & loopMask)!=0 ) continue;
|
||||||
if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;
|
assert( pTerm->pExpr );
|
||||||
sqlite3ExprIfFalse(pParse, pE, cont, 1);
|
sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, 1);
|
||||||
pTerm->p = 0;
|
pTerm->flags |= TERM_CODED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user