diff --git a/manifest b/manifest index 9a336de116..8f9dc7b011 100644 --- a/manifest +++ b/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 diff --git a/manifest.uuid b/manifest.uuid index 2d08ee9b92..a6139b6aec 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eaf1f1b405ec2c498092527fae00e5dbe9e176c1 \ No newline at end of file +b61402af690ac08b68974f3c807096b0cffd9bc0 \ No newline at end of file diff --git a/src/where.c b/src/where.c index cf55858f7e..e3ab83c592 100644 --- a/src/where.c +++ b/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_TOP_LIMIT ){ + }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowideOperator & 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->nLTermnLTerm && (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( xu.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( iTermnLSlot ); 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<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( ju.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 || jmaskLoop==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->nColcolUsed; int n = 0;