mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-12 13:01:09 +03:00
When processing a BETWEEN or CASE expression, avoid transforming a node of the original expression into a TK_REGISTER node. Instead, take a copy and use it instead. Fix for [1be72aab9].
FossilOrigin-Name: 7ef7b23cbb1b9ace9f853238d9133320c153e6c3417e6823ab6394ee1fe56358
This commit is contained in:
75
src/expr.c
75
src/expr.c
@@ -1086,16 +1086,6 @@ static int exprStructSize(Expr *p){
|
||||
return EXPR_FULLSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy the complete content of an Expr node, taking care not to read
|
||||
** past the end of the structure for a reduced-size version of the source
|
||||
** Expr.
|
||||
*/
|
||||
static void exprNodeCopy(Expr *pDest, Expr *pSrc){
|
||||
memset(pDest, 0, sizeof(Expr));
|
||||
memcpy(pDest, pSrc, exprStructSize(pSrc));
|
||||
}
|
||||
|
||||
/*
|
||||
** The dupedExpr*Size() routines each return the number of bytes required
|
||||
** to store a copy of an expression or expression tree. They differ in
|
||||
@@ -4048,6 +4038,8 @@ expr_code_doover:
|
||||
Expr opCompare; /* The X==Ei expression */
|
||||
Expr *pX; /* The X expression */
|
||||
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
||||
Expr *pDel = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
||||
assert(pExpr->x.pList->nExpr > 0);
|
||||
@@ -4056,13 +4048,17 @@ expr_code_doover:
|
||||
nExpr = pEList->nExpr;
|
||||
endLabel = sqlite3VdbeMakeLabel(pParse);
|
||||
if( (pX = pExpr->pLeft)!=0 ){
|
||||
exprNodeCopy(&tempX, pX);
|
||||
pDel = sqlite3ExprDup(db, pX, 0);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
break;
|
||||
}
|
||||
testcase( pX->op==TK_COLUMN );
|
||||
exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1));
|
||||
exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1));
|
||||
testcase( regFree1==0 );
|
||||
memset(&opCompare, 0, sizeof(opCompare));
|
||||
opCompare.op = TK_EQ;
|
||||
opCompare.pLeft = &tempX;
|
||||
opCompare.pLeft = pDel;
|
||||
pTest = &opCompare;
|
||||
/* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
|
||||
** The value in regFree1 might get SCopy-ed into the file result.
|
||||
@@ -4090,6 +4086,7 @@ expr_code_doover:
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
}
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
sqlite3VdbeResolveLabel(v, endLabel);
|
||||
break;
|
||||
}
|
||||
@@ -4371,40 +4368,44 @@ static void exprCodeBetween(
|
||||
void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
|
||||
int jumpIfNull /* Take the jump if the BETWEEN is NULL */
|
||||
){
|
||||
Expr exprAnd; /* The AND operator in x>=y AND x<=z */
|
||||
Expr exprAnd; /* The AND operator in x>=y AND x<=z */
|
||||
Expr compLeft; /* The x>=y term */
|
||||
Expr compRight; /* The x<=z term */
|
||||
Expr exprX; /* The x subexpression */
|
||||
int regFree1 = 0; /* Temporary use register */
|
||||
Expr *pDel = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
memset(&compLeft, 0, sizeof(Expr));
|
||||
memset(&compRight, 0, sizeof(Expr));
|
||||
memset(&exprAnd, 0, sizeof(Expr));
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
exprNodeCopy(&exprX, pExpr->pLeft);
|
||||
exprAnd.op = TK_AND;
|
||||
exprAnd.pLeft = &compLeft;
|
||||
exprAnd.pRight = &compRight;
|
||||
compLeft.op = TK_GE;
|
||||
compLeft.pLeft = &exprX;
|
||||
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compRight.op = TK_LE;
|
||||
compRight.pLeft = &exprX;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®Free1));
|
||||
if( xJump ){
|
||||
xJump(pParse, &exprAnd, dest, jumpIfNull);
|
||||
}else{
|
||||
/* Mark the expression is being from the ON or USING clause of a join
|
||||
** so that the sqlite3ExprCodeTarget() routine will not attempt to move
|
||||
** it into the Parse.pConstExpr list. We should use a new bit for this,
|
||||
** for clarity, but we are out of bits in the Expr.flags field so we
|
||||
** have to reuse the EP_FromJoin bit. Bummer. */
|
||||
exprX.flags |= EP_FromJoin;
|
||||
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
||||
pDel = sqlite3ExprDup(db, pExpr->pLeft, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
exprAnd.op = TK_AND;
|
||||
exprAnd.pLeft = &compLeft;
|
||||
exprAnd.pRight = &compRight;
|
||||
compLeft.op = TK_GE;
|
||||
compLeft.pLeft = pDel;
|
||||
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compRight.op = TK_LE;
|
||||
compRight.pLeft = pDel;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1));
|
||||
if( xJump ){
|
||||
xJump(pParse, &exprAnd, dest, jumpIfNull);
|
||||
}else{
|
||||
/* Mark the expression is being from the ON or USING clause of a join
|
||||
** so that the sqlite3ExprCodeTarget() routine will not attempt to move
|
||||
** it into the Parse.pConstExpr list. We should use a new bit for this,
|
||||
** for clarity, but we are out of bits in the Expr.flags field so we
|
||||
** have to reuse the EP_FromJoin bit. Bummer. */
|
||||
pDel->flags |= EP_FromJoin;
|
||||
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
|
||||
/* Ensure adequate test coverage */
|
||||
testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 );
|
||||
|
||||
Reference in New Issue
Block a user