1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

Add VdbeCoverage() and VdbeCoverageIf() macros for improved VDBE coverage

testing.

FossilOrigin-Name: b92d31a97d5fe4606d9ae1393c7f3e052f46bf5a
This commit is contained in:
drh
2014-02-18 03:07:12 +00:00
parent 552fd45441
commit 7d1761059b
6 changed files with 124 additions and 146 deletions

View File

@@ -1,5 +1,5 @@
C Improvements\sto\s"NOT\sIN\s(SELECT\s...)"\sprocessing.\s\sOnly\stest\sfor\sNULL\svalues\non\sthe\sRHS\son\sthe\sfirst\siteration,\sthen\sremember\sthe\sresult.\s\sThere\shas\sbeen\nlogic\sto\sdo\sthis\sfor\syear,\sbut\sit\sdidn't\swork\sright\sand\sended\sup\srepeating\nthe\sNULL\stest\son\severy\siteration.\s\sThis\sinefficiency\swas\sfound\susing\sthe\nVDBE\scoverage\stesting\stools.
D 2014-02-18T01:07:38.047
C Add\sVdbeCoverage()\sand\sVdbeCoverageIf()\smacros\sfor\simproved\sVDBE\scoverage\ntesting.
D 2014-02-18T03:07:12.342
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -172,7 +172,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c a00bf893bd39868c51020eba1fc5182eb36bfeb7
F src/expr.c e908787e4728beefdf742db90666248f89b1da01
F src/expr.c 014b8087a15c4c314bdd798cb1cb0b32693f8b40
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 3cd6ce998404fb1b7203d886d6fdff71cf3c8846
F src/func.c f4499b39d66b71825514334ce67b32ff14bd19f5
@@ -216,12 +216,12 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c ca8b99d894164435f5c55cb304c1b8121705c51e
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 618b53bd4553bd7a9ef95069396f12a8f28489e7
F src/select.c 28bff39f9bc5ec618b0719fe3f7b4be9f88b6f02
F src/shell.c 3dd86bf73ccd079f0e32ef5069600586085e8239
F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 004bd50575a05eefba7228c2d0fee432a53200de
F src/sqliteInt.h 22111056d7d5c404fef783b13088ef87d98074d0
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -290,7 +290,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
F src/where.c 7825dce3f92d7c7de9329505deefe176cbd5ba43
F src/where.c d622974f30d3347c7b71bfe49ce1f1e9b6570980
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -1151,7 +1151,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P a72687699ba2af2e7383be7371d4121750c7e34f
R babb7ab4a8213aedecd107bc9c2410b3
P 915f6f1c7aab54583729e60bdc1565f25ecc6f74
R d0043e1267f21a1ea521214d42169c3d
U drh
Z 3cb428699d451ff8a4012effde517352
Z f5a439caf79133298419241dae122f4e

View File

@@ -1 +1 @@
915f6f1c7aab54583729e60bdc1565f25ecc6f74
b92d31a97d5fe4606d9ae1393c7f3e052f46bf5a

View File

