]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Factor constant subexpressions out of loops. (CVS 4942)
authordrh <drh@noemail.net>
Mon, 31 Mar 2008 18:19:54 +0000 (18:19 +0000)
committerdrh <drh@noemail.net>
Mon, 31 Mar 2008 18:19:54 +0000 (18:19 +0000)
FossilOrigin-Name: 2126db39854c751aea6c95c67894ed9b9dfc0763

manifest
manifest.uuid
src/expr.c
src/sqliteInt.h
src/vdbe.c
src/where.c

index b12265afe77c275fd95fdeb687d9bb23a1e2290f..34311a79cb1c9f912e47f5b0c8effe8902c966be 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C In\ssetQuotedToken(),\sonly\smake\sa\smalloced\scopy\sif\sthe\sargument\scontains\sone\sor\smore\s"\scharacters.\s(CVS\s4941)
-D 2008-03-31T17:41:18
+C Factor\sconstant\ssubexpressions\sout\sof\sloops.\s(CVS\s4942)
+D 2008-03-31T18:19:54
 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
 F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -95,7 +95,7 @@ F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
 F src/date.c e41ce4513fb0e359dc678d6bddb4ace135fe365d
 F src/delete.c 3dc7d7cc46c8675219a7776b7c67b626bba530df
 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
-F src/expr.c 7e56d2a24af8137f4bebbfa1d7dd1dcf70107c88
+F src/expr.c d005510999ccc68301167fd3fcff21f133389379
 F src/fault.c 83057e86815d473e526f7df0b0108dfdd022ff23
 F src/func.c c9e8c7ff4c45027edee89bde7adbf86a3a3b2afe
 F src/hash.c 53655c312280211444bfe23af6490a460aec2980
@@ -140,7 +140,7 @@ 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 db668a07004d53a47c5d570963842489c6c4c3f3
+F src/sqliteInt.h 4d25edd2adb5f4be4c2b44c25533e0bbe69eb6e0
 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
 F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a
 F src/tclsqlite.c 1367762764772a233643524c3585b4711a9adcda
@@ -174,7 +174,7 @@ F src/update.c 2aefd3c9277792e9fa2414dfe14202119fa49fe7
 F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b
 F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2
 F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30
-F src/vdbe.c 09dd6f4c5e69f17f7633d22e3f45edbafe83eeaf
+F src/vdbe.c 07f500db3880a8555f7d76ef5f3cc405725ae9b8
 F src/vdbe.h f72201a0657d5f3d6cc008d1f8d9cc65768518c9
 F src/vdbeInt.h 0b96efdeecb0803e504bf1c16b198f87c91d6019
 F src/vdbeapi.c ab6e99f8a6b7fcb82c2c698da7a36762a7593f0a
@@ -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 dc146152cd0eb3b3568e92e7fed55cd008ebb9b5
+F src/where.c 902ddf1e7a737d19324d02de755fc816cc9cdba7
 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 618df68b8b78d376d30cea79a273fd39140f5033
-R 90b5f03ff5ebb83c1c1b0247d291a8ab
-U danielk1977
-Z 3148119d5b8a2206c0e723ccd87c91b1
+P b266924b8975b69bdb9ab45cf462e41436f89cc2
+R 2c294fffeaf40038acaaca80e4e177dd
+U drh
+Z 39a34de4a0aac903f6ed893e46452e8f
index 38a93cdbda9a2da4c08e445e1f75ee2f0418cd73..1be492977142fab2ea97547f1c3e940e84c0dcb2 100644 (file)
@@ -1 +1 @@
-b266924b8975b69bdb9ab45cf462e41436f89cc2
\ No newline at end of file
+2126db39854c751aea6c95c67894ed9b9dfc0763
\ No newline at end of file
index d35b3cd8e1ed77dfea6788662982c080f84b4b84..2fe48a5ff079363c5eabe70da86b9de5d4efb95d 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.357 2008/03/25 09:47:35 danielk1977 Exp $
+** $Id: expr.c,v 1.358 2008/03/31 18:19:54 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -786,7 +786,8 @@ void sqlite3ExprListDelete(ExprList *pList){
 }
 
 /*
-** Walk an expression tree.  Call xFunc for each node visited.
+** Walk an expression tree.  Call xFunc for each node visited.  xFunc
+** is called on the node before xFunc is called on the nodes children.
 **
 ** The return value from xFunc determines whether the tree walk continues.
 ** 0 means continue walking the tree.  1 means do not walk children
@@ -1932,13 +1933,13 @@ void sqlite3ExprCodeGetColumn(
 ** must check the return code and move the results to the desired
 ** register.
 */
