From: drh Date: Mon, 31 Mar 2008 23:48:03 +0000 (+0000) Subject: Avoid duplicate OP_Column opcodes by remembering prior results. X-Git-Tag: version-3.6.10~1234 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e55cbd722839062c039f1162ce517e80d5219ccf;p=thirdparty%2Fsqlite.git Avoid duplicate OP_Column opcodes by remembering prior results. This is similar to CSE, but only applies to columns. (CVS 4943) FossilOrigin-Name: c29ee0fed23dcdbd9dde6b1e42b603100ea2389c --- diff --git a/manifest b/manifest index 34311a79cb..bdee46c43e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Factor\sconstant\ssubexpressions\sout\sof\sloops.\s(CVS\s4942) -D 2008-03-31T18:19:54 +C Avoid\sduplicate\sOP_Column\sopcodes\sby\sremembering\sprior\sresults.\nThis\sis\ssimilar\sto\sCSE,\sbut\sonly\sapplies\sto\scolumns.\s(CVS\s4943) +D 2008-03-31T23:48:04 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -93,14 +93,14 @@ F src/build.c 4e6321d112f0ed1070c579677573e4eb76cda1fd F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c e41ce4513fb0e359dc678d6bddb4ace135fe365d -F src/delete.c 3dc7d7cc46c8675219a7776b7c67b626bba530df +F src/delete.c 9573b07fbdaef0e68d63eb218e5874c7a162c727 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c d005510999ccc68301167fd3fcff21f133389379 +F src/expr.c 787f5fd4ee5ca58d4470603626f1b43ac2348faa F src/fault.c 83057e86815d473e526f7df0b0108dfdd022ff23 F src/func.c c9e8c7ff4c45027edee89bde7adbf86a3a3b2afe F src/hash.c 53655c312280211444bfe23af6490a460aec2980 F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 -F src/insert.c c491fbd4f852f0ba82e26b4aad279b2611c51e94 +F src/insert.c 803299d223bdb11ce32ab17c485cd93a9630d673 F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 8267890e6a0a71f13b680794520999c642299081 F src/loadext.c f26b22f7c84153c9d5dbd7c240848823c6e6b6dc @@ -135,12 +135,12 @@ F src/pragma.c e659c9e443d11854cff2fd250012365ae0ca81ba F src/prepare.c 185fb47f1fb3e45a345d523eb391d673f5eb367c F src/printf.c 05d2b44d7b5b80c8a4a09108ddad9c20e254370d F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a -F src/select.c 61fcc616b6c50da1a8f5604f9766e352f69760a8 +F src/select.c 0d1b44c9ef1b97c9f43fe663cd94713186896e77 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 22297fffa6f00a6c6d44020fa13b1184a1bb372d F src/sqlite.h.in b1ac824d9fc163a5d2226ebf5990b09a02a11117 F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3 -F src/sqliteInt.h 4d25edd2adb5f4be4c2b44c25533e0bbe69eb6e0 +F src/sqliteInt.h 79f4a09bc1e5b3ea50dae581294d8681b345a165 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a F src/tclsqlite.c 1367762764772a233643524c3585b4711a9adcda @@ -170,7 +170,7 @@ F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730 F src/tokenize.c 13113f94bd1c15dea9e922f08b10f3eee6863474 F src/trigger.c 9bd3b6fa0beff4a02d262c96466f752ec15a7fc3 -F src/update.c 2aefd3c9277792e9fa2414dfe14202119fa49fe7 +F src/update.c e23e83cf481b25d5fc7beb92efbb71d297712fd3 F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2 F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30 @@ -183,7 +183,7 @@ F src/vdbeblob.c cc713c142c3d4952b380c98ee035f850830ddbdb F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736 F src/vdbemem.c b96fea7b98cc662ad7b587f28560b0c5649ac39f F src/vtab.c 00cd16317b29495c185ff40e4b227917d5a371b2 -F src/where.c 902ddf1e7a737d19324d02de755fc816cc9cdba7 +F src/where.c 811fd1e5c67902499866d942dfa5f44550501adf F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test d12210212bada2bde6d5aeb90969b86c1aa977d2 @@ -619,7 +619,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P b266924b8975b69bdb9ab45cf462e41436f89cc2 -R 2c294fffeaf40038acaaca80e4e177dd +P 2126db39854c751aea6c95c67894ed9b9dfc0763 +R 4b1f8c1e4e6f9db1b293f92989ff9195 U drh -Z 39a34de4a0aac903f6ed893e46452e8f +Z ab18e0e600a8f0ab348be2f5f3f1ef8e diff --git a/manifest.uuid b/manifest.uuid index 1be4929771..5ca840bf53 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2126db39854c751aea6c95c67894ed9b9dfc0763 \ No newline at end of file +c29ee0fed23dcdbd9dde6b1e42b603100ea2389c \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index e91ec74a52..92b9ed56e9 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.164 2008/03/25 17:23:33 drh Exp $ +** $Id: delete.c,v 1.165 2008/03/31 23:48:04 drh Exp $ */ #include "sqliteInt.h" @@ -534,6 +534,7 @@ int sqlite3GenerateIndexKey( if( doMakeRec ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut); sqlite3IndexAffinityStr(v, pIdx); + sqlite3ExprExpireColumnCacheLines(pParse, regBase, regBase+nCol); } sqlite3ReleaseTempRange(pParse, regBase, nCol+1); return regBase; diff --git a/src/expr.c b/src/expr.c index 2fe48a5ff0..095c74aca8 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.358 2008/03/31 18:19:54 drh Exp $ +** $Id: expr.c,v 1.359 2008/03/31 23:48:04 drh Exp $ */ #include "sqliteInt.h" #include @@ -1779,8 +1779,11 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ } /* Evaluate the expression and insert it into the temp table */ + pParse->disableColCache++; sqlite3ExprCode(pParse, pE2, r1); + pParse->disableColCache--; sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); + sqlite3ExprExpireColumnCacheLines(pParse, r1, r1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); } sqlite3ReleaseTempReg(pParse, r1); @@ -1894,17 +1897,35 @@ static void codeInteger(Vdbe *v, const char *z, int n, int negFlag, int iMem){ /* ** Generate code that will extract the iColumn-th column from -** table pTab and store the column value in register iReg. -** There is an open cursor to pTab in -** iTable. If iColumn<0 then code is generated that extracts the rowid. +** table pTab and store the column value in a register. An effort +** is made to store the column value in register iReg, but this is +** not guaranteed. The location of the column value is returned. +** +** There must be an open cursor to pTab in iTable when this routine +** is called. If iColumn<0 then code is generated that extracts the rowid. */ -void sqlite3ExprCodeGetColumn( - Vdbe *v, /* The VM being created */ +int sqlite3ExprCodeGetColumn( + Parse *pParse, /* Parsing and code generating context */ 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 */ ){ + Vdbe *v = pParse->pVdbe; + int i; + + for(i=0; inColCache; i++){ + if( pParse->aColCache[i].iTable==iTable + && pParse->aColCache[i].iColumn==iColumn ){ +#if 0 + sqlite3VdbeAddOp0(v, OP_Noop); + VdbeComment((v, "OPT: tab%d.col%d -> r%d", + iTable, iColumn, pParse->aColCache[i].iReg)); +#endif + return pParse->aColCache[i].iReg; + } + } + assert( v!=0 ); if( iColumn<0 ){ int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid; sqlite3VdbeAddOp2(v, op, iTable, iReg); @@ -1920,6 +1941,79 @@ void sqlite3ExprCodeGetColumn( } #endif } + if( pParse->disableColCache==0 ){ + i = pParse->iColCache; + pParse->aColCache[i].iTable = iTable; + pParse->aColCache[i].iColumn = iColumn; + pParse->aColCache[i].iReg = iReg; + i++; + if( i>ArraySize(pParse->aColCache) ) i = 0; + if( i>pParse->nColCache ) pParse->nColCache = i; + } + return iReg; +} + +/* +** Disable (+1) or enable (-1) the adding of new column cache entries. +*/ +void sqlite3ExprColumnCacheDisable(Parse *pParse, int disable){ + assert( disable==-1 || disable==+1 ); + assert( pParse->disableColCache>0 || disable==1 ); + pParse->disableColCache += disable; +} + +/* +** Clear all column cache entries associated with the vdbe +** cursor with cursor number iTable. +*/ +void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){ + if( iTable<0 ){ + pParse->nColCache = 0; + pParse->iColCache = 0; + }else{ + int i; + for(i=0; inColCache; i++){ + if( pParse->aColCache[i].iTable==iTable ){ + pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache]; + } + } + pParse->iColCache = pParse->nColCache; + } +} + +/* +** Expire all column cache entry associated with register between +** iFrom and iTo, inclusive. If there are no column cache entries +** on those registers then this routine is a no-op. +** +** Call this routine when register contents are overwritten to +** make sure the new register value is not used in place of the +** value that was overwritten. +*/ +void sqlite3ExprExpireColumnCacheLines(Parse *pParse, int iFrom, int iTo){ + int i; + for(i=0; inColCache; i++){ + int r = pParse->aColCache[i].iReg; + if( r>=iFrom && r<=iTo ){ + pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache]; + } + } + pParse->iColCache = pParse->nColCache; +} + +/* +** Generate code to moves content from one register to another. +** Keep the column cache up-to-date. +*/ +void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo){ + int i; + if( iFrom==iTo ) return; + sqlite3VdbeAddOp2(pParse->pVdbe, OP_Move, iFrom, iTo); + for(i=0; inColCache; i++){ + if( pParse->aColCache[i].iReg==iFrom ){ + pParse->aColCache[i].iReg = iTo; + } + } } /* @@ -1971,7 +2065,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( pParse->ckBase>0 ); inReg = pExpr->iColumn + pParse->ckBase; }else{ - sqlite3ExprCodeGetColumn(v, pExpr->pTab, + inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, pExpr->iColumn, pExpr->iTable, target); } break; @@ -2096,7 +2190,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ }else{ regFree1 = r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Integer, 0, r1); - r2 = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); } inReg = target; @@ -2193,6 +2287,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ if( nExpr ){ sqlite3ReleaseTempRange(pParse, r1, nExpr); } + sqlite3ExprExpireColumnCacheLines(pParse, r1, r1+nExpr-1); break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -2236,6 +2331,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ }else{ r2 = regFree2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); + sqlite3ExprExpireColumnCacheLines(pParse, r1, r1); j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2); } sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); @@ -2321,6 +2417,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ aListelem = pEList->a; nExpr = pEList->nExpr; endLabel = sqlite3VdbeMakeLabel(v); + sqlite3ExprColumnCacheDisable(pParse, 1); if( (pX = pExpr->pLeft)!=0 ){ cacheX = *pX; cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, ®Free1); @@ -2348,6 +2445,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } sqlite3VdbeResolveLabel(v, endLabel); + sqlite3ExprColumnCacheDisable(pParse, -1); break; } #ifndef SQLITE_OMIT_TRIGGER @@ -2532,13 +2630,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); + pParse->disableColCache++; sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + pParse->disableColCache--; sqlite3VdbeResolveLabel(v, d2); break; } case TK_OR: { sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + pParse->disableColCache++; sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + pParse->disableColCache--; break; } case TK_NOT: { @@ -2664,13 +2766,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ switch( pExpr->op ){ case TK_AND: { sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + pParse->disableColCache++; sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + pParse->disableColCache--; break; } case TK_OR: { int d2 = sqlite3VdbeMakeLabel(v); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); + pParse->disableColCache++; sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + pParse->disableColCache--; sqlite3VdbeResolveLabel(v, d2); break; } @@ -2980,15 +3086,39 @@ void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){ } } +/* +** Return true if any register in the range iFrom..iTo (inclusive) +** is used as part of the column cache. +*/ +static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ + int i; + for(i=0; inColCache; i++){ + int r = pParse->aColCache[i].iReg; + if( r>=iFrom && r<=iTo ) return 1; + } + return 0; +} + /* ** Allocate or deallocate temporary use registers during code generation. */ int sqlite3GetTempReg(Parse *pParse){ - if( pParse->nTempReg ){ - return pParse->aTempReg[--pParse->nTempReg]; - }else{ + int i, r; + if( pParse->nTempReg==0 ){ return ++pParse->nMem; } + for(i=0; inTempReg; i++){ + r = pParse->aTempReg[i]; + if( usedAsColumnCache(pParse, r, r) ) continue; + } + if( i>=pParse->nTempReg ){ + return ++pParse->nMem; + } + while( inTempReg-1 ){ + pParse->aTempReg[i] = pParse->aTempReg[i+1]; + } + pParse->nTempReg--; + return r; } void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg && pParse->nTempRegaTempReg) ){ @@ -3001,9 +3131,10 @@ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ ** Allocate or deallocate a block of nReg consecutive registers */ int sqlite3GetTempRange(Parse *pParse, int nReg){ - int i; - if( nReg<=pParse->nRangeReg ){ - i = pParse->iRangeReg; + int i, n; + i = pParse->iRangeReg; + n = pParse->nRangeReg; + if( nReg<=n && !usedAsColumnCache(pParse, i, i+n-1) ){ pParse->iRangeReg += nReg; pParse->nRangeReg -= nReg; }else{ diff --git a/src/insert.c b/src/insert.c index f7950d0578..e075400bb0 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.233 2008/03/25 09:47:35 danielk1977 Exp $ +** $Id: insert.c,v 1.234 2008/03/31 23:48:05 drh Exp $ */ #include "sqliteInt.h" @@ -1171,6 +1171,7 @@ void sqlite3GenerateConstraintChecks( sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); sqlite3IndexAffinityStr(v, pIdx); + sqlite3ExprExpireColumnCacheLines(pParse, regIdx, regIdx+pIdx->nColumn); sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); /* Find out what action to take in case there is an indexing conflict */ @@ -1285,6 +1286,7 @@ void sqlite3CompleteInsertion( regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3TableAffinityStr(v, pTab); + sqlite3ExprExpireColumnCacheLines(pParse, regData, regData+pTab->nCol-1); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid); diff --git a/src/select.c b/src/select.c index 11a8cf9c39..df3c3a7e86 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.423 2008/03/31 17:41:18 danielk1977 Exp $ +** $Id: select.c,v 1.424 2008/03/31 23:48:05 drh Exp $ */ #include "sqliteInt.h" @@ -241,7 +241,6 @@ Expr *sqlite3CreateIdExpr(Parse *pParse, const char *zName){ return sqlite3PExpr(pParse, TK_ID, 0, 0, &dummy); } - /* ** Add a term to the WHERE expression in *ppExpr that requires the ** zCol column to be equal in the two tables pTab1 and pTab2. @@ -425,7 +424,7 @@ static void pushOntoSorter( int regRecord = sqlite3GetTempReg(pParse); sqlite3ExprCodeExprList(pParse, pOrderBy, regBase); sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); - sqlite3VdbeAddOp2(v, OP_Move, regData, regBase+nExpr+1); + sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); @@ -670,6 +669,7 @@ static void selectInnerLoop( }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1); + sqlite3ExprExpireColumnCacheLines(pParse, regResult, regResult); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); sqlite3ReleaseTempReg(pParse, r1); } @@ -694,7 +694,7 @@ static void selectInnerLoop( if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p, regResult); }else{ - sqlite3VdbeAddOp2(v, OP_Move, regResult, iParm); + sqlite3ExprCodeMove(pParse, regResult, iParm); /* The LIMIT clause will jump out of the loop for us */ } break; @@ -716,6 +716,7 @@ static void selectInnerLoop( sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn); + sqlite3ExprExpireColumnCacheLines(pParse,regResult,regResult+nColumn-1); } break; } @@ -834,13 +835,14 @@ static void generateSortTail( assert( nColumn==1 ); j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid, &p->affinity, 1); + sqlite3ExprExpireColumnCacheLines(pParse, regRow, regRow); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid); sqlite3VdbeJumpHere(v, j1); break; } case SRT_Mem: { assert( nColumn==1 ); - sqlite3VdbeAddOp2(v, OP_Move, regRow, iParm); + sqlite3ExprCodeMove(pParse, regRow, iParm); /* The LIMIT clause will terminate the loop for us */ break; } @@ -856,6 +858,8 @@ static void generateSortTail( } if( eDest==SRT_Callback ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn); + sqlite3ExprExpireColumnCacheLines(pParse, pDest->iMem, + pDest->iMem+nColumn-1); }else{ sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm); } @@ -2926,6 +2930,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ (void*)pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); + sqlite3ExprExpireColumnCacheLines(pParse, regAgg, regAgg+nArg-1); if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } @@ -3434,8 +3439,12 @@ int sqlite3Select( for(i=0; iiSorterColumn>=j ){ - sqlite3ExprCodeGetColumn(v, pCol->pTab, pCol->iColumn, pCol->iTable, - j + regBase); + int r1 = j + regBase; + int r2 = sqlite3ExprCodeGetColumn(pParse, + pCol->pTab, pCol->iColumn, pCol->iTable, r1); + if( r1!=r2 ){ + sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1); + } j++; } } @@ -3485,7 +3494,7 @@ int sqlite3Select( */ sqlite3VdbeResolveLabel(v, addrGroupByChange); for(j=0; jnExpr; j++){ - sqlite3VdbeAddOp2(v, OP_Move, iBMem+j, iAMem+j); + sqlite3ExprCodeMove(pParse, iBMem+j, iAMem+j); } sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrOutputRow); VdbeComment((v, "output one row")); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 308ed3e692..40b6bfedf3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.682 2008/03/31 18:19:54 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.683 2008/03/31 23:48:05 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1463,6 +1463,14 @@ 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 */ + struct { + int iTable; /* Table cursor number */ + int iColumn; /* Table column number */ + int iReg; /* Register holding value of this column */ + } aColCache[10]; /* One for each valid 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 */ @@ -1829,7 +1837,11 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8); void sqlite3WhereEnd(WhereInfo*); -void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int); +int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int); +void sqlite3ExprCodeMove(Parse*, int, int); +void sqlite3ExprClearColumnCache(Parse*, int); +void sqlite3ExprColumnCacheDisable(Parse*, int); +void sqlite3ExprExpireColumnCacheLines(Parse*, int, int); int sqlite3ExprCode(Parse*, Expr*, int); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); diff --git a/src/update.c b/src/update.c index 6f479a55db..daacd02c93 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.173 2008/03/25 09:47:35 danielk1977 Exp $ +** $Id: update.c,v 1.174 2008/03/31 23:48:05 drh Exp $ */ #include "sqliteInt.h" @@ -446,6 +446,7 @@ void sqlite3Update( sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRow); if( !isView ){ sqlite3TableAffinityStr(v, pTab); + sqlite3ExprExpireColumnCacheLines(pParse, regCols, regCols+pTab->nCol-1); } sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol); if( pParse->nErr ) goto update_cleanup; diff --git a/src/where.c b/src/where.c index d0643f7e0e..9a375b93a7 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.295 2008/03/31 18:19:54 drh Exp $ +** $Id: where.c,v 1.296 2008/03/31 23:48:05 drh Exp $ */ #include "sqliteInt.h" @@ -1729,16 +1729,19 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ ** problem. */ static void buildIndexProbe( - Vdbe *v, /* Generate code into this VM */ + Parse *pParse, /* Parsing and code generation context */ int nColumn, /* The number of columns to check for NULL */ Index *pIdx, /* Index that we will be searching */ int regSrc, /* Take values from this register */ int regDest /* Write the result into this register */ ){ + Vdbe *v = pParse->pVdbe; assert( regSrc>0 ); assert( regDest>0 ); + assert( v!=0 ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regSrc, nColumn, regDest); sqlite3IndexAffinityStr(v, pIdx); + sqlite3ExprExpireColumnCacheLines(pParse, regSrc, regSrc+nColumn-1); } @@ -2532,7 +2535,7 @@ WhereInfo *sqlite3WhereBegin( nCol++; topEq = 0; } - buildIndexProbe(v, nCol, pIdx, regBase, pLevel->iMem); + buildIndexProbe(pParse, nCol, pIdx, regBase, pLevel->iMem); if( bRev ){ int op = topEq ? OP_MoveLe : OP_MoveLt; sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, pLevel->iMem); @@ -2577,7 +2580,7 @@ WhereInfo *sqlite3WhereBegin( }else{ r1 = sqlite3GetTempReg(pParse); } - buildIndexProbe(v, nCol, pIdx, regBase, r1); + buildIndexProbe(pParse, nCol, pIdx, regBase, r1); if( !bRev ){ int op = btmEq ? OP_MoveGe : OP_MoveGt; sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); @@ -2638,16 +2641,16 @@ WhereInfo *sqlite3WhereBegin( && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq]) ){ isMinQuery = 1; - buildIndexProbe(v, nEq, pIdx, regBase, pLevel->iMem); + buildIndexProbe(pParse, nEq, pIdx, regBase, pLevel->iMem); sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); r1 = ++pParse->nMem; - buildIndexProbe(v, nEq+1, pIdx, regBase, r1); + buildIndexProbe(pParse, nEq+1, pIdx, regBase, r1); }else{ /* Generate a single key that will be used to both start and ** terminate the search */ r1 = pLevel->iMem; - buildIndexProbe(v, nEq, pIdx, regBase, r1); + buildIndexProbe(pParse, nEq, pIdx, regBase, r1); } /* Generate code (1) to move to the first matching element of the table. @@ -2722,6 +2725,8 @@ WhereInfo *sqlite3WhereBegin( pLevel->top = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); + sqlite3ExprClearColumnCache(pParse, pLevel->iTabCur); + sqlite3ExprClearColumnCache(pParse, pLevel->iIdxCur); for(pTerm=wc.a, j=0; jflags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & notReady)!=0 ) continue; @@ -2805,6 +2810,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Generate loop termination code. */ + sqlite3ExprClearColumnCache(pWInfo->pParse, -1); for(i=pTabList->nSrc-1; i>=0; i--){ pLevel = &pWInfo->a[i]; sqlite3VdbeResolveLabel(v, pLevel->cont);