diff options
author | drh <drh@noemail.net> | 2008-03-31 18:19:54 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2008-03-31 18:19:54 +0000 |
commit | 678ccce8b35a0abb69bbcd4b7ceccf9d5400f395 (patch) | |
tree | 13c9ee37f8a3d766d74d69ec6cd8b801a8b46563 /src/expr.c | |
parent | a686bfcfa54f7414c9c8311ef430905951f3e20e (diff) | |
download | sqlite-678ccce8b35a0abb69bbcd4b7ceccf9d5400f395.tar.gz sqlite-678ccce8b35a0abb69bbcd4b7ceccf9d5400f395.zip |
Factor constant subexpressions out of loops. (CVS 4942)
FossilOrigin-Name: 2126db39854c751aea6c95c67894ed9b9dfc0763
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/src/expr.c b/src/expr.c index d35b3cd8e..2fe48a5ff 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.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, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2); 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, ®Free2); - 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, ®Free1); 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 |