1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-08 03:22:21 +03:00

Immediately purge entries from the column cache when the associated register

undergoes an affinity change.  Ticket [eb5548a849].  Enhance the
SQLITE_TESTCTRL_OPTIMIZATIONS setting of sqlite3_test_control so that it
can disable the column cache for testing purposes, in an effort to prevent
future problems of a similar nature to this one.

FossilOrigin-Name: ea4e57e1c1b6663ceb12872e31a8503f6c14e3d8
This commit is contained in:
drh
2009-12-24 16:00:28 +00:00
parent 07096f68ae
commit b6da74ebd5
7 changed files with 53 additions and 79 deletions

View File

@@ -227,30 +227,6 @@ CollSeq *sqlite3BinaryCompareCollSeq(
return pColl;
}
/*
** Generate the operands for a comparison operation. Before
** generating the code for each operand, set the EP_AnyAff
** flag on the expression so that it will be able to used a
** cached column value that has previously undergone an
** affinity change.
*/
static void codeCompareOperands(
Parse *pParse, /* Parsing and code generating context */
Expr *pLeft, /* The left operand */
int *pRegLeft, /* Register where left operand is stored */
int *pFreeLeft, /* Free this register when done */
Expr *pRight, /* The right operand */
int *pRegRight, /* Register where right operand is stored */
int *pFreeRight /* Write temp register for right operand there */
){
while( pLeft->op==TK_UPLUS ) pLeft = pLeft->pLeft;
pLeft->flags |= EP_AnyAff;
*pRegLeft = sqlite3ExprCodeTemp(pParse, pLeft, pFreeLeft);
while( pRight->op==TK_UPLUS ) pRight = pRight->pLeft;
pRight->flags |= EP_AnyAff;
*pRegRight = sqlite3ExprCodeTemp(pParse, pRight, pFreeRight);
}
/*
** Generate code for a comparison operator.
*/
@@ -1982,13 +1958,18 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
assert( iReg>0 ); /* Register numbers are always positive */
assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */
/* The SQLITE_ColumnCache flag disables the column cache. This is used
** for testing only - to verify that SQLite always gets the same answer
** with and without the column cache.
*/
if( pParse->db->flags & SQLITE_ColumnCache ) return;
/* 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;
}
@@ -2001,7 +1982,6 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
p->iTable = iTab;
p->iColumn = iCol;
p->iReg = iReg;
p->affChange = 0;
p->tempReg = 0;
p->lru = pParse->iCacheCnt++;
return;
@@ -2023,7 +2003,6 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
p->iTable = iTab;
p->iColumn = iCol;
p->iReg = iReg;
p->affChange = 0;
p->tempReg = 0;
p->lru = pParse->iCacheCnt++;
return;
@@ -2109,16 +2088,14 @@ int sqlite3ExprCodeGetColumn(
Table *pTab, /* Description of the table we are reading from */
int iColumn, /* Index of the table column */
int iTable, /* The cursor pointing to the table */
int iReg, /* Store results here */
int allowAffChng /* True if prior affinity changes are OK */
int iReg /* Store results here */
){
Vdbe *v = pParse->pVdbe;
int i;
struct yColCache *p;
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( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){
p->lru = pParse->iCacheCnt++;
sqlite3ExprCachePinRegister(pParse, p->iReg);
return p->iReg;
@@ -2162,7 +2139,8 @@ void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
int r = p->iReg;
if( r>=iStart && r<=iEnd ){
p->affChange = 1;
cacheEntryClear(pParse, p);
p->iReg = 0;
}
}
}
@@ -2329,10 +2307,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
assert( pParse->ckBase>0 );
inReg = pExpr->iColumn + pParse->ckBase;
}else{
testcase( (pExpr->flags & EP_AnyAff)!=0 );
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
pExpr->iColumn, pExpr->iTable, target,
pExpr->flags & EP_AnyAff);
pExpr->iColumn, pExpr->iTable, target);
}
break;
}
@@ -2449,8 +2425,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
testcase( op==TK_GE );
testcase( op==TK_EQ );
testcase( op==TK_NE );
codeCompareOperands(pParse, pExpr->pLeft, &r1, &regFree1,
pExpr->pRight, &r2, &regFree2);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, inReg, SQLITE_STOREP2);
testcase( regFree1==0 );
@@ -2461,8 +2437,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
case TK_ISNOT: {
testcase( op==TK_IS );
testcase( op==TK_ISNOT );
codeCompareOperands(pParse, pExpr->pLeft, &r1, &regFree1,
pExpr->pRight, &r2, &regFree2);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
op = (op==TK_IS) ? TK_EQ : TK_NE;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
@@ -2702,8 +2678,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
struct ExprList_item *pLItem = pExpr->x.pList->a;
Expr *pRight = pLItem->pExpr;
codeCompareOperands(pParse, pLeft, &r1, &regFree1,
pRight, &r2, &regFree2);
r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
testcase( regFree1==0 );
testcase( regFree2==0 );
r3 = sqlite3GetTempReg(pParse);
@@ -3238,8 +3214,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
testcase( op==TK_EQ );
testcase( op==TK_NE );
testcase( jumpIfNull==0 );
codeCompareOperands(pParse, pExpr->pLeft, &r1, &regFree1,
pExpr->pRight, &r2, &regFree2);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, jumpIfNull);
testcase( regFree1==0 );
@@ -3250,8 +3226,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_ISNOT: {
testcase( op==TK_IS );
testcase( op==TK_ISNOT );
codeCompareOperands(pParse, pExpr->pLeft, &r1, &regFree1,
pExpr->pRight, &r2, &regFree2);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
op = (op==TK_IS) ? TK_EQ : TK_NE;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, SQLITE_NULLEQ);
@@ -3381,8 +3357,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
testcase( op==TK_EQ );
testcase( op==TK_NE );
testcase( jumpIfNull==0 );
codeCompareOperands(pParse, pExpr->pLeft, &r1, &regFree1,
pExpr->pRight, &r2, &regFree2);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, jumpIfNull);
testcase( regFree1==0 );
@@ -3393,8 +3369,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_ISNOT: {
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_ISNOT );
codeCompareOperands(pParse, pExpr->pLeft, &r1, &regFree1,
pExpr->pRight, &r2, &regFree2);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, SQLITE_NULLEQ);