From: drh Date: Thu, 6 Jun 2013 23:02:03 +0000 (+0000) Subject: Improved management of the space to hold WhereLoop.aLTerm[]. X-Git-Tag: version-3.8.0~130^2~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4efc9298fb4fde4f5001b8d0e3155bbde5cffcea;p=thirdparty%2Fsqlite.git Improved management of the space to hold WhereLoop.aLTerm[]. FossilOrigin-Name: d4141ecbea3abbe83525910684fbd89eb74eeb34 --- diff --git a/manifest b/manifest index 7068f05a1e..b68a0110a6 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 0f8825c921..bc7a4d415f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b4a5dbad36bceabc5c5350e7676af6ad42de04eb \ No newline at end of file +d4141ecbea3abbe83525910684fbd89eb74eeb34 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 21277f1d25..08569fc60b 100644 --- a/src/where.c +++ b/src/where.c @@ -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; pTermnTerma; pTermnLTermu.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; jaTerm[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; jaTerm[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; ju.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->nTermnTerm + if( p->nLTermnLTerm && (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; imxTerm; i++) pNew->aTerm[i] = 0; + assert( pNew->nLSlot>=nConstraint ); + for(i=0; iaLTerm[i] = 0; pNew->u.vtab.omitMask = 0; - for(i=0; inConstraint; i++, pIdxCons++){ + for(i=0; i=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( iTermnLSlot ); + pNew->aLTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<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; pTermeOperator & 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; iTabiTab = 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; iu.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; ju.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