@@ -1369,24 +1369,6 @@ int sqlite3ExprCanBeNull(const Expr *p){
}
}
/*
** Generate an OP_IsNull instruction that tests register iReg and jumps
** to location iDest if the value in iReg is NULL. The value in iReg
** was computed by pExpr. If we can look at pExpr at compile-time and
** determine that it can never generate a NULL, then the OP_IsNull operation
** can be omitted.
*/
void sqlite3ExprCodeIsNullJump(
Vdbe *v, /* The VDBE under construction */
const Expr *pExpr, /* Only generate OP_IsNull if this expr can be NULL */
int iReg, /* Test the value in this register for NULL */
int iDest /* Jump here if the value is null */
){
if( sqlite3ExprCanBeNull(pExpr) ){
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iDest); VdbeCoverage(v);
}
}
/*
** Return TRUE if the given expression is a constant which would be
** unchanged by OP_Affinity with the affinity given in the second
@@ -1486,9 +1468,7 @@ static int isCandidateForInOpt(Select *p){
*/
int sqlite3CodeOnce(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
int addr = sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
VdbeCoverage(v);
return addr;
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
}
/*
@@ -1596,9 +1576,8 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
*/
assert(v);
if( iCol<0 ){
int iAddr;
iAddr = sqlite3CodeOnce(pParse);
int iAddr = sqlite3CodeOnce(pParse);
VdbeCoverage(v);
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
eType = IN_INDEX_ROWID;
@@ -1623,7 +1602,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
&& (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None))
){
int iAddr = sqlite3CodeOnce(pParse);
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
@@ -1723,7 +1702,7 @@ int sqlite3CodeSubselect(
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
testAddr = sqlite3CodeOnce(pParse);
testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
}
#ifndef SQLITE_OMIT_EXPLAIN
@@ -2548,22 +2527,16 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
case TK_GE:
case TK_NE:
case TK_EQ: {
assert( TK_LT==OP_Lt );
assert( TK_LE==OP_Le );
assert( TK_GT==OP_Gt );
assert( TK_GE==OP_Ge );
assert( TK_EQ==OP_Eq );
assert( TK_NE==OP_Ne );
testcase( op==TK_LT );
testcase( op==TK_LE );
testcase( op==TK_GT );
testcase( op==TK_GE );
testcase( op==TK_EQ );
testcase( op==TK_NE );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, inReg, SQLITE_STOREP2); VdbeCoverage(v);
r1, r2, inReg, SQLITE_STOREP2);
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -2577,7 +2550,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
op = (op==TK_IS) ? TK_EQ : TK_NE;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
VdbeCoverage(v);
VdbeCoverageIf(v, op==TK_EQ);
VdbeCoverageIf(v, op==TK_NE);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -2594,28 +2568,17 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
case TK_LSHIFT:
case TK_RSHIFT:
case TK_CONCAT: {
assert( TK_AND==OP_And );
assert( TK_OR==OP_Or );
assert( TK_PLUS==OP_Add );
assert( TK_MINUS==OP_Subtract );
assert( TK_REM==OP_Remainder );
assert( TK_BITAND==OP_BitAnd );
assert( TK_BITOR==OP_BitOr );
assert( TK_SLASH==OP_Divide );
assert( TK_LSHIFT==OP_ShiftLeft );
assert( TK_RSHIFT==OP_ShiftRight );
assert( TK_CONCAT==OP_Concat );
testcase( op==TK_AND );
testcase( op==TK_OR );
testcase( op==TK_PLUS );
testcase( op==TK_MINUS );
testcase( op==TK_REM );
testcase( op==TK_BITAND );
testcase( op==TK_BITOR );
testcase( op==TK_SLASH );
testcase( op==TK_LSHIFT );
testcase( op==TK_RSHIFT );
testcase( op==TK_CONCAT );
assert( TK_AND==OP_And ); testcase( op==TK_AND );
assert( TK_OR==OP_Or ); testcase( op==TK_OR );
assert( TK_PLUS==OP_Add ); testcase( op==TK_PLUS );
assert( TK_MINUS==OP_Subtract ); testcase( op==TK_MINUS );
assert( TK_REM==OP_Remainder ); testcase( op==TK_REM );
assert( TK_BITAND==OP_BitAnd ); testcase( op==TK_BITAND );
assert( TK_BITOR==OP_BitOr ); testcase( op==TK_BITOR );
assert( TK_SLASH==OP_Divide ); testcase( op==TK_SLASH );
assert( TK_LSHIFT==OP_ShiftLeft ); testcase( op==TK_LSHIFT );
assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT );
assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
sqlite3VdbeAddOp3(v, op, r2, r1, target);
@@ -2647,10 +2610,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
case TK_BITNOT:
case TK_NOT: {
assert( TK_BITNOT==OP_BitNot );
assert( TK_NOT==OP_Not );
testcase( op==TK_BITNOT );
testcase( op==TK_NOT );
assert( TK_BITNOT==OP_BitNot ); testcase( op==TK_BITNOT );
assert( TK_NOT==OP_Not ); testcase( op==TK_NOT );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
testcase( regFree1==0 );
inReg = target;
@@ -2660,14 +2621,14 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
case TK_ISNULL:
case TK_NOTNULL: {
int addr;
assert( TK_ISNULL==OP_IsNull );
assert( TK_NOTNULL==OP_NotNull );
testcase( op==TK_ISNULL );
testcase( op==TK_NOTNULL );
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
testcase( regFree1==0 );
addr = sqlite3VdbeAddOp1(v, op, r1); VdbeCoverage(v);
addr = sqlite3VdbeAddOp1(v, op, r1);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
sqlite3VdbeJumpHere(v, addr);
break;
@@ -2857,8 +2818,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
r3 = sqlite3GetTempReg(pParse);
r4 = sqlite3GetTempReg(pParse);
codeCompare(pParse, pLeft, pRight, OP_Ge,
r1, r2, r3, SQLITE_STOREP2);
VdbeCoverage(v);
r1, r2, r3, SQLITE_STOREP2); VdbeCoverage(v);
pLItem++;
pRight = pLItem->pExpr;
sqlite3ReleaseTempReg(pParse, regFree2);
@@ -3605,23 +3565,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_GE:
case TK_NE:
case TK_EQ: {
assert( TK_LT==OP_Lt );
assert( TK_LE==OP_Le );
assert( TK_GT==OP_Gt );
assert( TK_GE==OP_Ge );
assert( TK_EQ==OP_Eq );
assert( TK_NE==OP_Ne );
testcase( op==TK_LT );
testcase( op==TK_LE );
testcase( op==TK_GT );
testcase( op==TK_GE );
testcase( op==TK_EQ );
testcase( op==TK_NE );
testcase( jumpIfNull==0 );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, jumpIfNull); VdbeCoverage(v);
r1, r2, dest, jumpIfNull);
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -3634,19 +3588,21 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
op = (op==TK_IS) ? TK_EQ : TK_NE;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, SQLITE_NULLEQ); VdbeCoverage(v);
r1, r2, dest, SQLITE_NULLEQ);
VdbeCoverageIf(v, op==TK_EQ);
VdbeCoverageIf(v, op==TK_NE);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
assert( TK_ISNULL==OP_IsNull );
assert( TK_NOTNULL==OP_NotNull );
testcase( op==TK_ISNULL );
testcase( op==TK_NOTNULL );
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
sqlite3VdbeAddOp2(v, op, r1, dest); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break;
}
@@ -3765,17 +3721,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_GE:
case TK_NE:
case TK_EQ: {
testcase( op==TK_LT );
testcase( op==TK_LE );
testcase( op==TK_GT );
testcase( op==TK_GE );
testcase( op==TK_EQ );
testcase( op==TK_NE );
testcase( jumpIfNull==0 );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, jumpIfNull); VdbeCoverage(v);
r1, r2, dest, jumpIfNull);
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -3788,17 +3744,19 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, SQLITE_NULLEQ); VdbeCoverage(v);
r1, r2, dest, SQLITE_NULLEQ);
VdbeCoverageIf(v, op==TK_EQ);
VdbeCoverageIf(v, op==TK_NE);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
testcase( op==TK_ISNULL );
testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
sqlite3VdbeAddOp2(v, op, r1, dest); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break;
}

