Add more testcase() macros. Fix a memory leak following OOM in the
virtual table analysis logic. FossilOrigin-Name: b61402af690ac08b68974f3c807096b0cffd9bc0
This commit is contained in:
parent
93ec45d560
commit
7963b0e853
12
manifest
12
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
eaf1f1b405ec2c498092527fae00e5dbe9e176c1
|
||||
b61402af690ac08b68974f3c807096b0cffd9bc0
|
86
src/where.c
86
src/where.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user