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
#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 */
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.
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 */
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 */
};
/*
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 */
};
** Return the estimated number of output rows from a WHERE clause
*/
double sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
- return pWInfo->nRowOut;
+ return (double)pWInfo->nRowOut;
}
/*
** 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;
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;
+ sizeof(*pIdxOrderBy)*nOrderBy );
if( pIdxInfo==0 ){
sqlite3ErrorMsg(pParse, "out of memory");
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
return 0;
}
int i, eType;
int isEq = 0;
i64 v;
- double r, rS;
+ WhereCost r, rS;
assert( roundUp==0 || roundUp==1 );
assert( pIdx->nSample>0 );
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;
}
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));*/
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;
}
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 */
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 );
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; */
*/
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;
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;
*/
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 );
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;
*/
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;
}
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 );
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;
}
}
+
+/*
+** 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
*/
** 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;
*/
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: ");
&& 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
}
#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;
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;
}
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;
}
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 );
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;
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 ){
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;
}
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;
}
pProbe = &sPk;
}
- rSize = (double)pSrc->pTab->nRowEst;
+ rSize = (WhereCost)pSrc->pTab->nRowEst;
rLogSize = estLog(rSize);
/* Automatic indexes */
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;
*/
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);
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 */
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 ){
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);
}
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 ){
}
}
}
- 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);
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
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;
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;
rc = whereLoopInsert(pBuilder, pNew);
}
}
+ whereLoopClear(pWInfo->pParse->db, &sBest);
return rc;
}
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;
/* 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);
mPrior |= pNew->maskSelf;
if( rc || db->mallocFailed ) break;
}
-whereLoopAddAll_end:
whereLoopDelete(db, pBuilder->pNew);
pBuilder->pNew = 0;
return rc;
** 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++){
/* 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;
** 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 */
}
/* 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{
*/
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 */