aboutsummaryrefslogtreecommitdiff
path: root/src/expr.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2008-03-31 18:19:54 +0000
committerdrh <drh@noemail.net>2008-03-31 18:19:54 +0000
commit678ccce8b35a0abb69bbcd4b7ceccf9d5400f395 (patch)
tree13c9ee37f8a3d766d74d69ec6cd8b801a8b46563 /src/expr.c
parenta686bfcfa54f7414c9c8311ef430905951f3e20e (diff)
downloadsqlite-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.c53
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, &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