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:
74
src/expr.c
74
src/expr.c
@@ -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, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
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, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
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, ®Free1,
|
||||
pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2);
|
||||
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, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
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, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
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, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
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, ®Free1,
|
||||
pExpr->pRight, &r2, ®Free2);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
r1, r2, dest, SQLITE_NULLEQ);
|
||||
|
||||
Reference in New Issue
Block a user