Comment and variable-name cleanup in where.c. Add testcase() macros to

insure adequate test coverage of table-driven logic. (CVS 5032)

FossilOrigin-Name: adcef73b3925266a14a552cd9b06c14f22aaefc8
This commit is contained in:
drh 2008-04-19 14:40:43 +00:00
parent 1cceeb93ea
commit 981642f389
3 changed files with 66 additions and 32 deletions

View File

@ -1,5 +1,5 @@
C Fix\sa\stypo\sin\sthe\sdocumentation\son\ssqlite3_open_v2().\s(CVS\s5031)
D 2008-04-19T14:06:28
C Comment\sand\svariable-name\scleanup\sin\swhere.c.\s\sAdd\stestcase()\smacros\sto\ninsure\sadequate\stest\scoverage\sof\stable-driven\slogic.\s(CVS\s5032)
D 2008-04-19T14:40:44
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in 25b3282a4ac39388632c2fb0e044ff494d490952
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -183,7 +183,7 @@ F src/vdbeblob.c cc713c142c3d4952b380c98ee035f850830ddbdb
F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736
F src/vdbemem.c 237e61216381998ff71c6431e5e7bd03386f6225
F src/vtab.c f5e78bf73df3b0c1b53861109c1b2e0800b108cc
F src/where.c 011f866cf0f05c832eea5a30e079eb108253ac64
F src/where.c 85719d58e0f680b5d8239dc6af82b159775d7376
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/all.test d56a3ca8acdf761204aff0a2e7aa5eb8e11b31e6
@ -631,7 +631,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P df02175ec0f28d57942b8275b540ff855dfbeb09
R 6299f6a06e93546f99df6a47ebb09453
P f7b62daa9fe71dc713bde107507fc7bcb812d62b
R 6e41e3d0b22d62b812d3d07204f15026
U drh
Z 385bf8bab63aafd1f261478c271df70c
Z 179f0ff656646746a01845fdd389ea41

View File

@ -1 +1 @@
f7b62daa9fe71dc713bde107507fc7bcb812d62b
adcef73b3925266a14a552cd9b06c14f22aaefc8

View File