View File

@@ -4595,7 +4595,7 @@ int sqlite3Select(
/* If the subquery is not correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery
** once. */
onceAddr = sqlite3CodeOnce(pParse);
onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
}else{
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));

View File

@@ -3087,7 +3087,6 @@ int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*);
int sqlite3ExprIsInteger(Expr*, int*);
int sqlite3ExprCanBeNull(const Expr*);
void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
int sqlite3IsRowid(const char*);
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);

View File

@@ -1601,7 +1601,7 @@ static void constructAutomaticIndex(
** transient index on 2nd and subsequent iterations of the loop. */
v = pParse->pVdbe;
assert( v!=0 );
addrInit = sqlite3CodeOnce(pParse);
addrInit = sqlite3CodeOnce(pParse); VdbeCoverage(v);
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
@@ -2388,7 +2388,9 @@ static int codeEqualityTerm(
bRev = !bRev;
}
iTab = pX->iTable;
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev);
assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
pLoop->wsFlags |= WHERE_IN_ABLE;
if( pLevel->u.in.nIn==0 ){
@@ -2502,11 +2504,15 @@ static int codeAllEqualityTerms(
if( nSkip ){
int iIdxCur = pLevel->iIdxCur;
sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
VdbeComment((v, "begin skip-scan on %s", pIdx->zName));
j = sqlite3VdbeAddOp0(v, OP_Goto);
pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT),
iIdxCur, 0, regBase, nSkip); VdbeCoverage(v);
iIdxCur, 0, regBase, nSkip);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
sqlite3VdbeJumpHere(v, j);
for(j=0; j<nSkip; j++){
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j);
@@ -2539,7 +2545,10 @@ static int codeAllEqualityTerms(
testcase( pTerm->eOperator & WO_IN );
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
Expr *pRight = pTerm->pExpr->pRight;
sqlite3ExprCodeIsNullJump(v, pRight, regBase+j, pLevel->addrBrk);
if( sqlite3ExprCanBeNull(pRight) ){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
VdbeCoverage(v);
}
if( zAff ){
if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_NONE ){
zAff[j] = SQLITE_AFF_NONE;
@@ -2904,13 +2913,18 @@ static Bitmask codeOneLoopStart(
testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1);
VdbeComment((v, "pk")); VdbeCoverage(v);
VdbeComment((v, "pk"));
VdbeCoverageIf(v, pX->op==TK_GT);
VdbeCoverageIf(v, pX->op==TK_LE);
VdbeCoverageIf(v, pX->op==TK_LT);
VdbeCoverageIf(v, pX->op==TK_GE);
sqlite3ExprCacheAffinityChange(pParse, r1, 1);
sqlite3ReleaseTempReg(pParse, rTemp);
disableTerm(pLevel, pStart);
}else{
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
VdbeCoverage(v);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
}
if( pEnd ){
Expr *pX;
@@ -2938,7 +2952,10 @@ static Bitmask codeOneLoopStart(
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
VdbeCoverage(v);
VdbeCoverageIf(v, testOp==OP_Le);
VdbeCoverageIf(v, testOp==OP_Lt);
VdbeCoverageIf(v, testOp==OP_Ge);
VdbeCoverageIf(v, testOp==OP_Gt);
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
}
}else if( pLoop->wsFlags & WHERE_INDEXED ){
@@ -3080,8 +3097,11 @@ static Bitmask codeOneLoopStart(
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
sqlite3ExprCode(pParse, pRight, regBase+nEq);
if( (pRangeStart->wtFlags & TERM_VNULL)==0 ){
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
if( (pRangeStart->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
VdbeCoverage(v);
}
if( zStartAff ){
if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){
@@ -3105,20 +3125,14 @@ static Bitmask codeOneLoopStart(
codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 );
testcase( op==OP_Rewind );
testcase( op==OP_Last );
testcase( op==OP_SeekGT );
testcase( op==OP_SeekGE );
testcase( op==OP_SeekLE );
testcase( op==OP_SeekLT );
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
VdbeCoverage(v);
VdbeCoverageIf(v, op==OP_Rewind);
VdbeCoverageIf(v, op==OP_Last);
VdbeCoverageIf(v, op==OP_SeekGT);
VdbeCoverageIf(v, op==OP_SeekGE);
VdbeCoverageIf(v, op==OP_SeekLE);
VdbeCoverageIf(v, op==OP_SeekLT);
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
/* Load the value for the inequality constraint at the end of the
** range (if any).
@@ -3128,8 +3142,11 @@ static Bitmask codeOneLoopStart(
Expr *pRight = pRangeEnd->pExpr->pRight;
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
sqlite3ExprCode(pParse, pRight, regBase+nEq);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0 ){
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
VdbeCoverage(v);
}
if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_NONE
&& !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff)
@@ -3151,12 +3168,11 @@ static Bitmask codeOneLoopStart(
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
op = aEndOp[bRev*2 + endEq];
testcase( op==OP_IdxGT );
testcase( op==OP_IdxGE );
testcase( op==OP_IdxLT );
testcase( op==OP_IdxLE );
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
VdbeCoverage(v);
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
}
/* Seek the table cursor, if required */
@@ -3430,8 +3446,8 @@ static Bitmask codeOneLoopStart(
pLevel->op = aStep[bRev];
pLevel->p1 = iCur;
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}
}
@@ -5802,6 +5818,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
sqlite3VdbeChangeP5(v, pLevel->p5);
VdbeCoverage(v);
VdbeCoverageIf(v, pLevel->op==OP_Next);
VdbeCoverageIf(v, pLevel->op==OP_Prev);
VdbeCoverageIf(v, pLevel->op==OP_VNext);
}
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
struct InLoop *pIn;
@@ -5811,6 +5830,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
VdbeCoverage(v);
VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
}
sqlite3DbFree(db, pLevel->u.in.aInLoop);