Add more testcase() macros. Fix a memory leak following OOM in the

virtual table analysis logic.

FossilOrigin-Name: b61402af690ac08b68974f3c807096b0cffd9bc0
This commit is contained in:
drh 2013-06-17 21:37:40 +00:00
parent 93ec45d560
commit 7963b0e853
3 changed files with 73 additions and 27 deletions

View File

@ -1,5 +1,5 @@
C Simplifications\sto\sthe\sNGQP.\s\sAdd\sthe\squeryplantest\smakefile\starget.\s\sAdd\ntestcase()\smacros\sin\sthe\sNGQP.
D 2013-06-17T18:20:48.993
C Add\smore\stestcase()\smacros.\s\sFix\sa\smemory\sleak\sfollowing\sOOM\sin\sthe\nvirtual\stable\sanalysis\slogic.
D 2013-06-17T21:37:40.990
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
F src/where.c 74627cb9415ad421004de574cfafe6ed0359554b
F src/where.c b911a484d36d5dca41448e493974368d8147a2e1
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P e8f124284ee0d0e373dc4431668630f1e17015c1
R 5f6127cf4cee34c1f05fd60f463f5e2a
P eaf1f1b405ec2c498092527fae00e5dbe9e176c1
R 7a1603a9005d87a42c0df561c944734f
U drh
Z 08d0c98ccbb424b49a424bc18bdd25d5
Z 30a954d83fb3f9269803abab8ea42340

View File

@ -1 +1 @@
eaf1f1b405ec2c498092527fae00e5dbe9e176c1
b61402af690ac08b68974f3c807096b0cffd9bc0

View File

