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

@ -1,8 +1,8 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Move\sthe\squery\sflattener\sturn-off\sfrom\sa\spragma\sto\san\ssqlite3_test_control()\ncall.\s\sMake\sprovisions\s(not\syet\simplemented)\sto\sturn\soff\sother\soptimizers\nusing\sthe\ssame\scall.
D 2009-12-22T23:52:32
C Immediately\spurge\sentries\sfrom\sthe\scolumn\scache\swhen\sthe\sassociated\sregister\nundergoes\san\saffinity\schange.\s\sTicket\s[eb5548a849].\s\sEnhance\sthe\nSQLITE_TESTCTRL_OPTIMIZATIONS\ssetting\sof\ssqlite3_test_control\sso\sthat\sit\ncan\sdisable\sthe\scolumn\scache\sfor\stesting\spurposes,\sin\san\seffort\sto\sprevent\nfuture\sproblems\sof\sa\ssimilar\snature\sto\sthis\sone.
D 2009-12-24T16:00:29
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -118,8 +118,8 @@ F src/build.c 6ab7f8d8fa5b0ac6bfdce359e85f580b7a9b2e86
F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
F src/complete.c 4c8a742c4a4a6d9c835912648f5c8f032ea36c7b
F src/date.c a79c0a8f219370b972e320741f995a3bef9df33f
F src/delete.c 8b8afb9cd7783d573eae55a3f4208bc0637a2bb8
F src/expr.c 50385ed51f1cd7f1ab289629cd0f87d5b2fcca52
F src/delete.c 1425b44a1a8127ada4c909e8b71439354e523c24
F src/expr.c 6d138c36168ca68d37a19a375af10f5b806214fc
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
F src/func.c 69906340991919b4933dd8630774ad069e4d582e
@ -165,11 +165,11 @@ F src/printf.c 644bc7d59df3dc56d6d8b9a510914bfc6b51bc69
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c d052e5c44bab34f83b3c1741aaa07478d18b5dd5
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c 7e424c8fea32725dec2d86d06d98ffedd7fa5023
F src/select.c 71511cdee4393c4dbaaa6feeff6c860b3f7e4f5f
F src/shell.c b9fae60b0f2ce306c20fa99e83c75023bf35f15b
F src/sqlite.h.in 60cbf318765de59bb454e229bd2d5ec065dd686a
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
F src/sqliteInt.h 2612705b54169e0cd82740f4bf93d7284fe2536a
F src/sqliteInt.h 3b9eba31a66b2bcc7c0f51cbcf92ae273c883d73
F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
F src/status.c e651be6b30d397d86384c6867bc016e4913bcac7
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@ -222,7 +222,7 @@ F src/vdbemem.c 1e16e3a16e55f4c3452834f0e041726021aa66e0
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c 7c7713d66cda699f16bf1cc601d8d4f5070ab935
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c f20ee9a15c1ccb8b94cd31e3f8c6868e1358fc07
F src/where.c 5bf4b84dbd7b0129203562906340dded3de46543
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
@ -785,14 +785,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 37a1de02d1d8a34604f1bee896eaf579d4ba149a
R c2d4c8288e84ae9afb7a643682bb92e8
P 4a97c623f4e190134de4b2ca406e311034a74797
R becfd603a317957c894c09ed10d1cf47
U drh
Z 6449324b3eb75888a0748fac4f5b69aa
Z 823ba23042dadaf02b5d95ffa78418d3
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFLMVvDoxKgR168RlERArP6AJ9MsqPf1HHWZPNd9R2EyQa4uKZbCgCcCRSF
ZONbln7b9xypgxaX8ksQh18=
=pFNF
iD8DBQFLM5AgoxKgR168RlERArV4AJ9/5N6dJdz2JusC+5zWn7ZEq+ZJdQCdFCUl
ifDSVjdF1pkT8+LtcL0nAJ8=
=ip6B
-----END PGP SIGNATURE-----

View File

@ -1 +1 @@
4a97c623f4e190134de4b2ca406e311034a74797
ea4e57e1c1b6663ceb12872e31a8503f6c14e3d8

View File

@ -364,7 +364,7 @@ void sqlite3DeleteFrom(
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK);
if( pWInfo==0 ) goto delete_from_cleanup;
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);

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);

View File

@ -3917,7 +3917,7 @@ int sqlite3Select(
int r2;
r2 = sqlite3ExprCodeGetColumn(pParse,
pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
pCol->pTab, pCol->iColumn, pCol->iTable, r1);
if( r1!=r2 ){
sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
}

View File

@ -930,10 +930,10 @@ struct sqlite3 {
** These must be the low-order bits of the flags field.
*/
#define SQLITE_QueryFlattener 0x01 /* Disable query flattening */
#define SQLITE_IndexSort 0x02 /* Disable indexes for sorting */
#define SQLITE_IndexSearch 0x04 /* Disable indexes for searching */
#define SQLITE_IndexCover 0x08 /* Disable index covering table */
#define SQLITE_RegisterReuse 0x10 /* Disable register reuse */
#define SQLITE_ColumnCache 0x02 /* Disable the column cache */
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
/*
@ -1648,14 +1648,13 @@ struct Expr {
#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
#define EP_IntValue 0x0800 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */
#define EP_Reduced 0x1000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x2000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
#define EP_Static 0x4000 /* Held in memory not obtained from malloc() */
/*
** The following are the meanings of bits in the Expr.flags2 field.
@ -2133,7 +2132,6 @@ struct Parse {
struct yColCache {
int iTable; /* Table cursor number */
int iColumn; /* Table column number */
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. */
@ -2652,7 +2650,7 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
void sqlite3ExprCodeCopy(Parse*, int, int, int);
void sqlite3ExprCacheStore(Parse*, int, int, int);

View File

@ -3336,7 +3336,7 @@ static Bitmask codeOneLoopStart(
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
int r;
r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
regRowid, 0);
regRowid);
sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
sqlite3VdbeCurrentAddr(v)+2, r, iSet);
}