Improved management of the space to hold WhereLoop.aLTerm[].
FossilOrigin-Name: d4141ecbea3abbe83525910684fbd89eb74eeb34
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
C Remove\ssome\scommented-out\scode\sthat\swas\smistakenly\sleft\sin\sthe\sprevious\ncheck-in.
|
||||
D 2013-06-06T19:25:42.472
|
||||
C Improved\smanagement\sof\sthe\sspace\sto\shold\sWhereLoop.aLTerm[].
|
||||
D 2013-06-06T23:02:03.759
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
|
||||
F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
|
||||
F src/where.c 0b652e425f7a958a66591b082731c4e8379d8954
|
||||
F src/where.c e029cd3fe9f2fcc857cf19d05b352b2359638271
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
@@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P bfc76ae1e94fc5b7fd2c9484a36a8dfe6655d165
|
||||
R 6ac62cf90895a44c1fcede6b2ff8eacf
|
||||
P b4a5dbad36bceabc5c5350e7676af6ad42de04eb
|
||||
R c565385814d78fee98948398a72cac6f
|
||||
U drh
|
||||
Z b5c1236cedf9282cba7e1987b8db3ea9
|
||||
Z 2b77e3c42c0b772f55707fe4d25f7e48
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
b4a5dbad36bceabc5c5350e7676af6ad42de04eb
|
||||
d4141ecbea3abbe83525910684fbd89eb74eeb34
|
||||
+200
-138
@@ -45,6 +45,7 @@ typedef struct WherePath WherePath;
|
||||
typedef struct WhereTerm WhereTerm;
|
||||
typedef struct WhereLoopBuilder WhereLoopBuilder;
|
||||
typedef struct WhereScan WhereScan;
|
||||
typedef float WhereCost;
|
||||
|
||||
/*
|
||||
** For each nested loop in a WHERE clause implementation, the WhereInfo
|
||||
@@ -98,11 +99,12 @@ struct WhereLoop {
|
||||
#endif
|
||||
u8 iTab; /* Position in FROM clause of table for this loop */
|
||||
u8 iSortIdx; /* Sorting index number. 0==None */
|
||||
u16 nTerm; /* Number of entries in aTerm[] */
|
||||
u16 nLTerm; /* Number of entries in aLTerm[] */
|
||||
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
|
||||
u32 wsFlags; /* WHERE_* flags describing the plan */
|
||||
double rSetup; /* One-time setup cost (ex: create transient index) */
|
||||
double rRun; /* Cost of running each loop */
|
||||
double nOut; /* Estimated number of output rows */
|
||||
WhereCost rSetup; /* One-time setup cost (ex: create transient index) */
|
||||
WhereCost rRun; /* Cost of running each loop */
|
||||
WhereCost nOut; /* Estimated number of output rows */
|
||||
union {
|
||||
struct { /* Information for internal btree tables */
|
||||
int nEq; /* Number of equality constraints */
|
||||
@@ -116,10 +118,14 @@ struct WhereLoop {
|
||||
char *idxStr; /* Index identifier string */
|
||||
} vtab;
|
||||
} u;
|
||||
WhereTerm **aTerm; /* WhereTerms used */
|
||||
WhereTerm **aLTerm; /* WhereTerms used */
|
||||
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
|
||||
WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
|
||||
};
|
||||
|
||||
/* Forward declaration of methods */
|
||||
static int whereLoopResize(sqlite3*, WhereLoop*, int);
|
||||
|
||||
/*
|
||||
** Each instance of this object holds a sequence of WhereLoop objects
|
||||
** that implement some or all of the entire query plan.
|
||||
@@ -127,8 +133,8 @@ struct WhereLoop {
|
||||
struct WherePath {
|
||||
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
|
||||
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
|
||||
double nRow; /* Estimated number of rows generated by this path */
|
||||
double rCost; /* Total cost of this path */
|
||||
WhereCost nRow; /* Estimated number of rows generated by this path */
|
||||
WhereCost rCost; /* Total cost of this path */
|
||||
u8 isOrdered; /* True if this path satisfies ORDER BY */
|
||||
u8 isOrderedValid; /* True if the isOrdered field is valid */
|
||||
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
|
||||
@@ -318,7 +324,6 @@ struct WhereLoopBuilder {
|
||||
ExprList *pOrderBy; /* ORDER BY clause */
|
||||
WhereLoop *pNew; /* Template WhereLoop */
|
||||
WhereLoop *pBest; /* If non-NULL, store single best loop here */
|
||||
int mxTerm; /* Maximum number of aTerm[] entries on pNew */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -346,8 +351,8 @@ struct WhereInfo {
|
||||
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
||||
WhereClause sWC; /* Decomposition of the WHERE clause */
|
||||
WhereLoop *pLoops; /* List of all WhereLoop objects */
|
||||
double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
|
||||
double nRowOut; /* Estimated number of output rows */
|
||||
WhereCost savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
|
||||
WhereCost nRowOut; /* Estimated number of output rows */
|
||||
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
||||
};
|
||||
|
||||
@@ -399,7 +404,7 @@ struct WhereInfo {
|
||||
** Return the estimated number of output rows from a WHERE clause
|
||||
*/
|
||||
double sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
|
||||
return pWInfo->nRowOut;
|
||||
return (double)pWInfo->nRowOut;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1823,9 +1828,9 @@ static int isDistinctRedundant(
|
||||
** complexity. Because N is just a guess, it is no great tragedy if
|
||||
** logN is a little off.
|
||||
*/
|
||||
static double estLog(double N){
|
||||
double logN = 1;
|
||||
double x = 10;
|
||||
static WhereCost estLog(WhereCost N){
|
||||
WhereCost logN = 1;
|
||||
WhereCost x = 10;
|
||||
while( N>x ){
|
||||
logN += 1;
|
||||
x *= 10;
|
||||
@@ -1946,23 +1951,21 @@ static void constructAutomaticIndex(
|
||||
pWCEnd = &pWC->a[pWC->nTerm];
|
||||
pLoop = pLevel->pWLoop;
|
||||
idxCols = 0;
|
||||
pLoop->aTerm = sqlite3DbRealloc(pParse->db, pLoop->aTerm,
|
||||
mxConstraint*sizeof(pLoop->aTerm[0]));
|
||||
if( pLoop->aTerm==0 ) return;
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd && pLoop->nTerm<mxConstraint; pTerm++){
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd && pLoop->nLTerm<mxConstraint; pTerm++){
|
||||
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
||||
int iCol = pTerm->u.leftColumn;
|
||||
Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
|
||||
testcase( iCol==BMS );
|
||||
testcase( iCol==BMS-1 );
|
||||
if( (idxCols & cMask)==0 ){
|
||||
pLoop->aTerm[nColumn++] = pTerm;
|
||||
if( whereLoopResize(pParse->db, pLoop, nColumn+1) ) return;
|
||||
pLoop->aLTerm[nColumn++] = pTerm;
|
||||
idxCols |= cMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( nColumn>0 );
|
||||
pLoop->u.btree.nEq = pLoop->nTerm = nColumn;
|
||||
pLoop->u.btree.nEq = pLoop->nLTerm = nColumn;
|
||||
pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED
|
||||
| WHERE_TEMP_INDEX;
|
||||
|
||||
@@ -2118,7 +2121,6 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
+ sizeof(*pIdxOrderBy)*nOrderBy );
|
||||
if( pIdxInfo==0 ){
|
||||
sqlite3ErrorMsg(pParse, "out of memory");
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2241,7 +2243,7 @@ static int whereKeyStats(
|
||||
int i, eType;
|
||||
int isEq = 0;
|
||||
i64 v;
|
||||
double r, rS;
|
||||
WhereCost r, rS;
|
||||
|
||||
assert( roundUp==0 || roundUp==1 );
|
||||
assert( pIdx->nSample>0 );
|
||||
@@ -2459,7 +2461,7 @@ static int whereRangeScanEst(
|
||||
int nEq, /* index into p->aCol[] of the range-compared column */
|
||||
WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
|
||||
WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
|
||||
double *pRangeDiv /* OUT: Reduce search space by this divisor */
|
||||
WhereCost *pRangeDiv /* OUT: Reduce search space by this divisor */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
@@ -2498,9 +2500,9 @@ static int whereRangeScanEst(
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iUpper<=iLower ){
|
||||
*pRangeDiv = (double)p->aiRowEst[0];
|
||||
*pRangeDiv = (WhereCost)p->aiRowEst[0];
|
||||
}else{
|
||||
*pRangeDiv = (double)p->aiRowEst[0]/(double)(iUpper - iLower);
|
||||
*pRangeDiv = (WhereCost)p->aiRowEst[0]/(WhereCost)(iUpper - iLower);
|
||||
}
|
||||
/*WHERETRACE(("range scan regions: %u..%u div=%g\n",
|
||||
(u32)iLower, (u32)iUpper, *pRangeDiv));*/
|
||||
@@ -2513,9 +2515,9 @@ static int whereRangeScanEst(
|
||||
UNUSED_PARAMETER(nEq);
|
||||
#endif
|
||||
assert( pLower || pUpper );
|
||||
*pRangeDiv = (double)1;
|
||||
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= (double)4;
|
||||
if( pUpper ) *pRangeDiv *= (double)4;
|
||||
*pRangeDiv = (WhereCost)1;
|
||||
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= (WhereCost)4;
|
||||
if( pUpper ) *pRangeDiv *= (WhereCost)4;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2541,7 +2543,7 @@ static int whereEqualScanEst(
|
||||
Parse *pParse, /* Parsing & code generating context */
|
||||
Index *p, /* The index whose left-most column is pTerm */
|
||||
Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */
|
||||
double *pnRow /* Write the revised row estimate here */
|
||||
WhereCost *pnRow /* Write the revised row estimate here */
|
||||
){
|
||||
sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */
|
||||
u8 aff; /* Column affinity */
|
||||
@@ -2590,11 +2592,11 @@ static int whereInScanEst(
|
||||
Parse *pParse, /* Parsing & code generating context */
|
||||
Index *p, /* The index whose left-most column is pTerm */
|
||||
ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */
|
||||
double *pnRow /* Write the revised row estimate here */
|
||||
WhereCost *pnRow /* Write the revised row estimate here */
|
||||
){
|
||||
int rc = SQLITE_OK; /* Subfunction return code */
|
||||
double nEst; /* Number of rows for a single term */
|
||||
double nRowEst = (double)0; /* New estimate of the number of rows */
|
||||
WhereCost nEst; /* Number of rows for a single term */
|
||||
WhereCost nRowEst = (WhereCost)0; /* New estimate of the number of rows */
|
||||
int i; /* Loop counter */
|
||||
|
||||
assert( p->aSample!=0 );
|
||||
@@ -2858,7 +2860,7 @@ static int codeAllEqualityTerms(
|
||||
assert( pIdx->nColumn>=nEq );
|
||||
for(j=0; j<nEq; j++){
|
||||
int r1;
|
||||
pTerm = pLoop->aTerm[j];
|
||||
pTerm = pLoop->aLTerm[j];
|
||||
assert( pTerm!=0 );
|
||||
/* The following true for indices with redundant columns.
|
||||
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
||||
@@ -3132,14 +3134,14 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
int iReg; /* P3 Value for OP_VFilter */
|
||||
int addrNotFound;
|
||||
int nConstraint = pLoop->nTerm;
|
||||
int nConstraint = pLoop->nLTerm;
|
||||
|
||||
sqlite3ExprCachePush(pParse);
|
||||
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
|
||||
addrNotFound = pLevel->addrBrk;
|
||||
for(j=0; j<nConstraint; j++){
|
||||
int iTarget = iReg+j+2;
|
||||
pTerm = pLoop->aTerm[j];
|
||||
pTerm = pLoop->aLTerm[j];
|
||||
if( pTerm->eOperator & WO_IN ){
|
||||
codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
|
||||
addrNotFound = pLevel->addrNxt;
|
||||
@@ -3155,7 +3157,7 @@ static Bitmask codeOneLoopStart(
|
||||
pLoop->u.vtab.needFree = 0;
|
||||
for(j=0; j<nConstraint && j<16; j++){
|
||||
if( (pLoop->u.vtab.omitMask>>j)&1 ){
|
||||
disableTerm(pLevel, pLoop->aTerm[j]);
|
||||
disableTerm(pLevel, pLoop->aLTerm[j]);
|
||||
}
|
||||
}
|
||||
pLevel->op = OP_VNext;
|
||||
@@ -3176,7 +3178,7 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
assert( pLoop->u.btree.nEq==1 );
|
||||
iReleaseReg = sqlite3GetTempReg(pParse);
|
||||
pTerm = pLoop->aTerm[0];
|
||||
pTerm = pLoop->aLTerm[0];
|
||||
assert( pTerm!=0 );
|
||||
assert( pTerm->pExpr!=0 );
|
||||
assert( omitTable==0 );
|
||||
@@ -3202,8 +3204,8 @@ static Bitmask codeOneLoopStart(
|
||||
assert( omitTable==0 );
|
||||
j = 0;
|
||||
pStart = pEnd = 0;
|
||||
if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aTerm[j++];
|
||||
if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aTerm[j++];
|
||||
if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++];
|
||||
if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++];
|
||||
if( bRev ){
|
||||
pTerm = pStart;
|
||||
pStart = pEnd;
|
||||
@@ -3361,11 +3363,11 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
j = nEq;
|
||||
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
|
||||
pRangeStart = pLoop->aTerm[j++];
|
||||
pRangeStart = pLoop->aLTerm[j++];
|
||||
nExtraReg = 1;
|
||||
}
|
||||
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
|
||||
pRangeEnd = pLoop->aTerm[j++];
|
||||
pRangeEnd = pLoop->aLTerm[j++];
|
||||
nExtraReg = 1;
|
||||
}
|
||||
|
||||
@@ -3574,7 +3576,7 @@ static Bitmask codeOneLoopStart(
|
||||
int ii; /* Loop counter */
|
||||
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
|
||||
|
||||
pTerm = pLoop->aTerm[0];
|
||||
pTerm = pLoop->aLTerm[0];
|
||||
assert( pTerm!=0 );
|
||||
assert( pTerm->eOperator & WO_OR );
|
||||
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
|
||||
@@ -3860,19 +3862,27 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){
|
||||
sqlite3DebugPrintf(" %-15s", z);
|
||||
sqlite3_free(z);
|
||||
}
|
||||
sqlite3DebugPrintf(" fg %05x N %d", p->wsFlags, p->nTerm);
|
||||
sqlite3DebugPrintf(" fg %05x N %d", p->wsFlags, p->nLTerm);
|
||||
sqlite3DebugPrintf(" cost %.2g,%.2g,%.2g\n",
|
||||
p->prereq, p->rSetup, p->rRun, p->nOut);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Deallocate internal memory used by a WhereLoop object
|
||||
** Convert bulk memory into a valid WhereLoop that can be passed
|
||||
** to whereLoopClear harmlessly.
|
||||
*/
|
||||
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
|
||||
sqlite3DbFree(db, p->aTerm);
|
||||
p->aTerm = 0;
|
||||
p->nTerm = 0;
|
||||
static void whereLoopInit(WhereLoop *p){
|
||||
p->aLTerm = p->aLTermSpace;
|
||||
p->nLTerm = 0;
|
||||
p->nLSlot = ArraySize(p->aLTermSpace);
|
||||
p->wsFlags = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact.
|
||||
*/
|
||||
static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
|
||||
if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
||||
if( p->u.vtab.needFree ) sqlite3_free(p->u.vtab.idxStr);
|
||||
p->u.vtab.needFree = 0;
|
||||
@@ -3884,6 +3894,61 @@ static void whereLoopClear(sqlite3 *db, WhereLoop *p){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Deallocate internal memory used by a WhereLoop object
|
||||
*/
|
||||
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
|
||||
whereLoopClearUnion(db, p);
|
||||
whereLoopInit(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Increase the memory allocation for pLoop->aLTerm[] to be at least n.
|
||||
*/
|
||||
static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
|
||||
WhereTerm **paNew;
|
||||
if( p->nLSlot>=n ) return SQLITE_OK;
|
||||
n = (n+7)&~7;
|
||||
paNew = sqlite3DbMallocRaw(db, sizeof(p->aLTerm[0])*n);
|
||||
if( paNew==0 ) return SQLITE_NOMEM;
|
||||
memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
|
||||
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
|
||||
p->aLTerm = paNew;
|
||||
p->nLSlot = n;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer content from the second pLoop into the first.
|
||||
*/
|
||||
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
|
||||
if( whereLoopResize(db, pTo, pFrom->nLTerm) ) return SQLITE_NOMEM;
|
||||
whereLoopClearUnion(db, pTo);
|
||||
pTo->prereq = pFrom->prereq;
|
||||
pTo->maskSelf = pFrom->maskSelf;
|
||||
pTo->iTab = pFrom->iTab;
|
||||
pTo->iSortIdx = pFrom->iSortIdx;
|
||||
pTo->nLTerm = pFrom->nLTerm;
|
||||
pTo->rSetup = pFrom->rSetup;
|
||||
pTo->rRun = pFrom->rRun;
|
||||
pTo->nOut = pFrom->nOut;
|
||||
if( pTo->nLTerm ){
|
||||
memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
|
||||
}
|
||||
pTo->wsFlags = pFrom->wsFlags;
|
||||
pTo->u = pFrom->u;
|
||||
if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){
|
||||
pFrom->u.vtab.needFree = 0;
|
||||
}else if( (pFrom->wsFlags & WHERE_TEMP_INDEX)!=0 && pFrom->u.btree.pIndex!=0 ){
|
||||
sqlite3DbFree(db, pFrom->u.btree.pIndex->zColAff);
|
||||
sqlite3DbFree(db, pFrom->u.btree.pIndex);
|
||||
pFrom->u.btree.pIndex = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete a WhereLoop object
|
||||
*/
|
||||
@@ -3934,8 +3999,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
** dependencies
|
||||
*/
|
||||
static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
WhereLoop **ppPrev, *p, *pNext = 0, *pToFree = 0;
|
||||
WhereTerm **paTerm = 0;
|
||||
WhereLoop **ppPrev, *p, *pNext = 0;
|
||||
WhereInfo *pWInfo = pBuilder->pWInfo;
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
|
||||
@@ -3946,17 +4010,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
*/
|
||||
if( (p = pBuilder->pBest)!=0 ){
|
||||
if( p->maskSelf!=0 ){
|
||||
if( p->rRun+p->rSetup < pTemplate->rRun+pTemplate->rSetup ){
|
||||
WhereCost rCost = p->rRun + p->rSetup;
|
||||
WhereCost rTemplate = pTemplate->rRun + pTemplate->rSetup;
|
||||
if( rCost < rTemplate ){
|
||||
goto whereLoopInsert_noop;
|
||||
}
|
||||
if( p->rRun+p->rSetup == pTemplate->rRun+pTemplate->rSetup
|
||||
&& p->prereq <= pTemplate->prereq ){
|
||||
if( rCost == rTemplate && p->prereq <= pTemplate->prereq ){
|
||||
goto whereLoopInsert_noop;
|
||||
}
|
||||
}
|
||||
*p = *pTemplate;
|
||||
p->aTerm = 0;
|
||||
p->u.vtab.needFree = 0;
|
||||
whereLoopXfer(db, p, pTemplate);
|
||||
#if WHERETRACE_ENABLED
|
||||
if( sqlite3WhereTrace & 0x8 ){
|
||||
sqlite3DebugPrintf("ins-best: ");
|
||||
@@ -3976,7 +4039,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
&& p->rRun<=pTemplate->rRun
|
||||
){
|
||||
/* p is equal or better than pTemplate */
|
||||
if( p->nTerm<pTemplate->nTerm
|
||||
if( p->nLTerm<pTemplate->nLTerm
|
||||
&& (p->wsFlags & WHERE_INDEXED)!=0
|
||||
&& (pTemplate->wsFlags & WHERE_INDEXED)!=0
|
||||
&& p->u.btree.pIndex==pTemplate->u.btree.pIndex
|
||||
@@ -4019,30 +4082,18 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
}
|
||||
#endif
|
||||
if( p==0 ){
|
||||
p = pToFree = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
|
||||
p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
whereLoopInit(p);
|
||||
}
|
||||
if( pTemplate->nTerm ){
|
||||
paTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0]));
|
||||
if( paTerm==0 ){
|
||||
sqlite3DbFree(db, pToFree);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
*p = *pTemplate;
|
||||
whereLoopXfer(db, p, pTemplate);
|
||||
p->pNextLoop = pNext;
|
||||
*ppPrev = p;
|
||||
p->aTerm = paTerm;
|
||||
if( p->nTerm ){
|
||||
memcpy(p->aTerm, pTemplate->aTerm, p->nTerm*sizeof(p->aTerm[0]));
|
||||
}
|
||||
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
|
||||
Index *pIndex = p->u.btree.pIndex;
|
||||
if( pIndex && pIndex->tnum==0 ){
|
||||
p->u.btree.pIndex = 0;
|
||||
}
|
||||
}else{
|
||||
pTemplate->u.vtab.needFree = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
@@ -4077,11 +4128,15 @@ static int whereLoopAddBtreeIndex(
|
||||
WhereTerm *pTerm; /* A WhereTerm under consideration */
|
||||
int opMask; /* Valid operators for constraints */
|
||||
WhereScan scan; /* Iterator for WHERE terms */
|
||||
WhereLoop savedLoop; /* Saved original content of pNew[] */
|
||||
Bitmask saved_prereq; /* Original value of pNew->prereq */
|
||||
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
|
||||
int saved_nEq; /* Original value of pNew->u.btree.nEq */
|
||||
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
|
||||
WhereCost saved_nOut; /* Original value of pNew->nOut */
|
||||
int iCol; /* Index of the column in the table */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
tRowcnt iRowEst; /* Estimated index selectivity */
|
||||
double rLogSize; /* Logarithm of table size */
|
||||
WhereCost rLogSize; /* Logarithm of table size */
|
||||
WhereTerm *pTop, *pBtm; /* Top and bottom range constraints */
|
||||
|
||||
pNew = pBuilder->pNew;
|
||||
@@ -4108,18 +4163,22 @@ static int whereLoopAddBtreeIndex(
|
||||
}
|
||||
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
|
||||
opMask, pProbe);
|
||||
savedLoop = *pNew;
|
||||
pNew->rSetup = (double)0;
|
||||
saved_nEq = pNew->u.btree.nEq;
|
||||
saved_nLTerm = pNew->nLTerm;
|
||||
saved_wsFlags = pNew->wsFlags;
|
||||
saved_prereq = pNew->prereq;
|
||||
saved_nOut = pNew->nOut;
|
||||
pNew->rSetup = (WhereCost)0;
|
||||
rLogSize = estLog(pProbe->aiRowEst[0]);
|
||||
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
|
||||
int nIn = 1;
|
||||
if( pTerm->prereqRight & pNew->maskSelf ) continue;
|
||||
pNew->wsFlags = savedLoop.wsFlags;
|
||||
pNew->u.btree.nEq = savedLoop.u.btree.nEq;
|
||||
pNew->nTerm = savedLoop.nTerm;
|
||||
if( pNew->nTerm>=pBuilder->mxTerm ) break; /* Repeated column in index */
|
||||
pNew->aTerm[pNew->nTerm++] = pTerm;
|
||||
pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~pNew->maskSelf;
|
||||
pNew->wsFlags = saved_wsFlags;
|
||||
pNew->u.btree.nEq = saved_nEq;
|
||||
pNew->nLTerm = saved_nLTerm;
|
||||
if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
|
||||
pNew->aLTerm[pNew->nLTerm++] = pTerm;
|
||||
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
|
||||
pNew->rRun = rLogSize;
|
||||
if( pTerm->eOperator & WO_IN ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
@@ -4133,7 +4192,7 @@ static int whereLoopAddBtreeIndex(
|
||||
}
|
||||
pNew->rRun *= nIn;
|
||||
pNew->u.btree.nEq++;
|
||||
pNew->nOut = (double)iRowEst * nInMul * nIn;
|
||||
pNew->nOut = (WhereCost)iRowEst * nInMul * nIn;
|
||||
}else if( pTerm->eOperator & (WO_EQ) ){
|
||||
assert( (pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0
|
||||
|| nInMul==1 );
|
||||
@@ -4146,12 +4205,12 @@ static int whereLoopAddBtreeIndex(
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
}
|
||||
pNew->u.btree.nEq++;
|
||||
pNew->nOut = (double)iRowEst * nInMul;
|
||||
pNew->nOut = (WhereCost)iRowEst * nInMul;
|
||||
}else if( pTerm->eOperator & (WO_ISNULL) ){
|
||||
pNew->wsFlags |= WHERE_COLUMN_NULL;
|
||||
pNew->u.btree.nEq++;
|
||||
nIn = 2; /* Assume IS NULL matches two rows */
|
||||
pNew->nOut = (double)iRowEst * nInMul * nIn;
|
||||
pNew->nOut = (WhereCost)iRowEst * nInMul * nIn;
|
||||
}else if( pTerm->eOperator & (WO_GT|WO_GE) ){
|
||||
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
|
||||
pBtm = pTerm;
|
||||
@@ -4160,14 +4219,14 @@ static int whereLoopAddBtreeIndex(
|
||||
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
|
||||
pTop = pTerm;
|
||||
pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
|
||||
pNew->aTerm[pNew->nTerm-2] : 0;
|
||||
pNew->aLTerm[pNew->nLTerm-2] : 0;
|
||||
}
|
||||
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
|
||||
/* Adjust nOut and rRun for STAT3 range values */
|
||||
double rDiv;
|
||||
WhereCost rDiv;
|
||||
whereRangeScanEst(pParse, pProbe, pNew->u.btree.nEq,
|
||||
pBtm, pTop, &rDiv);
|
||||
pNew->nOut = savedLoop.nOut/rDiv;
|
||||
pNew->nOut = saved_nOut/rDiv;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
if( pNew->u.btree.nEq==1 && pProbe->nSample ){
|
||||
@@ -4198,7 +4257,11 @@ static int whereLoopAddBtreeIndex(
|
||||
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul*nIn);
|
||||
}
|
||||
}
|
||||
*pNew = savedLoop;
|
||||
pNew->prereq = saved_prereq;
|
||||
pNew->u.btree.nEq = saved_nEq;
|
||||
pNew->wsFlags = saved_wsFlags;
|
||||
pNew->nOut = saved_nOut;
|
||||
pNew->nLTerm = saved_nLTerm;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4252,8 +4315,8 @@ static int whereLoopAddBtree(
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int iSortIdx = 1; /* Index number */
|
||||
int b; /* A boolean value */
|
||||
double rSize; /* number of rows in the table */
|
||||
double rLogSize; /* Logarithm of the number of rows in the table */
|
||||
WhereCost rSize; /* number of rows in the table */
|
||||
WhereCost rLogSize; /* Logarithm of the number of rows in the table */
|
||||
|
||||
pNew = pBuilder->pNew;
|
||||
pWInfo = pBuilder->pWInfo;
|
||||
@@ -4286,7 +4349,7 @@ static int whereLoopAddBtree(
|
||||
}
|
||||
pProbe = &sPk;
|
||||
}
|
||||
rSize = (double)pSrc->pTab->nRowEst;
|
||||
rSize = (WhereCost)pSrc->pTab->nRowEst;
|
||||
rLogSize = estLog(rSize);
|
||||
|
||||
/* Automatic indexes */
|
||||
@@ -4306,10 +4369,10 @@ static int whereLoopAddBtree(
|
||||
if( termCanDriveIndex(pTerm, pSrc, 0) ){
|
||||
pNew->u.btree.nEq = 1;
|
||||
pNew->u.btree.pIndex = 0;
|
||||
pNew->nTerm = 1;
|
||||
pNew->aTerm[0] = pTerm;
|
||||
pNew->nLTerm = 1;
|
||||
pNew->aLTerm[0] = pTerm;
|
||||
pNew->rSetup = 20*rLogSize*pSrc->pTab->nRowEst;
|
||||
pNew->nOut = (double)10;
|
||||
pNew->nOut = (WhereCost)10;
|
||||
pNew->rRun = rLogSize + pNew->nOut;
|
||||
pNew->wsFlags = WHERE_TEMP_INDEX;
|
||||
pNew->prereq = mExtra | pTerm->prereqRight;
|
||||
@@ -4322,9 +4385,9 @@ static int whereLoopAddBtree(
|
||||
*/
|
||||
for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){
|
||||
pNew->u.btree.nEq = 0;
|
||||
pNew->nTerm = 0;
|
||||
pNew->nLTerm = 0;
|
||||
pNew->iSortIdx = 0;
|
||||
pNew->rSetup = (double)0;
|
||||
pNew->rSetup = (WhereCost)0;
|
||||
pNew->prereq = mExtra;
|
||||
pNew->u.btree.pIndex = pProbe;
|
||||
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
|
||||
@@ -4392,6 +4455,7 @@ static int whereLoopAddVirtual(
|
||||
WhereTerm *pTerm;
|
||||
int i, j;
|
||||
int iTerm, mxTerm;
|
||||
int nConstraint;
|
||||
int seenIn = 0; /* True if an IN operator is seen */
|
||||
int seenVar = 0; /* True if a non-constant constraint is seen */
|
||||
int iPhase; /* 0: const w/o IN, 1: const, 2: no IN, 2: IN */
|
||||
@@ -4411,9 +4475,11 @@ static int whereLoopAddVirtual(
|
||||
pNew->prereq = 0;
|
||||
pNew->rSetup = 0;
|
||||
pNew->wsFlags = WHERE_VIRTUALTABLE;
|
||||
pNew->nTerm = 0;
|
||||
pNew->nLTerm = 0;
|
||||
pNew->u.vtab.needFree = 0;
|
||||
pUsage = pIdxInfo->aConstraintUsage;
|
||||
nConstraint = pIdxInfo->nConstraint;
|
||||
if( whereLoopResize(db, pNew, nConstraint) ) return SQLITE_NOMEM;
|
||||
|
||||
for(iPhase=0; iPhase<=3; iPhase++){
|
||||
if( !seenIn && (iPhase&1)!=0 ){
|
||||
@@ -4456,23 +4522,23 @@ static int whereLoopAddVirtual(
|
||||
pIdxInfo->idxNum = 0;
|
||||
pIdxInfo->needToFreeIdxStr = 0;
|
||||
pIdxInfo->orderByConsumed = 0;
|
||||
/* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
|
||||
/* ((WhereCost)2) In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((WhereCost)2);
|
||||
rc = vtabBestIndex(pParse, pTab, pIdxInfo);
|
||||
if( rc ) goto whereLoopAddVtab_exit;
|
||||
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
|
||||
pNew->prereq = 0;
|
||||
mxTerm = -1;
|
||||
for(i=0; i<pBuilder->mxTerm; i++) pNew->aTerm[i] = 0;
|
||||
assert( pNew->nLSlot>=nConstraint );
|
||||
for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
|
||||
pNew->u.vtab.omitMask = 0;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
|
||||
for(i=0; i<nConstraint; i++, pIdxCons++){
|
||||
if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
|
||||
if( iTerm>=pBuilder->mxTerm ) break;
|
||||
j = pIdxCons->iTermOffset;
|
||||
if( iTerm>=pIdxInfo->nConstraint
|
||||
if( iTerm>=nConstraint
|
||||
|| j<0
|
||||
|| j>=pWC->nTerm
|
||||
|| pNew->aTerm[iTerm]!=0
|
||||
|| pNew->aLTerm[iTerm]!=0
|
||||
){
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName);
|
||||
@@ -4480,7 +4546,8 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
pTerm = &pWC->a[j];
|
||||
pNew->prereq |= pTerm->prereqRight;
|
||||
pNew->aTerm[iTerm] = pTerm;
|
||||
assert( iTerm<pNew->nLSlot );
|
||||
pNew->aLTerm[iTerm] = pTerm;
|
||||
if( iTerm>mxTerm ) mxTerm = iTerm;
|
||||
if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
|
||||
if( (pTerm->eOperator & WO_IN)!=0 ){
|
||||
@@ -4500,17 +4567,18 @@ static int whereLoopAddVirtual(
|
||||
}
|
||||
}
|
||||
}
|
||||
if( i>=pIdxInfo->nConstraint ){
|
||||
pNew->nTerm = mxTerm+1;
|
||||
if( i>=nConstraint ){
|
||||
pNew->nLTerm = mxTerm+1;
|
||||
assert( pNew->nLTerm<=pNew->nLSlot );
|
||||
pNew->u.vtab.idxNum = pIdxInfo->idxNum;
|
||||
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
|
||||
pIdxInfo->needToFreeIdxStr = 0;
|
||||
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
|
||||
pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
|
||||
&& pIdxInfo->orderByConsumed);
|
||||
pNew->rSetup = (double)0;
|
||||
pNew->rSetup = (WhereCost)0;
|
||||
pNew->rRun = pIdxInfo->estimatedCost;
|
||||
pNew->nOut = (double)25;
|
||||
pNew->nOut = (WhereCost)25;
|
||||
whereLoopInsert(pBuilder, pNew);
|
||||
if( pNew->u.vtab.needFree ){
|
||||
sqlite3_free(pNew->u.vtab.idxStr);
|
||||
@@ -4545,6 +4613,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
|
||||
pWCEnd = pWC->a + pWC->nTerm;
|
||||
pNew = pBuilder->pNew;
|
||||
whereLoopInit(&sBest);
|
||||
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
|
||||
if( (pTerm->eOperator & WO_OR)!=0
|
||||
@@ -4553,8 +4622,8 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
|
||||
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
|
||||
WhereTerm *pOrTerm;
|
||||
double rTotal = 0;
|
||||
double nRow = 0;
|
||||
WhereCost rTotal = 0;
|
||||
WhereCost nRow = 0;
|
||||
Bitmask prereq = mExtra;
|
||||
|
||||
pItem = pWInfo->pTabList->a + pNew->iTab;
|
||||
@@ -4577,21 +4646,24 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
continue;
|
||||
}
|
||||
sBest.maskSelf = 0;
|
||||
sBest.rSetup = 0;
|
||||
sBest.rRun = 0;
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
rc = whereLoopAddVirtual(&sSubBuild, mExtra);
|
||||
}else{
|
||||
rc = whereLoopAddBtree(&sSubBuild, mExtra);
|
||||
}
|
||||
if( sBest.maskSelf==0 ) break;
|
||||
assert( sBest.rSetup==(double)0 );
|
||||
assert( sBest.rSetup==(WhereCost)0 );
|
||||
rTotal += sBest.rRun;
|
||||
nRow += sBest.nOut;
|
||||
prereq |= sBest.prereq;
|
||||
}
|
||||
pNew->nTerm = 1;
|
||||
pNew->aTerm[0] = pTerm;
|
||||
assert( pNew->nLSlot>=1 );
|
||||
pNew->nLTerm = 1;
|
||||
pNew->aLTerm[0] = pTerm;
|
||||
pNew->wsFlags = WHERE_MULTI_OR;
|
||||
pNew->rSetup = (double)0;
|
||||
pNew->rSetup = (WhereCost)0;
|
||||
pNew->rRun = rTotal;
|
||||
pNew->nOut = nRow;
|
||||
pNew->prereq = prereq;
|
||||
@@ -4599,6 +4671,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
}
|
||||
}
|
||||
whereLoopClear(pWInfo->pParse->db, &sBest);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4612,7 +4685,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
int iTab;
|
||||
SrcList *pTabList = pWInfo->pTabList;
|
||||
struct SrcList_item *pItem;
|
||||
WhereClause *pWC = pBuilder->pWC;
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
int nTabList = pWInfo->nLevel;
|
||||
int rc = SQLITE_OK;
|
||||
@@ -4621,17 +4693,8 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
/* Loop over the tables in the join, from left to right */
|
||||
pBuilder->pNew = pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop));
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
pBuilder->mxTerm = pWC->nTerm+1;
|
||||
while( pWC->pOuter ){
|
||||
pWC = pWC->pOuter;
|
||||
pBuilder->mxTerm += pWC->nTerm;
|
||||
}
|
||||
pWC = pBuilder->pWC;
|
||||
pNew->aTerm = sqlite3DbMallocZero(db,pBuilder->mxTerm*sizeof(pNew->aTerm[0]));
|
||||
if( pNew->aTerm==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto whereLoopAddAll_end;
|
||||
}
|
||||
pNew->aLTerm = pNew->aLTermSpace;
|
||||
pNew->nLSlot = ArraySize(pNew->aLTermSpace);
|
||||
for(iTab=0, pItem=pTabList->a; iTab<nTabList; iTab++, pItem++){
|
||||
pNew->iTab = iTab;
|
||||
pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor);
|
||||
@@ -4649,7 +4712,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
mPrior |= pNew->maskSelf;
|
||||
if( rc || db->mallocFailed ) break;
|
||||
}
|
||||
whereLoopAddAll_end:
|
||||
whereLoopDelete(db, pBuilder->pNew);
|
||||
pBuilder->pNew = 0;
|
||||
return rc;
|
||||
@@ -4755,7 +4817,7 @@ static int wherePathSatisfiesOrderBy(
|
||||
** in the ORDER BY clause.
|
||||
*/
|
||||
for(i=0; i<pLoop->u.btree.nEq; i++){
|
||||
pTerm = pLoop->aTerm[i];
|
||||
pTerm = pLoop->aLTerm[i];
|
||||
if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))==0 ) continue;
|
||||
iColumn = pTerm->u.leftColumn;
|
||||
for(j=0; j<nOrderBy; j++){
|
||||
@@ -4784,7 +4846,7 @@ static int wherePathSatisfiesOrderBy(
|
||||
|
||||
/* Skip over == and IS NULL terms */
|
||||
if( j<pLoop->u.btree.nEq
|
||||
&& ((i = pLoop->aTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
|
||||
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
|
||||
){
|
||||
if( i & WO_ISNULL ) isOrderDistinct = 0;
|
||||
continue;
|
||||
@@ -4898,15 +4960,15 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
|
||||
** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation
|
||||
** error occurs.
|
||||
*/
|
||||
static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){
|
||||
static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
|
||||
int mxChoice; /* Maximum number of simultaneous paths tracked */
|
||||
int nLoop; /* Number of terms in the join */
|
||||
sqlite3 *db; /* The database connection */
|
||||
int iLoop; /* Loop counter over the terms of the join */
|
||||
int ii, jj; /* Loop counters */
|
||||
double rCost; /* Cost of a path */
|
||||
double mxCost; /* Maximum cost of a set of paths */
|
||||
double rSortCost; /* Cost to do a sort */
|
||||
WhereCost rCost; /* Cost of a path */
|
||||
WhereCost mxCost; /* Maximum cost of a set of paths */
|
||||
WhereCost rSortCost; /* Cost to do a sort */
|
||||
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
|
||||
WherePath *aFrom; /* All nFrom paths at the previous level */
|
||||
WherePath *aTo; /* The nTo best paths at the current level */
|
||||
@@ -4937,12 +4999,12 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){
|
||||
}
|
||||
|
||||
/* Seed the search with a single WherePath containing zero WhereLoops */
|
||||
aFrom[0].nRow = (double)1;
|
||||
aFrom[0].nRow = (WhereCost)1;
|
||||
nFrom = 1;
|
||||
|
||||
/* Precompute the cost of sorting the final result set, if the caller
|
||||
** to sqlite3WhereBegin() was concerned about sorting */
|
||||
rSortCost = (double)0;
|
||||
rSortCost = (WhereCost)0;
|
||||
if( pWInfo->pOrderBy==0 || nRowEst<=0.0 ){
|
||||
aFrom[0].isOrderedValid = 1;
|
||||
}else{
|
||||
@@ -5412,7 +5474,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
*/
|
||||
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
|
||||
notReady = ~(Bitmask)0;
|
||||
pWInfo->nRowOut = (double)1;
|
||||
pWInfo->nRowOut = (WhereCost)1;
|
||||
for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){
|
||||
Table *pTab; /* Table to open */
|
||||
int iDb; /* Index of database containing table/index */
|
||||
|
||||
Reference in New Issue
Block a user