aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c4
-rw-r--r--src/expr.c262
-rw-r--r--src/select.c11
-rw-r--r--src/sqliteInt.h32
-rw-r--r--src/trigger.c4
-rw-r--r--src/where.c22
6 files changed, 221 insertions, 114 deletions
diff --git a/src/build.c b/src/build.c
index 987a90c99..73d2f5ca7 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
-** $Id: build.c,v 1.529 2009/04/20 17:43:03 drh Exp $
+** $Id: build.c,v 1.530 2009/04/23 13:22:43 drh Exp $
*/
#include "sqliteInt.h"
@@ -190,7 +190,7 @@ void sqlite3FinishCoding(Parse *pParse){
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqlite3VdbeTrace(v, trace);
#endif
- assert( pParse->disableColCache==0 ); /* Disables and re-enables match */
+ assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
pParse->nTab, pParse->explain);
pParse->rc = SQLITE_DONE;
diff --git a/src/expr.c b/src/expr.c
index b7d30412b..003480c7d 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.427 2009/04/22 17:15:03 drh Exp $
+** $Id: expr.c,v 1.428 2009/04/23 13:22:43 drh Exp $
*/
#include "sqliteInt.h"
@@ -1463,7 +1463,7 @@ void sqlite3CodeSubselect(
int testAddr = 0; /* One-time test address */
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
-
+ sqlite3ExprCachePush(pParse);
/* This code must be run in its entirety every time it is encountered
** if any of the following is true:
@@ -1570,11 +1570,7 @@ void sqlite3CodeSubselect(
}
/* Evaluate the expression and insert it into the temp table */
- pParse->disableColCache++;
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
- assert( pParse->disableColCache>0 );
- pParse->disableColCache--;
-
if( isRowid ){
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2);
sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
@@ -1628,6 +1624,7 @@ void sqlite3CodeSubselect(
if( testAddr ){
sqlite3VdbeJumpHere(v, testAddr-1);
}
+ sqlite3ExprCachePop(pParse, 1);
return;
}
@@ -1705,6 +1702,120 @@ static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
}
}
+/*
+** Clear a cache entry.
+*/
+static void cacheEntryClear(Parse *pParse, struct yColCache *p){
+ if( p->tempReg ){
+ if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
+ pParse->aTempReg[pParse->nTempReg++] = p->iReg;
+ }
+ p->tempReg = 0;
+ }
+}
+
+
+/*
+** Record in the column cache that a particular column from a
+** particular table is stored in a particular register.
+*/
+void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
+ int i;
+ int minLru;
+ int idxLru;
+ struct yColCache *p;
+
+ /* First replace any existing entry */
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ if( p->iReg && p->iTable==iTab && p->iColumn==iCol ){
+ cacheEntryClear(pParse, p);
+ p->iLevel = pParse->iCacheLevel;
+ p->iReg = iReg;
+ p->affChange = 0;
+ p->lru = pParse->iCacheCnt++;
+ return;
+ }
+ }
+ if( iReg<=0 ) return;
+
+ /* 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->affChange = 0;
+ p->tempReg = 0;
+ p->lru = pParse->iCacheCnt++;
+ 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( idxLru>=0 ){
+ p = &pParse->aColCache[idxLru];
+ p->iLevel = pParse->iCacheLevel;
+ p->iTable = iTab;
+ p->iColumn = iCol;
+ p->iReg = iReg;
+ p->affChange = 0;
+ p->tempReg = 0;
+ p->lru = pParse->iCacheCnt++;
+ return;
+ }
+}
+
+/*
+** Indicate that a register is being overwritten. Purge the register
+** from the column cache.
+*/
+void sqlite3ExprCacheRemove(Parse *pParse, int iReg){
+ int i;
+ struct yColCache *p;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ if( p->iReg==iReg ){
+ cacheEntryClear(pParse, p);
+ p->iReg = 0;
+ }
+ }
+}
+
+/*
+** Remember the current column cache context. Any new entries added
+** added to the column cache after this call are removed when the
+** corresponding pop occurs.
+*/
+void sqlite3ExprCachePush(Parse *pParse){
+ pParse->iCacheLevel++;
+}
+
+/*
+** Remove from the column cache any entries that were added since the
+** the previous N Push operations. In other words, restore the cache
+** to the state it was in N Pushes ago.
+*/
+void sqlite3ExprCachePop(Parse *pParse, int N){
+ int i;
+ struct yColCache *p;
+ assert( N>0 );
+ assert( pParse->iCacheLevel>=N );
+ pParse->iCacheLevel -= N;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ if( p->iReg && p->iLevel>pParse->iCacheLevel ){
+ cacheEntryClear(pParse, p);
+ p->iReg = 0;
+ }
+ }
+}
/*
** Generate code that will extract the iColumn-th column from
@@ -1733,13 +1844,15 @@ int sqlite3ExprCodeGetColumn(
int i;
struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
- if( p->iTable==iTable && p->iColumn==iColumn
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn
&& (!p->affChange || allowAffChng) ){
#if 0
sqlite3VdbeAddOp0(v, OP_Noop);
VdbeComment((v, "OPT: tab%d.col%d -> r%d", iTable, iColumn, p->iReg));
#endif
+ p->lru = pParse->iCacheCnt++;
+ p->tempReg = 0; /* This pins the register, but also leaks it */
return p->iReg;
}
}
@@ -1758,37 +1871,21 @@ int sqlite3ExprCodeGetColumn(
}
#endif
}
- if( pParse->disableColCache==0 ){
- i = pParse->iColCache;
- p = &pParse->aColCache[i];
- p->iTable = iTable;
- p->iColumn = iColumn;
- p->iReg = iReg;
- p->affChange = 0;
- i++;
- if( i>=ArraySize(pParse->aColCache) ) i = 0;
- if( i>pParse->nColCache ) pParse->nColCache = i;
- pParse->iColCache = i;
- }
+ sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
return iReg;
}
/*
-** Clear all column cache entries associated with the vdbe
-** cursor with cursor number iTable.
+** Clear all column cache entries.
*/
-void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){
- if( iTable<0 ){
- pParse->nColCache = 0;
- pParse->iColCache = 0;
- }else{
- int i;
- for(i=0; i<pParse->nColCache; i++){
- if( pParse->aColCache[i].iTable==iTable ){
- testcase( i==pParse->nColCache-1 );
- pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache];
- pParse->iColCache = pParse->nColCache;
- }
+void sqlite3ExprCacheClear(Parse *pParse){
+ int i;
+ struct yColCache *p;
+
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ if( p->iReg ){
+ cacheEntryClear(pParse, p);
+ p->iReg = 0;
}
}
}
@@ -1800,10 +1897,11 @@ void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){
void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
int iEnd = iStart + iCount - 1;
int i;
- for(i=0; i<pParse->nColCache; i++){
- int r = pParse->aColCache[i].iReg;
+ struct yColCache *p;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ int r = p->iReg;
if( r>=iStart && r<=iEnd ){
- pParse->aColCache[i].affChange = 1;
+ p->affChange = 1;
}
}
}
@@ -1814,12 +1912,13 @@ void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
*/
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
int i;
+ struct yColCache *p;
if( iFrom==iTo ) return;
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
- for(i=0; i<pParse->nColCache; i++){
- int x = pParse->aColCache[i].iReg;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ int x = p->iReg;
if( x>=iFrom && x<iFrom+nReg ){
- pParse->aColCache[i].iReg += iTo-iFrom;
+ p->iReg += iTo-iFrom;
}
}
}
@@ -1842,33 +1941,15 @@ void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
*/
static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
int i;
- for(i=0; i<pParse->nColCache; i++){
- int r = pParse->aColCache[i].iReg;
+ struct yColCache *p;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ int r = p->iReg;
if( r>=iFrom && r<=iTo ) return 1;
}
return 0;
}
/*
-** There is a value in register iReg.
-**
-** We are going to modify the value, so we need to make sure it
-** is not a cached register. If iReg is a cached register,
-** then clear the corresponding cache line.
-*/
-void sqlite3ExprWritableRegister(Parse *pParse, int iReg){
- int i;
- if( usedAsColumnCache(pParse, iReg, iReg) ){
- for(i=0; i<pParse->nColCache; i++){
- if( pParse->aColCache[i].iReg==iReg ){
- pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache];
- pParse->iColCache = pParse->nColCache;
- }
- }
- }
-}
-
-/*
** If the last instruction coded is an ephemeral copy of any of
** the registers in the nReg registers beginning with iReg, then
** convert the last instruction from OP_SCopy to OP_Copy.
@@ -1905,6 +1986,7 @@ void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
** alias has not yet been computed.
*/
static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
+#if 0
sqlite3 *db = pParse->db;
int iReg;
if( pParse->nAliasAlloc<pParse->nAlias ){
@@ -1919,7 +2001,7 @@ static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
assert( iAlias>0 && iAlias<=pParse->nAlias );
iReg = pParse->aAlias[iAlias-1];
if( iReg==0 ){
- if( pParse->disableColCache ){
+ if( pParse->iCacheLevel>0 ){
iReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
}else{
iReg = ++pParse->nMem;
@@ -1928,6 +2010,9 @@ static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
}
}
return iReg;
+#else
+ return sqlite3ExprCodeTarget(pParse, pExpr, target);
+#endif
}
/*
@@ -2307,9 +2392,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
/* Code the <expr> from "<expr> IN (...)". The temporary table
** pExpr->iTable contains the values that make up the (...) set.
*/
- pParse->disableColCache++;
+ sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pExpr->pLeft, target);
- pParse->disableColCache--;
j2 = sqlite3VdbeAddOp1(v, OP_IsNull, target);
if( eType==IN_INDEX_ROWID ){
j3 = sqlite3VdbeAddOp1(v, OP_MustBeInt, target);
@@ -2370,6 +2454,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
sqlite3VdbeJumpHere(v, j2);
sqlite3VdbeJumpHere(v, j5);
+ sqlite3ExprCachePop(pParse, 1);
VdbeComment((v, "end IN expr r%d", target));
break;
}
@@ -2446,6 +2531,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
Expr cacheX; /* Cached expression X */
Expr *pX; /* The X expression */
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
+ VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; )
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
assert((pExpr->x.pList->nExpr % 2) == 0);
@@ -2464,8 +2550,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
opCompare.pLeft = &cacheX;
pTest = &opCompare;
}
- pParse->disableColCache++;
for(i=0; i<nExpr; i=i+2){
+ sqlite3ExprCachePush(pParse);
if( pX ){
assert( pTest!=0 );
opCompare.pRight = aListelem[i].pExpr;
@@ -2479,16 +2565,18 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
testcase( aListelem[i+1].pExpr->op==TK_REGISTER );
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
+ sqlite3ExprCachePop(pParse, 1);
sqlite3VdbeResolveLabel(v, nextCase);
}
if( pExpr->pRight ){
+ sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pExpr->pRight, target);
+ sqlite3ExprCachePop(pParse, 1);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
}
+ assert( pParse->iCacheLevel==iCacheLevel );
sqlite3VdbeResolveLabel(v, endLabel);
- assert( pParse->disableColCache>0 );
- pParse->disableColCache--;
break;
}
#ifndef SQLITE_OMIT_TRIGGER
@@ -2763,23 +2851,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_AND: {
int d2 = sqlite3VdbeMakeLabel(v);
testcase( jumpIfNull==0 );
- testcase( pParse->disableColCache==0 );
+ sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
- pParse->disableColCache++;
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
- assert( pParse->disableColCache>0 );
- pParse->disableColCache--;
sqlite3VdbeResolveLabel(v, d2);
+ sqlite3ExprCachePop(pParse, 1);
break;
}
case TK_OR: {
testcase( jumpIfNull==0 );
- testcase( pParse->disableColCache==0 );
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
- pParse->disableColCache++;
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
- assert( pParse->disableColCache>0 );
- pParse->disableColCache--;
break;
}
case TK_NOT: {
@@ -2923,24 +3005,18 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
switch( pExpr->op ){
case TK_AND: {
testcase( jumpIfNull==0 );
- testcase( pParse->disableColCache==0 );
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
- pParse->disableColCache++;
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- assert( pParse->disableColCache>0 );
- pParse->disableColCache--;
break;
}
case TK_OR: {
int d2 = sqlite3VdbeMakeLabel(v);
testcase( jumpIfNull==0 );
- testcase( pParse->disableColCache==0 );
+ sqlite3ExprCachePush(pParse);
sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
- pParse->disableColCache++;
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- assert( pParse->disableColCache>0 );
- pParse->disableColCache--;
sqlite3VdbeResolveLabel(v, d2);
+ sqlite3ExprCachePop(pParse, 1);
break;
}
case TK_NOT: {
@@ -3276,7 +3352,7 @@ void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
}
/*
-** Allocate or deallocate temporary use registers during code generation.
+** Allocate a single new register for use to hold some intermediate result.
*/
int sqlite3GetTempReg(Parse *pParse){
if( pParse->nTempReg==0 ){
@@ -3284,9 +3360,25 @@ int sqlite3GetTempReg(Parse *pParse){
}
return pParse->aTempReg[--pParse->nTempReg];
}
+
+/*
+** Deallocate a register, making available for reuse for some other
+** purpose.
+**
+** If a register is currently being used by the column cache, then
+** the dallocation is deferred until the column cache line that uses
+** the register becomes stale.
+*/
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
- sqlite3ExprWritableRegister(pParse, iReg);
+ int i;
+ struct yColCache *p;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ if( p->iReg==iReg ){
+ p->tempReg = 1;
+ return;
+ }
+ }
pParse->aTempReg[pParse->nTempReg++] = iReg;
}
}
diff --git a/src/select.c b/src/select.c
index 98afa508e..f00f708f0 100644
--- a/src/select.c
+++ b/src/select.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.508 2009/04/16 00:24:24 drh Exp $
+** $Id: select.c,v 1.509 2009/04/23 13:22:43 drh Exp $
*/
#include "sqliteInt.h"
@@ -421,6 +421,7 @@ static void pushOntoSorter(
int nExpr = pOrderBy->nExpr;
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
int regRecord = sqlite3GetTempReg(pParse);
+ sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
@@ -573,6 +574,7 @@ static void selectInnerLoop(
/* If the destination is an EXISTS(...) expression, the actual
** values returned by the SELECT are not required.
*/
+ sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pEList, regResult, eDest==SRT_Output);
}
nColumn = nResultCol;
@@ -1346,6 +1348,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
** The current implementation interprets "LIMIT 0" to mean
** no rows.
*/
+ sqlite3ExprCacheClear(pParse);
if( p->pLimit ){
p->iLimit = iLimit = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
@@ -3456,6 +3459,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
struct AggInfo_col *pC;
pAggInfo->directMode = 1;
+ sqlite3ExprCacheClear(pParse);
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
int addrNext = 0;
@@ -3495,12 +3499,14 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
if( addrNext ){
sqlite3VdbeResolveLabel(v, addrNext);
+ sqlite3ExprCacheClear(pParse);
}
}
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
pAggInfo->directMode = 0;
+ sqlite3ExprCacheClear(pParse);
}
/*
@@ -3918,6 +3924,7 @@ int sqlite3Select(
}
}
regBase = sqlite3GetTempRange(pParse, nCol);
+ sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
j = nGroupBy+1;
@@ -3944,6 +3951,7 @@ int sqlite3Select(
sqlite3VdbeAddOp2(v, OP_Sort, sAggInfo.sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort"));
sAggInfo.useSortingIdx = 1;
+ sqlite3ExprCacheClear(pParse);
}
/* Evaluate the current GROUP BY terms and store in b0, b1, b2...
@@ -3952,6 +3960,7 @@ int sqlite3Select(
** from the previous row currently stored in a0, a1, a2...
*/
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
+ sqlite3ExprCacheClear(pParse);
for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sAggInfo.sortingIdx, j, iBMem+j);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 66a22ded1..51729d16c 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.859 2009/04/22 15:32:59 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.860 2009/04/23 13:22:44 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1894,6 +1894,13 @@ struct SelectDest {
};
/*
+** Size of the column cache
+*/
+#ifndef SQLITE_N_COLCACHE
+# define SQLITE_N_COLCACHE 10
+#endif
+
+/*
** An SQL parser context. A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
** carry around information that is global to the entire parse.
@@ -1929,15 +1936,19 @@ struct Parse {
int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets used so far */
int ckBase; /* Base register of data during check constraints */
- int disableColCache; /* True to disable adding to column cache */
- int nColCache; /* Number of entries in the column cache */
- int iColCache; /* Next entry of the cache to replace */
+ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
+ int iCacheCnt; /* Counter used to generate aColCache[].lru values */
+ u8 nColCache; /* Number of entries in the column cache */
+ u8 iColCache; /* Next entry of the cache to replace */
struct yColCache {
int iTable; /* Table cursor number */
int iColumn; /* Table column number */
- char affChange; /* True if this register has had an affinity change */
- int iReg; /* Register holding value of this column */
- } aColCache[10]; /* One for each valid column cache entry */
+ u8 affChange; /* True if this register has had an affinity change */
+ u8 tempReg; /* iReg is a temp register that needs to be freed */
+ int iLevel; /* Nesting level */
+ int iReg; /* Reg with value of this column. 0 means none. */
+ int lru; /* Least recently used entry has the smallest value */
+ } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
u32 writeMask; /* Start a write transaction on these databases */
u32 cookieMask; /* Bitmask of schema verified databases */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
@@ -2446,9 +2457,12 @@ void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
void sqlite3ExprCodeCopy(Parse*, int, int, int);
-void sqlite3ExprClearColumnCache(Parse*, int);
+void sqlite3ExprCacheStore(Parse*, int, int, int);
+void sqlite3ExprCachePush(Parse*);
+void sqlite3ExprCachePop(Parse*, int);
+void sqlite3ExprCacheRemove(Parse*, int);
+void sqlite3ExprCacheClear(Parse*);
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
-void sqlite3ExprWritableRegister(Parse*,int);
void sqlite3ExprHardCopy(Parse*,int,int);
int sqlite3ExprCode(Parse*, Expr*, int);
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
diff --git a/src/trigger.c b/src/trigger.c
index 34b3f099d..98a49eddc 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -10,7 +10,7 @@
*************************************************************************
**
**
-** $Id: trigger.c,v 1.135 2009/02/28 10:47:42 danielk1977 Exp $
+** $Id: trigger.c,v 1.136 2009/04/23 13:22:44 drh Exp $
*/
#include "sqliteInt.h"
@@ -689,7 +689,7 @@ static int codeTriggerProgram(
sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0);
VdbeComment((v, "begin trigger %s", pStepList->pTrig->name));
while( pTriggerStep ){
- sqlite3ExprClearColumnCache(pParse, -1);
+ sqlite3ExprCacheClear(pParse);
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
diff --git a/src/where.c b/src/where.c
index 3b81602fb..3fa674d11 100644
--- a/src/where.c
+++ b/src/where.c
@@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
-** $Id: where.c,v 1.387 2009/04/22 17:15:03 drh Exp $
+** $Id: where.c,v 1.388 2009/04/23 13:22:44 drh Exp $
*/
#include "sqliteInt.h"
@@ -2469,20 +2469,16 @@ static Bitmask codeOneLoopStart(
pVtabIdx->aConstraint;
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
- pParse->disableColCache++;
for(j=1; j<=nConstraint; j++){
for(k=0; k<nConstraint; k++){
if( aUsage[k].argvIndex==j ){
int iTerm = aConstraint[k].iTermOffset;
- assert( pParse->disableColCache );
sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1);
break;
}
}
if( k==nConstraint ) break;
}
- assert( pParse->disableColCache );
- pParse->disableColCache--;
sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr,
@@ -2517,6 +2513,7 @@ static Bitmask codeOneLoopStart(
addrNxt = pLevel->addrNxt;
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
VdbeComment((v, "pk"));
pLevel->op = OP_Noop;
}else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){
@@ -2586,6 +2583,7 @@ static Bitmask codeOneLoopStart(
if( testOp!=OP_Noop ){
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
}
@@ -2712,12 +2710,7 @@ static Bitmask codeOneLoopStart(
/* Seek the index cursor to the start of the range. */
nConstraint = nEq;
if( pRangeStart ){
- int dcc = pParse->disableColCache;
- if( pRangeEnd ){
- pParse->disableColCache++;
- }
sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
- pParse->disableColCache = dcc;
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
nConstraint++;
}else if( isMinQuery ){
@@ -2743,6 +2736,7 @@ static Bitmask codeOneLoopStart(
*/
nConstraint = nEq;
if( pRangeEnd ){
+ sqlite3ExprCacheRemove(pParse, regBase+nEq);
sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
@@ -2782,6 +2776,7 @@ static Bitmask codeOneLoopStart(
if( !omitTable ){
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */
}
@@ -2939,9 +2934,7 @@ static Bitmask codeOneLoopStart(
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
continue;
}
- pParse->disableColCache += k;
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
- pParse->disableColCache -= k;
k = 1;
pTerm->wtFlags |= TERM_CODED;
}
@@ -2953,8 +2946,7 @@ static Bitmask codeOneLoopStart(
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
VdbeComment((v, "record LEFT JOIN hit"));
- sqlite3ExprClearColumnCache(pParse, pLevel->iTabCur);
- sqlite3ExprClearColumnCache(pParse, pLevel->iIdxCur);
+ sqlite3ExprCacheClear(pParse);
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
@@ -3507,7 +3499,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
/* Generate loop termination code.
*/
- sqlite3ExprClearColumnCache(pParse, -1);
+ sqlite3ExprCacheClear(pParse);
for(i=pTabList->nSrc-1; i>=0; i--){
pLevel = &pWInfo->a[i];
sqlite3VdbeResolveLabel(v, pLevel->addrCont);