-static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
+int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
   Vdbe *v = pParse->pVdbe;  /* The VM under construction */
   int op;                   /* The opcode being coded */
   int inReg = target;       /* Results stored in register inReg */
   int regFree1 = 0;         /* If non-zero free this temporary register */
   int regFree2 = 0;         /* If non-zero free this temporary register */
-  int r1, r2, r3;           /* Various register numbers */
+  int r1, r2, r3, r4;       /* Various register numbers */
 
   assert( v!=0 || pParse->db->mallocFailed );
   assert( target>0 && target<=pParse->nMem );
@@ -2227,7 +2228,7 @@ static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
       j2  = sqlite3VdbeAddOp0(v, OP_Goto);
       sqlite3VdbeJumpHere(v, j1);
       if( eType==IN_INDEX_ROWID ){
-        j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, 0, 1);
+        j3 = sqlite3VdbeAddOp1(v, OP_MustBeInt, r1);
         j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r1);
         j5 = sqlite3VdbeAddOp0(v, OP_Goto);
         sqlite3VdbeJumpHere(v, j3);
@@ -2262,15 +2263,17 @@ static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
       r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
       r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
       r3 = sqlite3GetTempReg(pParse);
+      r4 = sqlite3GetTempReg(pParse);
       codeCompare(pParse, pLeft, pRight, OP_Ge,
                   r1, r2, r3, SQLITE_STOREP2);
       pLItem++;
       pRight = pLItem->pExpr;
       sqlite3ReleaseTempReg(pParse, regFree2);
       r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
-      codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r2, SQLITE_STOREP2);
-      sqlite3VdbeAddOp3(v, OP_And, r3, r2, target);
+      codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2);
+      sqlite3VdbeAddOp3(v, OP_And, r3, r4, target);
       sqlite3ReleaseTempReg(pParse, r3);
+      sqlite3ReleaseTempReg(pParse, r4);
       break;
     }
     case TK_UPLUS: {
@@ -2322,6 +2325,7 @@ static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
         cacheX = *pX;
         cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, &regFree1);
         cacheX.op = TK_REGISTER;
+        cacheX.iColumn = 0;
         opCompare.op = TK_EQ;
         opCompare.pLeft = &cacheX;
         pTest = &opCompare;
@@ -2381,7 +2385,7 @@ static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
 ** are stored.
 **
 ** If the register is a temporary register that can be deallocated,
-** then write its number into *pReg.  If the result register is no
+** then write its number into *pReg.  If the result register is not
 ** a temporary, then set *pReg to zero.
 */
 int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
@@ -2435,11 +2439,44 @@ int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
     iMem = ++pParse->nMem;
     sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem);
     pExpr->iTable = iMem;
+    pExpr->iColumn = pExpr->op;
     pExpr->op = TK_REGISTER;
   }
   return inReg;
 }
 