@ -2114,6 +2114,8 @@ static void constructAutomaticIndex(
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
int iCol = pTerm->u.leftColumn;
Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
testcase( iCol==BMS-1 );
testcase( iCol==BMS );
if( (idxCols & cMask)==0 ){
Expr *pX = pTerm->pExpr;
idxCols |= cMask;
@ -3046,7 +3048,6 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){
int *aiColumn = pIndex->aiColumn;
StrAccum txt;
if( pIndex==0 ) return 0;
if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){
return 0;
}
@ -3113,7 +3114,7 @@ static void explainOneScan(
zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
}
if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0
&& pLoop->u.btree.pIndex!=0
&& ALWAYS(pLoop->u.btree.pIndex!=0)
){
char *zWhere = explainIndexRange(db, pLoop, pItem->pTab);
zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg,
@ -3133,7 +3134,7 @@ static void explainOneScan(
zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg);
}else if( flags&WHERE_BTM_LIMIT ){
zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg);
}else if( flags&WHERE_TOP_LIMIT ){
}else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){
zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg);
}
}
@ -3487,10 +3488,10 @@ static Bitmask codeOneLoopStart(
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
}
testcase( pRangeStart && pRangeStart->eOperator & WO_LE );
testcase( pRangeStart && pRangeStart->eOperator & WO_GE );
testcase( pRangeEnd && pRangeEnd->eOperator & WO_LE );
testcase( pRangeEnd && pRangeEnd->eOperator & WO_GE );
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 );
testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 );
startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE);
endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE);
start_constraints = pRangeStart || nEq>0;
@ -3889,6 +3890,8 @@ static Bitmask codeOneLoopStart(
pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
if( pAlt==0 ) continue;
if( pAlt->wtFlags & (TERM_CODED) ) continue;
testcase( pAlt->eOperator & WO_EQ );
testcase( pAlt->eOperator & WO_IN );
VdbeNoopComment((v, "begin transitive constraint"));
sEq = *pAlt->pExpr;
sEq.pLeft = pE->pLeft;
@ -4095,6 +4098,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
WhereCost rCost = whereCostAdd(p->rRun,p->rSetup);
WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup);
if( rCost < rTemplate ){
testcase( rCost==rTemplate-1 );
goto whereLoopInsert_noop;
}
if( rCost == rTemplate && p->prereq <= pTemplate->prereq ){
@ -4120,6 +4124,8 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
&& p->rSetup<=pTemplate->rSetup
&& p->rRun<=pTemplate->rRun
){
testcase( p->rSetup==pTemplate->rSetup );
testcase( p->rRun==pTemplate->rRun );
/* p is equal or better than pTemplate */
if( p->nLTerm<pTemplate->nLTerm
&& (p->wsFlags & WHERE_INDEXED)!=0
@ -4145,14 +4151,26 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
goto whereLoopInsert_noop;
}
}
testcase( (p->prereq & pTemplate->prereq)==p->prereq
&& p->rSetup==pTemplate->rSetup+1 );
testcase( (p->prereq & pTemplate->prereq)==p->prereq
&& p->rSetup<=pTemplate->rSetup
&& p->rRun==pTemplate->rRun+1 );
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
&& p->rSetup>=pTemplate->rSetup
&& p->rRun>=pTemplate->rRun
){
/* Overwrite an existing WhereLoop with a better one */
testcase( p->rSetup==pTemplate->rSetup );
testcase( p->rRun==pTemplate->rRun );
pNext = p->pNextLoop;
break;
}
testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq
&& p->rSetup==pTemplate->rSetup-1 );
testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq
&& p->rSetup>=pTemplate->rSetup-1
&& p->rRun==pTemplate->rRun-1 );
}
/* If we reach this point it means that either p[] should be overwritten
@ -4231,7 +4249,6 @@ static int whereLoopAddBtreeIndex(
if( db->mallocFailed ) return SQLITE_NOMEM;
assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
assert( pNew->u.btree.nEq<=pProbe->nColumn );
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
if( pNew->wsFlags & WHERE_BTM_LIMIT ){
opMask = WO_LT|WO_LE;
@ -4242,6 +4259,7 @@ static int whereLoopAddBtreeIndex(
}
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
assert( pNew->u.btree.nEq<=pProbe->nColumn );
if( pNew->u.btree.nEq < pProbe->nColumn ){
iCol = pProbe->aiColumn[pNew->u.btree.nEq];
nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
@ -4301,10 +4319,15 @@ static int whereLoopAddBtreeIndex(
nIn = 10; assert( 10==whereCost(2) );
pNew->nOut = nRowEst + nInMul + nIn;
}else if( pTerm->eOperator & (WO_GT|WO_GE) ){
testcase( pTerm->eOperator & WO_GT );
testcase( pTerm->eOperator & WO_GE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
pBtm = pTerm;
pTop = 0;
}else if( pTerm->eOperator & (WO_LT|WO_LE) ){
}else{
assert( pTerm->eOperator & (WO_LT|WO_LE) );
testcase( pTerm->eOperator & WO_LT );
testcase( pTerm->eOperator & WO_LE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
pTop = pTerm;
pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
@ -4393,6 +4416,8 @@ static Bitmask columnsInIndex(Index *pIdx){
int j;
for(j=pIdx->nColumn-1; j>=0; j--){
int x = pIdx->aiColumn[j];
testcase( x==BMS-1 );
testcase( x==BMS-2 );
if( x<BMS-1 ) m |= MASKBIT(x);
}
return m;
@ -4604,7 +4629,10 @@ static int whereLoopAddVirtual(
pNew->u.vtab.needFree = 0;
pUsage = pIdxInfo->aConstraintUsage;
nConstraint = pIdxInfo->nConstraint;
if( whereLoopResize(db, pNew, nConstraint) ) return SQLITE_NOMEM;
if( whereLoopResize(db, pNew, nConstraint) ){
sqlite3DbFree(db, pIdxInfo);
return SQLITE_NOMEM;
}
for(iPhase=0; iPhase<=3; iPhase++){
if( !seenIn && (iPhase&1)!=0 ){
@ -4621,9 +4649,10 @@ static int whereLoopAddVirtual(
pIdxCons->usable = 0;
if( (pTerm->eOperator & WO_IN)!=0 ){
seenIn = 1;
}else if( pTerm->prereqRight!=0 ){
}
if( pTerm->prereqRight!=0 ){
seenVar = 1;
}else{
}else if( (pTerm->eOperator & WO_IN)==0 ){
pIdxCons->usable = 1;
}
break;
@ -4668,11 +4697,16 @@ static int whereLoopAddVirtual(
sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName);
goto whereLoopAddVtab_exit;
}
testcase( iTerm==nConstraint-1 );
testcase( j==0 );
testcase( j==pWC->nTerm-1 );
pTerm = &pWC->a[j];
pNew->prereq |= pTerm->prereqRight;
assert( iTerm<pNew->nLSlot );
pNew->aLTerm[iTerm] = pTerm;
if( iTerm>mxTerm ) mxTerm = iTerm;
testcase( iTerm==15 );
testcase( iTerm==16 );
if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
if( (pTerm->eOperator & WO_IN)!=0 ){
if( pUsage[i].omit==0 ){
@ -4923,6 +4957,7 @@ static int wherePathSatisfiesOrderBy(
if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0;
nOrderBy = pOrderBy->nExpr;
testcase( nOrderBy==BMS-1 );
if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */
isOrderDistinct = 1;
obDone = MASKBIT(nOrderBy)-1;
@ -4947,9 +4982,7 @@ static int wherePathSatisfiesOrderBy(
pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
~ready, WO_EQ|WO_ISNULL, 0);
if( pTerm==0 ) continue;
testcase( pTerm->eOperator & WO_EQ );
testcase( pTerm->eOperator & WO_ISNULL );
if( pOBExpr->iColumn>=0 ){
if( (pTerm->eOperator&WO_EQ)!=0 && pOBExpr->iColumn>=0 ){
const char *z1, *z2;
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( !pColl ) pColl = db->pDfltColl;
@ -4985,7 +5018,10 @@ static int wherePathSatisfiesOrderBy(
if( j<pLoop->u.btree.nEq
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
){
if( i & WO_ISNULL ) isOrderDistinct = 0;
if( i & WO_ISNULL ){
testcase( isOrderDistinct );
isOrderDistinct = 0;
}
continue;
}
@ -4999,6 +5035,7 @@ static int wherePathSatisfiesOrderBy(
if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
}else{
/* The ROWID column at the end */
assert( j==nColumn );
iColumn = -1;
revIdx = 0;
}
@ -5037,7 +5074,10 @@ static int wherePathSatisfiesOrderBy(
break;
}
if( isMatch ){
if( iColumn<0 ) distinctColumns = 1;
if( iColumn<0 ){
testcase( distinctColumns==0 );
distinctColumns = 1;
}
obSat |= MASKBIT(i);
if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
/* Make sure the sort order is compatible in an ORDER BY clause.
@ -5052,7 +5092,10 @@ static int wherePathSatisfiesOrderBy(
}
}else{
/* No match found */
if( j==0 || j<nColumn ) isOrderDistinct = 0;
if( j==0 || j<nColumn ){
testcase( isOrderDistinct!=0 );
isOrderDistinct = 0;
}
break;
}
} /* end Loop over all index columns */
@ -5199,6 +5242,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
/* Check to see if pWLoop should be added to the mxChoice best so far */
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
if( pTo->maskLoop==maskNew && pTo->isOrderedValid==isOrderedValid ){
testcase( jj==nTo-1 );
break;
}
}
@ -5242,8 +5286,10 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
}
#endif
testcase( pTo->rCost==rCost );
continue;
}
testcase( pTo->rCost==rCost+1 );
/* A new and better score for a previously created equivalent path */
#ifdef WHERETRACE_ENABLED
if( sqlite3WhereTrace&0x4 ){
@ -5779,8 +5825,8 @@ WhereInfo *sqlite3WhereBegin(
&& (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
testcase( pTab->nCol==BMS-1 );
testcase( pTab->nCol==BMS );
testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 );
testcase( !pWInfo->okOnePass && pTab->nCol==BMS );
if( !pWInfo->okOnePass && pTab->nCol<BMS ){
Bitmask b = pTabItem->colUsed;
int n = 0;