]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Avoid duplicate OP_Column opcodes by remembering prior results.
authordrh <drh@noemail.net>
Mon, 31 Mar 2008 23:48:03 +0000 (23:48 +0000)
committerdrh <drh@noemail.net>
Mon, 31 Mar 2008 23:48:03 +0000 (23:48 +0000)
This is similar to CSE, but only applies to columns. (CVS 4943)

FossilOrigin-Name: c29ee0fed23dcdbd9dde6b1e42b603100ea2389c

manifest
manifest.uuid
src/delete.c
src/expr.c
src/insert.c
src/select.c
src/sqliteInt.h
src/update.c
src/where.c

index 34311a79cb1c9f912e47f5b0c8effe8902c966be..bdee46c43e86d4031f7025d67ffff779aa48d9d0 100644 (file)
--- 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
index 1be492977142fab2ea97547f1c3e940e84c0dcb2..5ca840bf5354d1fc0d5a5a2d24caab0ba0bbfefc 100644 (file)
@@ -1 +1 @@
-2126db39854c751aea6c95c67894ed9b9dfc0763
\ No newline at end of file
+c29ee0fed23dcdbd9dde6b1e42b603100ea2389c
\ No newline at end of file
index e91ec74a5247d86fd52dc62ae8c0c5c1475c952a..92b9ed56e97f0e4af8a4fd65c8cd6f715f19abe9 100644 (file)
@@ -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;
index 2fe48a5ff079363c5eabe70da86b9de5d4efb95d..095c74aca89de073ea471167c6f9662b0b50d1a5 100644 (file)
@@ -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 <ctype.h>
@@ -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; i<pParse->nColCache; 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; i<pParse->nColCache; 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; i<pParse->nColCache; 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; i<pParse->nColCache; 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, &regFree2);
         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, &regFree1);
@@ -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; i<pParse->nColCache; 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; i<pParse->nTempReg; i++){
+    r = pParse->aTempReg[i];
+    if( usedAsColumnCache(pParse, r, r) ) continue;
+  }
+  if( i>=pParse->nTempReg ){
+    return ++pParse->nMem;
+  }
+  while( i<pParse->nTempReg-1 ){
+    pParse->aTempReg[i] = pParse->aTempReg[i+1];
+  }
+  pParse->nTempReg--;
+  return r;
 }
 void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
   if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
@@ -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{
index f7950d057854e4df298c0754eac3a7db70e5fd31..e075400bb0ac1322b5ffdba5f9c5b66e2fbaea84 100644 (file)
@@ -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);
index 11a8cf9c39e7180393e1653008dd043e2275e300..df3c3a7e864a7f2f5e067bab0f477e976e2793e5 100644 (file)
@@ -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; i<sAggInfo.nColumn; i++){
           struct AggInfo_col *pCol = &sAggInfo.aCol[i];
           if( pCol->iSorterColumn>=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; j<pGroupBy->nExpr; 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"));
index 308ed3e692f5d0113d612400670cd32672156ce4..40b6bfedf319247802ef0e2d32659b9e59d699ac 100644 (file)
@@ -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);
index 6f479a55dba34d5fe301b6d89a454f996d312695..daacd02c931a4ea1fd6581845cfe3781c08a5152 100644 (file)
@@ -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;
index d0643f7e0ec59e42659e75675a3f40aed576dd92..9a375b93a7b2fa0454a05c30d27b5a7742f3f5e8 100644 (file)
@@ -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; j<wc.nTerm; j++, pTerm++){
         if( pTerm->flags & (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);