+/*
+** If pExpr is a constant expression, then evaluate the expression
+** into a register and convert the expression into a TK_REGISTER
+** expression.
+*/
+static int evalConstExpr(void *pArg, Expr *pExpr){
+  Parse *pParse = (Parse*)pArg;
+  if( pExpr->op==TK_REGISTER ){
+    return 1;
+  }
+  if( sqlite3ExprIsConstantNotJoin(pExpr) ){
+    int r1 = ++pParse->nMem;
+    int r2;
+    r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
+    if( r1!=r2 ) pParse->nMem--;
+    pExpr->iColumn = pExpr->op;
+    pExpr->op = TK_REGISTER;
+    pExpr->iTable = r2;
+    return 1;
+  }
+  return 0;
+}
+
+/*
+** Preevaluate constant subexpressions within pExpr and store the
+** results in registers.  Modify pExpr so that the constant subexpresions
+** are TK_REGISTER opcodes that refer to the precomputed values.
+*/
+void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
+   walkExprTree(pExpr, evalConstExpr, pParse);
+}
+
 
 /*
 ** Generate code that pushes the value of every element of the given
index 1b94f61a0602464c6e9e66ffa3995c93c6f7db0d..308ed3e692f5d0113d612400670cd32672156ce4 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.681 2008/03/26 12:46:24 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.682 2008/03/31 18:19:54 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1130,15 +1130,16 @@ struct Expr {
 /*
 ** The following are the meanings of bits in the Expr.flags field.
 */
-#define EP_FromJoin     0x01  /* Originated in ON or USING clause of a join */
-#define EP_Agg          0x02  /* Contains one or more aggregate functions */
-#define EP_Resolved     0x04  /* IDs have been resolved to COLUMNs */
-#define EP_Error        0x08  /* Expression contains one or more errors */
-#define EP_Distinct     0x10  /* Aggregate function with DISTINCT keyword */
-#define EP_VarSelect    0x20  /* pSelect is correlated, not constant */
-#define EP_Dequoted     0x40  /* True if the string has been dequoted */
-#define EP_InfixFunc    0x80  /* True for an infix function: LIKE, GLOB, etc */
-#define EP_ExpCollate  0x100  /* Collating sequence specified explicitly */
+#define EP_FromJoin   0x0001  /* Originated in ON or USING clause of a join */
+#define EP_Agg        0x0002  /* Contains one or more aggregate functions */
+#define EP_Resolved   0x0004  /* IDs have been resolved to COLUMNs */
+#define EP_Error      0x0008  /* Expression contains one or more errors */
+#define EP_Distinct   0x0010  /* Aggregate function with DISTINCT keyword */
+#define EP_VarSelect  0x0020  /* pSelect is correlated, not constant */
+#define EP_Dequoted   0x0040  /* True if the string has been dequoted */
+#define EP_InfixFunc  0x0080  /* True for an infix function: LIKE, GLOB, etc */
+#define EP_ExpCollate 0x0100  /* Collating sequence specified explicitly */
+#define EP_Constant   0x0200  /* A constant expression */
 
 /*
 ** These macros can be used to test, set, or clear bits in the 
@@ -1831,7 +1832,9 @@ void sqlite3WhereEnd(WhereInfo*);
 void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
 int sqlite3ExprCode(Parse*, Expr*, int);
 int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
+int sqlite3ExprCodeTarget(Parse*, Expr*, int);
 int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
+void sqlite3ExprCodeConstants(Parse*, Expr*);
 int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
 void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
 void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
index b27c635d56f0aaac41a22c258951f22c00427d5b..f969bbcd56dc177119368cf896604b7c070226b6 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.722 2008/03/28 19:16:34 danielk1977 Exp $
+** $Id: vdbe.c,v 1.723 2008/03/31 18:19:54 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -103,7 +103,7 @@ static void updateMaxBlobsize(Mem *p){
 ** Test a register to see if it exceeds the current maximum blob size.
 ** If it does, record the new maximum blob size.
 */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST)
 # define UPDATE_MAX_BLOBSIZE(P)  updateMaxBlobsize(P)
 #else
 # define UPDATE_MAX_BLOBSIZE(P)
