diff options
author | drh <drh@noemail.net> | 2016-08-13 10:02:17 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2016-08-13 10:02:17 +0000 |
commit | 79752b6e63c03a18fd93817c6e9580d7445a7ce9 (patch) | |
tree | 5ec3cc0465d7b54cf8e75c55aeb044a46888dbba /src/expr.c | |
parent | 471b4b92bdb2a203d048f2c87fb53d8d83381c0b (diff) | |
download | sqlite-79752b6e63c03a18fd93817c6e9580d7445a7ce9.tar.gz sqlite-79752b6e63c03a18fd93817c6e9580d7445a7ce9.zip |
Attempt to simplify the logic and generated code for vector comparisons.
Basic comparison operators are working, but there are many indexing test
failures still to be worked through.
FossilOrigin-Name: dfc028cfbe7657d20727a2670ecadb1575eb8cbb
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 109 |
1 files changed, 56 insertions, 53 deletions
diff --git a/src/expr.c b/src/expr.c index 3faeae79d..54bf0dfab 100644 --- a/src/expr.c +++ b/src/expr.c @@ -409,37 +409,52 @@ static int exprVectorRegister( /* ** Expression pExpr is a comparison between two vector values. Compute -** the result of the comparison and write it to register dest. +** the result of the comparison (1, 0, or NULL) and write that +** result into register dest. +** +** The caller must satisfy the following preconditions: +** +** if pExpr->op==TK_IS: op==TK_EQ and p5==SQLITE_NULLEQ +** if pExpr->op==TK_ISNOT: op==TK_NE and p5==SQLITE_NULLEQ +** otherwise: op==pExpr->op and p5==0 */ -static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){ +static void codeVectorCompare( + Parse *pParse, /* Code generator context */ + Expr *pExpr, /* The comparison operation */ + int dest, /* Write results into this register */ + u8 op, /* Comparison operator */ + u8 p5 /* SQLITE_NULLEQ or zero */ +){ Vdbe *v = pParse->pVdbe; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int nRight = sqlite3ExprVectorSize(pRight); - int addr = sqlite3VdbeMakeLabel(v); /* Check that both sides of the comparison are vectors, and that ** both are the same length. */ if( nLeft!=nRight ){ sqlite3ErrorMsg(pParse, "invalid use of row value"); }else{ - int p5 = (pExpr->op==TK_IS || pExpr->op==TK_ISNOT) ? SQLITE_NULLEQ : 0; int i; int regLeft = 0; int regRight = 0; - int regTmp = 0; + u8 opx = op; + int addrDone = sqlite3VdbeMakeLabel(v); assert( pExpr->op==TK_EQ || pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT || pExpr->op==TK_LT || pExpr->op==TK_GT || pExpr->op==TK_LE || pExpr->op==TK_GE ); + assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ) + || (pExpr->op==TK_ISNOT && op==TK_NE) ); + assert( p5==0 || pExpr->op!=op ); + assert( p5==SQLITE_NULLEQ || pExpr->op==op ); - if( pExpr->op==TK_EQ || pExpr->op==TK_NE ){ - regTmp = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Integer, (pExpr->op==TK_EQ), dest); - } + p5 |= SQLITE_STOREP2; + if( opx==TK_LE ) opx = TK_LT; + if( opx==TK_GE ) opx = TK_GT; regLeft = exprCodeSubselect(pParse, pLeft); regRight = exprCodeSubselect(pParse, pRight); @@ -448,55 +463,43 @@ static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){ int regFree1 = 0, regFree2 = 0; Expr *pL, *pR; int r1, r2; - if( i ) sqlite3ExprCachePush(pParse); + if( i>0 ) sqlite3ExprCachePush(pParse); r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); - - switch( pExpr->op ){ - case TK_IS: - codeCompare( - pParse, pL, pR, OP_Eq, r1, r2, dest, SQLITE_STOREP2|SQLITE_NULLEQ - ); - sqlite3VdbeAddOp3(v, OP_IfNot, dest, addr, 1); - VdbeCoverage(v); - break; - - case TK_ISNOT: - codeCompare( - pParse, pL, pR, OP_Ne, r1, r2, dest, SQLITE_STOREP2|SQLITE_NULLEQ - ); - sqlite3VdbeAddOp3(v, OP_If, dest, addr, 1); - VdbeCoverage(v); - break; - - case TK_EQ: - case TK_NE: - codeCompare(pParse, pL, pR, OP_Cmp, r1, r2, regTmp,SQLITE_STOREP2|p5); - sqlite3VdbeAddOp4Int( - v, OP_CmpTest, regTmp, addr, dest, pExpr->op==TK_NE - ); - VdbeCoverage(v); - break; - - case TK_LT: - case TK_LE: - case TK_GT: - case TK_GE: - codeCompare(pParse, pL, pR, OP_Cmp, r1, r2, dest, SQLITE_STOREP2|p5); - sqlite3VdbeAddOp4Int(v, OP_CmpTest, dest, addr, 0, pExpr->op); - VdbeCoverage(v); - break; - } - + codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5); + testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); + testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); + testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); + testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); + testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); + testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); - if( i ) sqlite3ExprCachePop(pParse); + if( i>0 ) sqlite3ExprCachePop(pParse); + if( i==nLeft-1 ){ + break; + } + if( opx==TK_EQ ){ + sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v); + p5 |= SQLITE_KEEPNULL; + }else if( opx==TK_NE ){ + sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v); + p5 |= SQLITE_KEEPNULL; + }else if( opx==op ){ + assert( op==TK_LT || op==TK_GT ); + sqlite3VdbeAddOp3(v, OP_If, dest, addrDone, 1); + VdbeCoverageIf(v, op==TK_LT); + VdbeCoverageIf(v, op==TK_GT); + }else{ + assert( op==TK_LE || op==TK_GE ); + sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone); + VdbeCoverageIf(v, op==TK_LE); + VdbeCoverageIf(v, op==TK_GE); + if( i==nLeft-2 ) opx = op; + } } - - sqlite3ReleaseTempReg(pParse, regTmp); + sqlite3VdbeResolveLabel(v, addrDone); } - - sqlite3VdbeResolveLabel(v, addr); } #if SQLITE_MAX_EXPR_DEPTH>0 @@ -3251,7 +3254,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ case TK_EQ: { Expr *pLeft = pExpr->pLeft; if( sqlite3ExprIsVector(pLeft) ){ - codeVectorCompare(pParse, pExpr, target); + codeVectorCompare(pParse, pExpr, target, op, p5); }else{ r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); |