diff options
author | drh <drh@noemail.net> | 2016-09-30 20:22:27 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2016-09-30 20:22:27 +0000 |
commit | 9b40d13f437429abae07b4e03fd18647696c98e4 (patch) | |
tree | 6a59bc8370f15a44eb9bc19aeba54b16fad74d0c /src/expr.c | |
parent | e05950d8788b721565043405f26afa3e0a8fdf5c (diff) | |
download | sqlite-9b40d13f437429abae07b4e03fd18647696c98e4.tar.gz sqlite-9b40d13f437429abae07b4e03fd18647696c98e4.zip |
Fix the Parse.aColCache column cache so that all of the valid entries are
in the first Parse.nColCache slots.
FossilOrigin-Name: 6028502059ccbd3699637b7a70a6d8ce1b7c3dad
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 126 |
1 files changed, 52 insertions, 74 deletions
diff --git a/src/expr.c b/src/expr.c index e8c245ec4..0640029cb 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2964,32 +2964,19 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ } } -#if defined(SQLITE_DEBUG) /* -** Verify the consistency of the column cache +** Erase column-cache entry number i */ -static int cacheIsValid(Parse *pParse){ - int i, n; - for(i=n=0; i<SQLITE_N_COLCACHE; i++){ - if( pParse->aColCache[i].iReg>0 ) n++; - } - return n==pParse->nColCache; -} -#endif - -/* -** Clear a cache entry. -*/ -static void cacheEntryClear(Parse *pParse, struct yColCache *p){ - if( p->tempReg ){ +static void cacheEntryClear(Parse *pParse, int i){ + if( pParse->aColCache[i].tempReg ){ if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){ - pParse->aTempReg[pParse->nTempReg++] = p->iReg; + pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; } - p->tempReg = 0; } - p->iReg = 0; pParse->nColCache--; - assert( pParse->db->mallocFailed || cacheIsValid(pParse) ); + if( i<pParse->nColCache ){ + pParse->aColCache[i] = pParse->aColCache[pParse->nColCache]; + } } @@ -3019,46 +3006,33 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){ ** that the object will never already be in cache. Verify this guarantee. */ #ifndef NDEBUG - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ - assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol ); + for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){ + assert( p->iTable!=iTab || p->iColumn!=iCol ); } #endif - /* Find an empty slot and replace it */ - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ - if( p->iReg==0 ){ - p->iLevel = pParse->iCacheLevel; - p->iTable = iTab; - p->iColumn = iCol; - p->iReg = iReg; - p->tempReg = 0; - p->lru = pParse->iCacheCnt++; - pParse->nColCache++; - assert( pParse->db->mallocFailed || cacheIsValid(pParse) ); - return; - } - } - - /* Replace the last recently used */ - minLru = 0x7fffffff; - idxLru = -1; - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ - if( p->lru<minLru ){ - idxLru = i; - minLru = p->lru; + /* If the cache is already full, delete the least recently used entry */ + if( pParse->nColCache>=SQLITE_N_COLCACHE ){ + minLru = 0x7fffffff; + idxLru = -1; + for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ + if( p->lru<minLru ){ + idxLru = i; + minLru = p->lru; + } } - } - if( ALWAYS(idxLru>=0) ){ p = &pParse->aColCache[idxLru]; - p->iLevel = pParse->iCacheLevel; - p->iTable = iTab; - p->iColumn = iCol; - p->iReg = iReg; - p->tempReg = 0; - p->lru = pParse->iCacheCnt++; - assert( cacheIsValid(pParse) ); - return; + }else{ + p = &pParse->aColCache[pParse->nColCache++]; } + + /* Add the new entry to the end of the cache */ + p->iLevel = pParse->iCacheLevel; + p->iTable = iTab; + p->iColumn = iCol; + p->iReg = iReg; + p->tempReg = 0; + p->lru = pParse->iCacheCnt++; } /* @@ -3066,13 +3040,14 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){ ** Purge the range of registers from the column cache. */ void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){ - struct yColCache *p; - if( iReg<=0 || pParse->nColCache==0 ) return; - p = &pParse->aColCache[SQLITE_N_COLCACHE-1]; - while(1){ - if( p->iReg >= iReg && p->iReg < iReg+nReg ) cacheEntryClear(pParse, p); - if( p==pParse->aColCache ) break; - p--; + int i = 0; + while( i<pParse->nColCache ){ + struct yColCache *p = &pParse->aColCache[i]; + if( p->iReg >= iReg && p->iReg < iReg+nReg ){ + cacheEntryClear(pParse, i); + }else{ + i++; + } } } @@ -3096,8 +3071,7 @@ void sqlite3ExprCachePush(Parse *pParse){ ** the cache to the state it was in prior the most recent Push. */ void sqlite3ExprCachePop(Parse *pParse){ - int i; - struct yColCache *p; + int i = 0; assert( pParse->iCacheLevel>=1 ); pParse->iCacheLevel--; #ifdef SQLITE_DEBUG @@ -3105,9 +3079,11 @@ void sqlite3ExprCachePop(Parse *pParse){ printf("POP to %d\n", pParse->iCacheLevel); } #endif - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ - if( p->iReg && p->iLevel>pParse->iCacheLevel ){ - cacheEntryClear(pParse, p); + while( i<pParse->nColCache ){ + if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){ + cacheEntryClear(pParse, i); + }else{ + i++; } } } @@ -3121,7 +3097,7 @@ void sqlite3ExprCachePop(Parse *pParse){ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){ int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ + for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){ if( p->iReg==iReg ){ p->tempReg = 0; } @@ -3199,7 +3175,7 @@ int sqlite3ExprCodeGetColumn( int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ + for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){ if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){ p->lru = pParse->iCacheCnt++; sqlite3ExprCachePinRegister(pParse, p->iReg); @@ -3232,18 +3208,20 @@ void sqlite3ExprCodeGetColumnToReg( */ void sqlite3ExprCacheClear(Parse *pParse){ int i; - struct yColCache *p; #if SQLITE_DEBUG if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ printf("CLEAR\n"); } #endif - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ - if( p->iReg ){ - cacheEntryClear(pParse, p); + for(i=0; i<pParse->nColCache; i++){ + if( pParse->aColCache[i].tempReg + && pParse->nTempReg<ArraySize(pParse->aTempReg) + ){ + pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; } } + pParse->nColCache = 0; } /* @@ -3275,7 +3253,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ + for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){ int r = p->iReg; if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/ } @@ -4971,7 +4949,7 @@ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){ int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){ + for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){ if( p->iReg==iReg ){ p->tempReg = 1; return; |