index 1d8b50c87d2c39f339115a43b0e2cc08b458f220..d0643f7e0ec59e42659e75675a3f40aed576dd92 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.294 2008/03/28 19:16:57 danielk1977 Exp $
+** $Id: where.c,v 1.295 2008/03/31 18:19:54 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -535,7 +535,8 @@ static int isLikeOrGlob(
 #endif
   pList = pExpr->pList;
   pRight = pList->a[0].pExpr;
-  if( pRight->op!=TK_STRING ){
+  if( pRight->op!=TK_STRING
+   && (pRight->op!=TK_REGISTER || pRight->iColumn!=TK_STRING) ){
     return 0;
   }
   pLeft = pList->a[1].pExpr;
@@ -1752,19 +1753,23 @@ static void buildIndexProbe(
 ** result is left on the stack.  For constraints of the form X IN (...)
 ** this routine sets up a loop that will iterate over all values of X.
 */
-static void codeEqualityTerm(
+static int codeEqualityTerm(
   Parse *pParse,      /* The parsing context */
   WhereTerm *pTerm,   /* The term of the WHERE clause to be coded */
   WhereLevel *pLevel, /* When level of the FROM clause we are working on */
-  int iReg            /* Leave results in this register */
+  int iTarget         /* Attempt to leave results in this register */
 ){
   Expr *pX = pTerm->pExpr;
   Vdbe *v = pParse->pVdbe;
+  int iReg;                  /* Register holding results */
 
-  assert( iReg>0 && iReg<=pParse->nMem );
+  if( iTarget<=0 ){
+    iReg = iTarget = sqlite3GetTempReg(pParse);
+  }
   if( pX->op==TK_EQ ){
-    sqlite3ExprCode(pParse, pX->pRight, iReg);
+    iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
   }else if( pX->op==TK_ISNULL ){
+    iReg = iTarget;
     sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
 #ifndef SQLITE_OMIT_SUBQUERY
   }else{
@@ -1773,6 +1778,7 @@ static void codeEqualityTerm(
     struct InLoop *pIn;
 
     assert( pX->op==TK_IN );
+    iReg = iTarget;
     eType = sqlite3FindInIndex(pParse, pX, 1);
     iTab = pX->iTable;
     sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
@@ -1799,6 +1805,7 @@ static void codeEqualityTerm(
 #endif
   }
   disableTerm(pLevel, pTerm);
+  return iReg;
 }
 
 /*
@@ -1852,11 +1859,15 @@ static int codeAllEqualityTerms(
   */
   assert( pIdx->nColumn>=nEq );
   for(j=0; j<nEq; j++){
+    int r1;
     int k = pIdx->aiColumn[j];
     pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
     if( pTerm==0 ) break;
     assert( (pTerm->flags & TERM_CODED)==0 );
-    codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
+    r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
+    if( r1!=regBase+j ){
+      sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
+    }
     if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
       sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk);
     }
@@ -2022,6 +2033,7 @@ WhereInfo *sqlite3WhereBegin(
   */
   initMaskSet(&maskSet);
   whereClauseInit(&wc, pParse, &maskSet);
+  sqlite3ExprCodeConstants(pParse, pWhere);
   whereSplit(&wc, pWhere, TK_AND);
     
   /* Allocate and initialize the WhereInfo structure that will become the
@@ -2367,13 +2379,11 @@ WhereInfo *sqlite3WhereBegin(
       assert( pTerm->pExpr!=0 );
       assert( pTerm->leftCursor==iCur );
       assert( omitTable==0 );
-      r1 = sqlite3GetTempReg(pParse);
-      codeEqualityTerm(pParse, pTerm, pLevel, r1);
+      r1 = codeEqualityTerm(pParse, pTerm, pLevel, 0);
       nxt = pLevel->nxt;
-      sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, nxt, 1);
+      sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, nxt);
       sqlite3VdbeAddOp3(v, OP_NotExists, iCur, nxt, r1);
       VdbeComment((v, "pk"));
-      sqlite3ReleaseTempReg(pParse, r1);
       pLevel->op = OP_Noop;
     }else if( pLevel->flags & WHERE_ROWID_RANGE ){
       /* Case 2:  We have an inequality comparison against the ROWID field.