@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.301 2008/04/18 10:25:24 danielk1977 Exp $
** $Id: where.c,v 1.302 2008/04/19 14:40:44 drh Exp $
*/
#include "sqliteInt.h"
@ -1272,8 +1272,10 @@ static double bestVirtualIndex(
** to this virtual table */
for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->eOperator==WO_IN ) continue;
if( pTerm->eOperator==WO_ISNULL ) continue;
if( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
testcase( pTerm->eOperator==WO_IN );
testcase( pTerm->eOperator==WO_ISNULL );
if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
nTerm++;
}
@ -1320,8 +1322,10 @@ static double bestVirtualIndex(
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->eOperator==WO_IN ) continue;
if( pTerm->eOperator==WO_ISNULL ) continue;
if( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
testcase( pTerm->eOperator==WO_IN );
testcase( pTerm->eOperator==WO_ISNULL );
if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
pIdxCons[j].iColumn = pTerm->leftColumn;
pIdxCons[j].iTermOffset = i;
pIdxCons[j].op = pTerm->eOperator;
@ -1867,6 +1871,8 @@ static int codeAllEqualityTerms(
if( r1!=regBase+j ){
sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
}
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_IN );
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk);
}
@ -2456,7 +2462,7 @@ WhereInfo *sqlite3WhereBegin(
}else if( pLevel->flags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){
/* Case 3: A scan using an index.
**
** The WHERE clause may contain one or more equality
** The WHERE clause may contain zero or more equality
** terms ("==" or "IN" operators) that refer to the N
** left-most columns of the index. It may also contain
** inequality constraints (>, <, >= or <=) on the indexed
@ -2472,10 +2478,15 @@ WhereInfo *sqlite3WhereBegin(
** x=5 AND y>5 AND y<10
** x=5 AND y=5 AND z<=10
**
** This cannot be optimized:
** The z<10 term of the following cannot be used, only
** the x=5 term:
**
** x=5 AND z<10
**
** N may be zero if there are inequality constraints.
** If there are no inequality constraints, then N is at
** least one.
**
** This case is also used when there are no WHERE clause
** constraints but an index is selected anyway, in order
** to force the output order to conform to an ORDER BY.
@ -2505,7 +2516,7 @@ WhereInfo *sqlite3WhereBegin(
int endEq; /* True if range end uses ==, >= or <= */
int start_constraints; /* Start of range is constrained */
int k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */
char *ptr;
int nConstraint; /* Number of constraint terms */
int op;
/* Generate code to evaluate all constraint terms using == or IN
@ -2545,16 +2556,20 @@ WhereInfo *sqlite3WhereBegin(
** a forward order scan on a descending index, interchange the
** start and end terms (pRangeStart and pRangeEnd).
*/
if( bRev==((pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)?1:0) ){
if( bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
}
startEq = ((!pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE))?1:0);
endEq = ((!pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE))?1:0);
start_constraints = ((pRangeStart || nEq>0)?1:0);
testcase( pRangeStart && pRangeStart->eOperator & WO_LE );
testcase( pRangeStart && pRangeStart->eOperator & WO_GE );
testcase( pRangeEnd && pRangeEnd->eOperator & WO_LE );
testcase( pRangeEnd && pRangeEnd->eOperator & WO_GE );
startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE);
endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE);
start_constraints = pRangeStart || nEq>0;
/* Seek the index cursor to the start of the range. */
ptr = (char *)(sqlite3_intptr_t)nEq;
nConstraint = nEq;
if( pRangeStart ){
int dcc = pParse->disableColCache;
if( pRangeEnd ){
@ -2563,42 +2578,55 @@ WhereInfo *sqlite3WhereBegin(
sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
pParse->disableColCache = dcc;
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
ptr++;
nConstraint++;
}else if( isMinQuery ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
ptr++;
nConstraint++;
startEq = 0;
start_constraints = 1;
}
codeApplyAffinity(pParse, regBase, (int)ptr, pIdx);
codeApplyAffinity(pParse, regBase, nConstraint, pIdx);
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase, ptr, P4_INT32);
assert( op!=0 );
testcase( op==OP_Rewind );
testcase( op==OP_Last );
testcase( op==OP_MoveGt );
testcase( op==OP_MoveGe );
testcase( op==OP_MoveLe );
testcase( op==OP_MoveLt );
sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase,
(char*)nConstraint, P4_INT32);
/* Load the value for the inequality constraint at the end of the
** range (if any).
*/
ptr = (char *)(sqlite3_intptr_t)nEq;
nConstraint = nEq;
if( pRangeEnd ){
sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
ptr++;
nConstraint++;
}
/* Top of the loop body */
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
op = aEndOp[((pRangeEnd || nEq)?1:0) * (1 + bRev)];
sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase, ptr, P4_INT32);
op = aEndOp[(pRangeEnd || nEq) * (1 + bRev)];
testcase( op==OP_Noop );
testcase( op==OP_IdxGE );
testcase( op==OP_IdxLT );
sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase,
(char*)nConstraint, P4_INT32);
sqlite3VdbeChangeP5(v, endEq!=bRev);
/* If there are inequality constraints (there may not be if the
** index is only being used to optimize ORDER BY), check that the
** value of the table column the inequality contrains is not NULL.
/* If there are inequality constraints, check that the value
** of the table column that the inequality contrains is not NULL.
** If it is, jump to the next iteration of the loop.
*/
r1 = sqlite3GetTempReg(pParse);
testcase( pLevel->flags & WHERE_BTM_LIMIT );
testcase( pLevel->flags & WHERE_TOP_LIMIT );
if( pLevel->flags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT) ){
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont);
@ -2619,7 +2647,7 @@ WhereInfo *sqlite3WhereBegin(
disableTerm(pLevel, pRangeStart);
disableTerm(pLevel, pRangeEnd);
}else{
/* Case 5: There is no usable index. We must do a complete
/* Case 4: There is no usable index. We must do a complete
** scan of the entire table.
*/
assert( omitTable==0 );
@ -2635,6 +2663,8 @@ WhereInfo *sqlite3WhereBegin(
*/
for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){
Expr *pE;
testcase( pTerm->flags & TERM_VIRTUAL );
testcase( pTerm->flags & TERM_CODED );
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & notReady)!=0 ) continue;
pE = pTerm->pExpr;
@ -2656,6 +2686,8 @@ WhereInfo *sqlite3WhereBegin(
sqlite3ExprClearColumnCache(pParse, pLevel->iTabCur);
sqlite3ExprClearColumnCache(pParse, pLevel->iIdxCur);
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
testcase( pTerm->flags & TERM_VIRTUAL );
testcase( pTerm->flags & TERM_CODED );
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & notReady)!=0 ) continue;
assert( pTerm->pExpr );
@ -2690,6 +2722,8 @@ WhereInfo *sqlite3WhereBegin(
}
sqlite3_query_plan[nQPlan++] = ' ';
}
testcase( pLevel->flags & WHERE_ROWID_EQ );
testcase( pLevel->flags & WHERE_ROWID_RANGE );
if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
memcpy(&sqlite3_query_plan[nQPlan], "* ", 2);
nQPlan += 2;