mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Omit the SQLITE_STOREP2 and SQLITE_KEEPNULL options from the comparison
opcodes, allowing them to run faster. This required refactoring the vector comparison logic, which in turn required changing OP_ElseNotEq into OP_ElseEq. FossilOrigin-Name: 380b46054b6a9b67e57357815e8e94057253fa3cce838ae76e5d5031c6bd26b2
This commit is contained in:
88
src/vdbe.c
88
src/vdbe.c
@@ -1915,8 +1915,7 @@ case OP_Cast: { /* in1 */
|
||||
** Synopsis: IF r[P3]==r[P1]
|
||||
**
|
||||
** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then
|
||||
** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, then
|
||||
** store the result of comparison in register P2.
|
||||
** jump to address P2.
|
||||
**
|
||||
** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
|
||||
** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
|
||||
@@ -1942,10 +1941,6 @@ case OP_Cast: { /* in1 */
|
||||
** If neither operand is NULL the result is the same as it would be if
|
||||
** the SQLITE_NULLEQ flag were omitted from P5.
|
||||
**
|
||||
** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
|
||||
** content of r[P2] is only changed if the new value is NULL or 0 (false).
|
||||
** In other words, a prior r[P2] value will not be overwritten by 1 (true).
|
||||
**
|
||||
** This opcode saves the result of comparison for use by the new
|
||||
** OP_Jump opcode.
|
||||
*/
|
||||
@@ -1955,17 +1950,12 @@ case OP_Cast: { /* in1 */
|
||||
** This works just like the Eq opcode except that the jump is taken if
|
||||
** the operands in registers P1 and P3 are not equal. See the Eq opcode for
|
||||
** additional information.
|
||||
**
|
||||
** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
|
||||
** content of r[P2] is only changed if the new value is NULL or 1 (true).
|
||||
** In other words, a prior r[P2] value will not be overwritten by 0 (false).
|
||||
*/
|
||||
/* Opcode: Lt P1 P2 P3 P4 P5
|
||||
** Synopsis: IF r[P3]<r[P1]
|
||||
**
|
||||
** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then
|
||||
** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5 store
|
||||
** the result of comparison (0 or 1 or NULL) into register P2.
|
||||
** jump to address P2.
|
||||
**
|
||||
** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
|
||||
** reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL
|
||||
@@ -2051,16 +2041,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
|
||||
*/
|
||||
iCompare = 1; /* Operands are not equal */
|
||||
if( pOp->p5 & SQLITE_STOREP2 ){
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
MemSetTypeFlag(pOut, MEM_Null);
|
||||
REGISTER_TRACE(pOp->p2, pOut);
|
||||
}else{
|
||||
VdbeBranchTaken(2,3);
|
||||
if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
||||
goto jump_to_p2;
|
||||
}
|
||||
VdbeBranchTaken(2,3);
|
||||
if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2132,66 +2115,39 @@ compare_op:
|
||||
assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
|
||||
pIn1->flags = flags1;
|
||||
|
||||
if( pOp->p5 & SQLITE_STOREP2 ){
|
||||
pOut = &aMem[pOp->p2];
|
||||
if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
|
||||
/* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
|
||||
** and prevents OP_Ne from overwriting NULL with 0. This flag
|
||||
** is only used in contexts where either:
|
||||
** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
|
||||
** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
|
||||
** Therefore it is not necessary to check the content of r[P2] for
|
||||
** NULL. */
|
||||
assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq );
|
||||
assert( res2==0 || res2==1 );
|
||||
testcase( res2==0 && pOp->opcode==OP_Eq );
|
||||
testcase( res2==1 && pOp->opcode==OP_Eq );
|
||||
testcase( res2==0 && pOp->opcode==OP_Ne );
|
||||
testcase( res2==1 && pOp->opcode==OP_Ne );
|
||||
if( (pOp->opcode==OP_Eq)==res2 ) break;
|
||||
}
|
||||
memAboutToChange(p, pOut);
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
pOut->u.i = res2;
|
||||
REGISTER_TRACE(pOp->p2, pOut);
|
||||
}else{
|
||||
VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
||||
if( res2 ){
|
||||
goto jump_to_p2;
|
||||
}
|
||||
VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
||||
if( res2 ){
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ElseNotEq * P2 * * *
|
||||
/* Opcode: ElseEq * P2 * * *
|
||||
**
|
||||
** This opcode must follow an OP_Lt or OP_Gt comparison operator. There
|
||||
** can be zero or more OP_ReleaseReg opcodes intervening, but no other
|
||||
** opcodes are allowed to occur between this instruction and the previous
|
||||
** OP_Lt or OP_Gt. Furthermore, the prior OP_Lt or OP_Gt must have the
|
||||
** SQLITE_STOREP2 bit set in the P5 field.
|
||||
** OP_Lt or OP_Gt.
|
||||
**
|
||||
** If result of an OP_Eq comparison on the same two operands as the
|
||||
** prior OP_Lt or OP_Gt would have been NULL or false (0), then then
|
||||
** jump to P2. If the result of an OP_Eq comparison on the two previous
|
||||
** operands would have been true (1), then fall through.
|
||||
** prior OP_Lt or OP_Gt would have been true, then jump to P2.
|
||||
** If the result of an OP_Eq comparison on the two previous
|
||||
** operands would have been false or NULL, then fall through.
|
||||
*/
|
||||
case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
|
||||
case OP_ElseEq: { /* same as TK_ESCAPE, jump */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Verify the preconditions of this opcode - that it follows an OP_Lt or
|
||||
** OP_Gt with the SQLITE_STOREP2 flag set, with zero or more intervening
|
||||
** OP_ReleaseReg opcodes */
|
||||
** OP_Gt with zero or more intervening OP_ReleaseReg opcodes */
|
||||
int iAddr;
|
||||
for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){
|
||||
if( aOp[iAddr].opcode==OP_ReleaseReg ) continue;
|
||||
assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt );
|
||||
assert( aOp[iAddr].p5 & SQLITE_STOREP2 );
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
VdbeBranchTaken(iCompare!=0, 2);
|
||||
if( iCompare!=0 ) goto jump_to_p2;
|
||||
VdbeBranchTaken(iCompare==0, 2);
|
||||
if( iCompare==0 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2503,13 +2459,13 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
|
||||
}
|
||||
|
||||
/* Opcode: ZeroOrNull P1 P2 P3 * *
|
||||
** Synopsis: r[P2] = (P1,P3 NOT NULL) ? 0 : NULL;
|
||||
** Synopsis: r[P2] = 0 OR NULL
|
||||
**
|
||||
** If both registers P1 and P3 are NOT NULL, then store a zero in
|
||||
** register P2. If either register P1 or register P3 or both contain
|
||||
** a NULL then store a NULL in register P2.
|
||||
** If all both registers P1 and P3 are NOT NULL, then store a zero in
|
||||
** register P2. If either registers P1 or P3 are NULL then put
|
||||
** a NULL in register P2.
|
||||
*/
|
||||
case OP_ZeroOrNull: { /* in1, out2, in3 */
|
||||
case OP_ZeroOrNull: { /* in1, in2, out2, in3 */
|
||||
if( (aMem[pOp->p1].flags & MEM_Null)!=0
|
||||
|| (aMem[pOp->p3].flags & MEM_Null)!=0
|
||||
){
|
||||
|
Reference in New Issue
Block a user