| | @@ -670,11 +670,11 @@ |
| 670 | 670 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 671 | 671 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 672 | 672 | */ |
| 673 | 673 | #define SQLITE_VERSION "3.7.17" |
| 674 | 674 | #define SQLITE_VERSION_NUMBER 3007017 |
| 675 | | -#define SQLITE_SOURCE_ID "2013-06-14 02:51:48 b920bb70bb009b7c54e7667544c9810c5ee25e19" |
| 675 | +#define SQLITE_SOURCE_ID "2013-06-18 01:52:41 4c6d58d75d51e1ce829aec214617c3a89e784a2d" |
| 676 | 676 | |
| 677 | 677 | /* |
| 678 | 678 | ** CAPI3REF: Run-Time Library Version Numbers |
| 679 | 679 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 680 | 680 | ** |
| | @@ -76734,12 +76734,12 @@ |
| 76734 | 76734 | eType = IN_INDEX_EPH; |
| 76735 | 76735 | if( prNotFound ){ |
| 76736 | 76736 | *prNotFound = rMayHaveNull = ++pParse->nMem; |
| 76737 | 76737 | sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); |
| 76738 | 76738 | }else{ |
| 76739 | | - testcase( pParse->nQueryLoop>1 ); |
| 76740 | | - pParse->nQueryLoop = 1; |
| 76739 | + testcase( pParse->nQueryLoop>0 ); |
| 76740 | + pParse->nQueryLoop = 0; |
| 76741 | 76741 | if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){ |
| 76742 | 76742 | eType = IN_INDEX_ROWID; |
| 76743 | 76743 | } |
| 76744 | 76744 | } |
| 76745 | 76745 | sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); |
| | @@ -97520,12 +97520,12 @@ |
| 97520 | 97520 | if( sqlite3ExprIsInteger(p->pLimit, &n) ){ |
| 97521 | 97521 | sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit); |
| 97522 | 97522 | VdbeComment((v, "LIMIT counter")); |
| 97523 | 97523 | if( n==0 ){ |
| 97524 | 97524 | sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); |
| 97525 | | - }else{ |
| 97526 | | - if( p->nSelectRow > n ) p->nSelectRow = n; |
| 97525 | + }else if( n>=0 && p->nSelectRow>(u64)n ){ |
| 97526 | + p->nSelectRow = n; |
| 97527 | 97527 | } |
| 97528 | 97528 | }else{ |
| 97529 | 97529 | sqlite3ExprCode(pParse, p->pLimit, iLimit); |
| 97530 | 97530 | sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); |
| 97531 | 97531 | VdbeComment((v, "LIMIT counter")); |
| | @@ -97715,11 +97715,11 @@ |
| 97715 | 97715 | pDelete = p->pPrior; |
| 97716 | 97716 | p->pPrior = pPrior; |
| 97717 | 97717 | p->nSelectRow += pPrior->nSelectRow; |
| 97718 | 97718 | if( pPrior->pLimit |
| 97719 | 97719 | && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit) |
| 97720 | | - && p->nSelectRow > nLimit |
| 97720 | + && nLimit>0 && p->nSelectRow > (u64)nLimit |
| 97721 | 97721 | ){ |
| 97722 | 97722 | p->nSelectRow = nLimit; |
| 97723 | 97723 | } |
| 97724 | 97724 | if( addr ){ |
| 97725 | 97725 | sqlite3VdbeJumpHere(v, addr); |
| | @@ -100383,11 +100383,12 @@ |
| 100383 | 100383 | ** This might involve two separate loops with an OP_Sort in between, or |
| 100384 | 100384 | ** it might be a single loop that uses an index to extract information |
| 100385 | 100385 | ** in the right order to begin with. |
| 100386 | 100386 | */ |
| 100387 | 100387 | sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); |
| 100388 | | - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, 0, 0); |
| 100388 | + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, |
| 100389 | + WHERE_GROUPBY, 0); |
| 100389 | 100390 | if( pWInfo==0 ) goto select_end; |
| 100390 | 100391 | if( sqlite3WhereIsOrdered(pWInfo) ){ |
| 100391 | 100392 | /* The optimizer is able to deliver rows in group by order so |
| 100392 | 100393 | ** we do not have to sort. The OP_OpenEphemeral table will be |
| 100393 | 100394 | ** cancelled later because we still need to use the pKeyInfo |
| | @@ -104352,11 +104353,11 @@ |
| 104352 | 104353 | ** useful utility to have around when working with this module. |
| 104353 | 104354 | */ |
| 104354 | 104355 | typedef unsigned short int WhereCost; |
| 104355 | 104356 | |
| 104356 | 104357 | /* |
| 104357 | | -** This object contains information needed to implement a single nestd |
| 104358 | +** This object contains information needed to implement a single nested |
| 104358 | 104359 | ** loop in WHERE clause. |
| 104359 | 104360 | ** |
| 104360 | 104361 | ** Contrast this object with WhereLoop. This object describes the |
| 104361 | 104362 | ** implementation of the loop. WhereLoop describes the algorithm. |
| 104362 | 104363 | ** This object contains a pointer to the WhereLoop algorithm as one of |
| | @@ -106328,11 +106329,10 @@ |
| 106328 | 106329 | int mxBitCol; /* Maximum column in pSrc->colUsed */ |
| 106329 | 106330 | CollSeq *pColl; /* Collating sequence to on a column */ |
| 106330 | 106331 | WhereLoop *pLoop; /* The Loop object */ |
| 106331 | 106332 | Bitmask idxCols; /* Bitmap of columns used for indexing */ |
| 106332 | 106333 | Bitmask extraCols; /* Bitmap of additional columns */ |
| 106333 | | - const int mxConstraint = 10; /* Maximum number of constraints */ |
| 106334 | 106334 | |
| 106335 | 106335 | /* Generate code to skip over the creation and initialization of the |
| 106336 | 106336 | ** transient index on 2nd and subsequent iterations of the loop. */ |
| 106337 | 106337 | v = pParse->pVdbe; |
| 106338 | 106338 | assert( v!=0 ); |
| | @@ -106343,11 +106343,11 @@ |
| 106343 | 106343 | nColumn = 0; |
| 106344 | 106344 | pTable = pSrc->pTab; |
| 106345 | 106345 | pWCEnd = &pWC->a[pWC->nTerm]; |
| 106346 | 106346 | pLoop = pLevel->pWLoop; |
| 106347 | 106347 | idxCols = 0; |
| 106348 | | - for(pTerm=pWC->a; pTerm<pWCEnd && pLoop->nLTerm<mxConstraint; pTerm++){ |
| 106348 | + for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ |
| 106349 | 106349 | if( termCanDriveIndex(pTerm, pSrc, notReady) ){ |
| 106350 | 106350 | int iCol = pTerm->u.leftColumn; |
| 106351 | 106351 | Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); |
| 106352 | 106352 | testcase( iCol==BMS ); |
| 106353 | 106353 | testcase( iCol==BMS-1 ); |
| | @@ -106401,10 +106401,12 @@ |
| 106401 | 106401 | idxCols = 0; |
| 106402 | 106402 | for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ |
| 106403 | 106403 | if( termCanDriveIndex(pTerm, pSrc, notReady) ){ |
| 106404 | 106404 | int iCol = pTerm->u.leftColumn; |
| 106405 | 106405 | Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); |
| 106406 | + testcase( iCol==BMS-1 ); |
| 106407 | + testcase( iCol==BMS ); |
| 106406 | 106408 | if( (idxCols & cMask)==0 ){ |
| 106407 | 106409 | Expr *pX = pTerm->pExpr; |
| 106408 | 106410 | idxCols |= cMask; |
| 106409 | 106411 | pIdx->aiColumn[n] = pTerm->u.leftColumn; |
| 106410 | 106412 | pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); |
| | @@ -107214,12 +107216,10 @@ |
| 107214 | 107216 | ** string in this example would be set to SQLITE_AFF_NONE. |
| 107215 | 107217 | */ |
| 107216 | 107218 | static int codeAllEqualityTerms( |
| 107217 | 107219 | Parse *pParse, /* Parsing context */ |
| 107218 | 107220 | WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ |
| 107219 | | - WhereClause *pWC, /* The WHERE clause */ |
| 107220 | | - Bitmask notReady, /* Which parts of FROM have not yet been coded */ |
| 107221 | 107221 | int bRev, /* Reverse the order of IN operators */ |
| 107222 | 107222 | int nExtraReg, /* Number of extra registers to allocate */ |
| 107223 | 107223 | char **pzAff /* OUT: Set to point to affinity string */ |
| 107224 | 107224 | ){ |
| 107225 | 107225 | int nEq; /* The number of == or IN constraints to code */ |
| | @@ -107335,11 +107335,10 @@ |
| 107335 | 107335 | int i, j; |
| 107336 | 107336 | Column *aCol = pTab->aCol; |
| 107337 | 107337 | int *aiColumn = pIndex->aiColumn; |
| 107338 | 107338 | StrAccum txt; |
| 107339 | 107339 | |
| 107340 | | - if( pIndex==0 ) return 0; |
| 107341 | 107340 | if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ |
| 107342 | 107341 | return 0; |
| 107343 | 107342 | } |
| 107344 | 107343 | sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH); |
| 107345 | 107344 | txt.db = db; |
| | @@ -107402,11 +107401,11 @@ |
| 107402 | 107401 | |
| 107403 | 107402 | if( pItem->zAlias ){ |
| 107404 | 107403 | zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); |
| 107405 | 107404 | } |
| 107406 | 107405 | if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 |
| 107407 | | - && pLoop->u.btree.pIndex!=0 |
| 107406 | + && ALWAYS(pLoop->u.btree.pIndex!=0) |
| 107408 | 107407 | ){ |
| 107409 | 107408 | char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); |
| 107410 | 107409 | zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg, |
| 107411 | 107410 | ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""), |
| 107412 | 107411 | ((flags & WHERE_IDX_ONLY)?"COVERING ":""), |
| | @@ -107422,11 +107421,11 @@ |
| 107422 | 107421 | zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); |
| 107423 | 107422 | }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ |
| 107424 | 107423 | zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg); |
| 107425 | 107424 | }else if( flags&WHERE_BTM_LIMIT ){ |
| 107426 | 107425 | zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg); |
| 107427 | | - }else if( flags&WHERE_TOP_LIMIT ){ |
| 107426 | + }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){ |
| 107428 | 107427 | zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg); |
| 107429 | 107428 | } |
| 107430 | 107429 | } |
| 107431 | 107430 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 107432 | 107431 | else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ |
| | @@ -107593,10 +107592,11 @@ |
| 107593 | 107592 | assert( omitTable==0 ); |
| 107594 | 107593 | j = 0; |
| 107595 | 107594 | pStart = pEnd = 0; |
| 107596 | 107595 | if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; |
| 107597 | 107596 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; |
| 107597 | + assert( pStart!=0 || pEnd!=0 ); |
| 107598 | 107598 | if( bRev ){ |
| 107599 | 107599 | pTerm = pStart; |
| 107600 | 107600 | pStart = pEnd; |
| 107601 | 107601 | pEnd = pTerm; |
| 107602 | 107602 | } |
| | @@ -107647,15 +107647,11 @@ |
| 107647 | 107647 | } |
| 107648 | 107648 | start = sqlite3VdbeCurrentAddr(v); |
| 107649 | 107649 | pLevel->op = bRev ? OP_Prev : OP_Next; |
| 107650 | 107650 | pLevel->p1 = iCur; |
| 107651 | 107651 | pLevel->p2 = start; |
| 107652 | | - if( pStart==0 && pEnd==0 ){ |
| 107653 | | - pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; |
| 107654 | | - }else{ |
| 107655 | | - assert( pLevel->p5==0 ); |
| 107656 | | - } |
| 107652 | + assert( pLevel->p5==0 ); |
| 107657 | 107653 | if( testOp!=OP_Noop ){ |
| 107658 | 107654 | iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse); |
| 107659 | 107655 | sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); |
| 107660 | 107656 | sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); |
| 107661 | 107657 | sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); |
| | @@ -107762,13 +107758,11 @@ |
| 107762 | 107758 | |
| 107763 | 107759 | /* Generate code to evaluate all constraint terms using == or IN |
| 107764 | 107760 | ** and store the values of those terms in an array of registers |
| 107765 | 107761 | ** starting at regBase. |
| 107766 | 107762 | */ |
| 107767 | | - regBase = codeAllEqualityTerms( |
| 107768 | | - pParse, pLevel, pWC, notReady, bRev, nExtraReg, &zStartAff |
| 107769 | | - ); |
| 107763 | + regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); |
| 107770 | 107764 | zEndAff = sqlite3DbStrDup(pParse->db, zStartAff); |
| 107771 | 107765 | addrNxt = pLevel->addrNxt; |
| 107772 | 107766 | |
| 107773 | 107767 | /* If we are doing a reverse order scan on an ascending index, or |
| 107774 | 107768 | ** a forward order scan on a descending index, interchange the |
| | @@ -107778,14 +107772,14 @@ |
| 107778 | 107772 | || (bRev && pIdx->nColumn==nEq) |
| 107779 | 107773 | ){ |
| 107780 | 107774 | SWAP(WhereTerm *, pRangeEnd, pRangeStart); |
| 107781 | 107775 | } |
| 107782 | 107776 | |
| 107783 | | - testcase( pRangeStart && pRangeStart->eOperator & WO_LE ); |
| 107784 | | - testcase( pRangeStart && pRangeStart->eOperator & WO_GE ); |
| 107785 | | - testcase( pRangeEnd && pRangeEnd->eOperator & WO_LE ); |
| 107786 | | - testcase( pRangeEnd && pRangeEnd->eOperator & WO_GE ); |
| 107777 | + testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); |
| 107778 | + testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); |
| 107779 | + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); |
| 107780 | + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); |
| 107787 | 107781 | startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); |
| 107788 | 107782 | endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); |
| 107789 | 107783 | start_constraints = pRangeStart || nEq>0; |
| 107790 | 107784 | |
| 107791 | 107785 | /* Seek the index cursor to the start of the range. */ |
| | @@ -108088,12 +108082,12 @@ |
| 108088 | 108082 | ** terms, set pCov to the candidate covering index. Otherwise, set |
| 108089 | 108083 | ** pCov to NULL to indicate that no candidate covering index will |
| 108090 | 108084 | ** be available. |
| 108091 | 108085 | */ |
| 108092 | 108086 | pSubLoop = pSubWInfo->a[0].pWLoop; |
| 108087 | + assert( (pSubLoop->wsFlags & WHERE_TEMP_INDEX)==0 ); |
| 108093 | 108088 | if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 |
| 108094 | | - && (pSubLoop->wsFlags & WHERE_TEMP_INDEX)==0 |
| 108095 | 108089 | && (ii==0 || pSubLoop->u.btree.pIndex==pCov) |
| 108096 | 108090 | ){ |
| 108097 | 108091 | assert( pSubWInfo->a[0].iIdxCur==iCovCur ); |
| 108098 | 108092 | pCov = pSubLoop->u.btree.pIndex; |
| 108099 | 108093 | }else{ |
| | @@ -108180,10 +108174,12 @@ |
| 108180 | 108174 | assert( !ExprHasProperty(pE, EP_FromJoin) ); |
| 108181 | 108175 | assert( (pTerm->prereqRight & newNotReady)!=0 ); |
| 108182 | 108176 | pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0); |
| 108183 | 108177 | if( pAlt==0 ) continue; |
| 108184 | 108178 | if( pAlt->wtFlags & (TERM_CODED) ) continue; |
| 108179 | + testcase( pAlt->eOperator & WO_EQ ); |
| 108180 | + testcase( pAlt->eOperator & WO_IN ); |
| 108185 | 108181 | VdbeNoopComment((v, "begin transitive constraint")); |
| 108186 | 108182 | sEq = *pAlt->pExpr; |
| 108187 | 108183 | sEq.pLeft = pE->pLeft; |
| 108188 | 108184 | sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL); |
| 108189 | 108185 | } |
| | @@ -108386,13 +108382,14 @@ |
| 108386 | 108382 | if( (p = pBuilder->pBest)!=0 ){ |
| 108387 | 108383 | if( p->maskSelf!=0 ){ |
| 108388 | 108384 | WhereCost rCost = whereCostAdd(p->rRun,p->rSetup); |
| 108389 | 108385 | WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup); |
| 108390 | 108386 | if( rCost < rTemplate ){ |
| 108387 | + testcase( rCost==rTemplate-1 ); |
| 108391 | 108388 | goto whereLoopInsert_noop; |
| 108392 | 108389 | } |
| 108393 | | - if( rCost == rTemplate && p->prereq <= pTemplate->prereq ){ |
| 108390 | + if( rCost==rTemplate && (p->prereq & pTemplate->prereq)==p->prereq ){ |
| 108394 | 108391 | goto whereLoopInsert_noop; |
| 108395 | 108392 | } |
| 108396 | 108393 | } |
| 108397 | 108394 | #if WHERETRACE_ENABLED |
| 108398 | 108395 | if( sqlite3WhereTrace & 0x8 ){ |
| | @@ -108411,11 +108408,13 @@ |
| 108411 | 108408 | if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ) continue; |
| 108412 | 108409 | if( (p->prereq & pTemplate->prereq)==p->prereq |
| 108413 | 108410 | && p->rSetup<=pTemplate->rSetup |
| 108414 | 108411 | && p->rRun<=pTemplate->rRun |
| 108415 | 108412 | ){ |
| 108416 | | - /* p is equal or better than pTemplate */ |
| 108413 | + /* This branch taken when p is equal or better than pTemplate in |
| 108414 | + ** all of (1) dependences (2) setup-cost, and (3) run-cost. */ |
| 108415 | + testcase( p->rRun==pTemplate->rRun ); |
| 108417 | 108416 | if( p->nLTerm<pTemplate->nLTerm |
| 108418 | 108417 | && (p->wsFlags & WHERE_INDEXED)!=0 |
| 108419 | 108418 | && (pTemplate->wsFlags & WHERE_INDEXED)!=0 |
| 108420 | 108419 | && p->u.btree.pIndex==pTemplate->u.btree.pIndex |
| 108421 | 108420 | && p->prereq==pTemplate->prereq |
| | @@ -108436,18 +108435,28 @@ |
| 108436 | 108435 | /* pTemplate is not helpful. |
| 108437 | 108436 | ** Return without changing or adding anything */ |
| 108438 | 108437 | goto whereLoopInsert_noop; |
| 108439 | 108438 | } |
| 108440 | 108439 | } |
| 108440 | + testcase( (p->prereq & pTemplate->prereq)==p->prereq |
| 108441 | + && p->rSetup<=pTemplate->rSetup |
| 108442 | + && p->rRun==pTemplate->rRun+1 ); |
| 108441 | 108443 | if( (p->prereq & pTemplate->prereq)==pTemplate->prereq |
| 108442 | 108444 | && p->rSetup>=pTemplate->rSetup |
| 108443 | 108445 | && p->rRun>=pTemplate->rRun |
| 108444 | 108446 | ){ |
| 108445 | | - /* Overwrite an existing WhereLoop with a better one */ |
| 108447 | + /* Overwrite an existing WhereLoop with a better one: one that is |
| 108448 | + ** better at one of (1) dependences, (2) setup-cost, or (3) run-cost |
| 108449 | + ** and is no worse in any of those categories. */ |
| 108450 | + testcase( p->rSetup==pTemplate->rSetup ); |
| 108451 | + testcase( p->rRun==pTemplate->rRun ); |
| 108446 | 108452 | pNext = p->pNextLoop; |
| 108447 | 108453 | break; |
| 108448 | 108454 | } |
| 108455 | + testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq |
| 108456 | + && p->rSetup>=pTemplate->rSetup |
| 108457 | + && p->rRun==pTemplate->rRun-1 ); |
| 108449 | 108458 | } |
| 108450 | 108459 | |
| 108451 | 108460 | /* If we reach this point it means that either p[] should be overwritten |
| 108452 | 108461 | ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new |
| 108453 | 108462 | ** WhereLoop and insert it. |
| | @@ -108522,11 +108531,10 @@ |
| 108522 | 108531 | |
| 108523 | 108532 | pNew = pBuilder->pNew; |
| 108524 | 108533 | if( db->mallocFailed ) return SQLITE_NOMEM; |
| 108525 | 108534 | |
| 108526 | 108535 | assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); |
| 108527 | | - assert( pNew->u.btree.nEq<=pProbe->nColumn ); |
| 108528 | 108536 | assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); |
| 108529 | 108537 | if( pNew->wsFlags & WHERE_BTM_LIMIT ){ |
| 108530 | 108538 | opMask = WO_LT|WO_LE; |
| 108531 | 108539 | }else if( pProbe->tnum<=0 || (pSrc->jointype & JT_LEFT)!=0 ){ |
| 108532 | 108540 | opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE; |
| | @@ -108533,10 +108541,11 @@ |
| 108533 | 108541 | }else{ |
| 108534 | 108542 | opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE; |
| 108535 | 108543 | } |
| 108536 | 108544 | if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); |
| 108537 | 108545 | |
| 108546 | + assert( pNew->u.btree.nEq<=pProbe->nColumn ); |
| 108538 | 108547 | if( pNew->u.btree.nEq < pProbe->nColumn ){ |
| 108539 | 108548 | iCol = pProbe->aiColumn[pNew->u.btree.nEq]; |
| 108540 | 108549 | nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]); |
| 108541 | 108550 | }else{ |
| 108542 | 108551 | iCol = -1; |
| | @@ -108580,11 +108589,11 @@ |
| 108580 | 108589 | pNew->wsFlags |= WHERE_COLUMN_EQ; |
| 108581 | 108590 | if( iCol<0 |
| 108582 | 108591 | || (pProbe->onError!=OE_None && nInMul==0 |
| 108583 | 108592 | && pNew->u.btree.nEq==pProbe->nColumn-1) |
| 108584 | 108593 | ){ |
| 108585 | | - testcase( pNew->wsFlags & WHERE_COLUMN_IN ); |
| 108594 | + assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 ); |
| 108586 | 108595 | pNew->wsFlags |= WHERE_ONEROW; |
| 108587 | 108596 | } |
| 108588 | 108597 | pNew->u.btree.nEq++; |
| 108589 | 108598 | pNew->nOut = nRowEst + nInMul; |
| 108590 | 108599 | }else if( pTerm->eOperator & (WO_ISNULL) ){ |
| | @@ -108592,14 +108601,19 @@ |
| 108592 | 108601 | pNew->u.btree.nEq++; |
| 108593 | 108602 | /* TUNING: IS NULL selects 2 rows */ |
| 108594 | 108603 | nIn = 10; assert( 10==whereCost(2) ); |
| 108595 | 108604 | pNew->nOut = nRowEst + nInMul + nIn; |
| 108596 | 108605 | }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ |
| 108606 | + testcase( pTerm->eOperator & WO_GT ); |
| 108607 | + testcase( pTerm->eOperator & WO_GE ); |
| 108597 | 108608 | pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; |
| 108598 | 108609 | pBtm = pTerm; |
| 108599 | 108610 | pTop = 0; |
| 108600 | | - }else if( pTerm->eOperator & (WO_LT|WO_LE) ){ |
| 108611 | + }else{ |
| 108612 | + assert( pTerm->eOperator & (WO_LT|WO_LE) ); |
| 108613 | + testcase( pTerm->eOperator & WO_LT ); |
| 108614 | + testcase( pTerm->eOperator & WO_LE ); |
| 108601 | 108615 | pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; |
| 108602 | 108616 | pTop = pTerm; |
| 108603 | 108617 | pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? |
| 108604 | 108618 | pNew->aLTerm[pNew->nLTerm-2] : 0; |
| 108605 | 108619 | } |
| | @@ -108612,10 +108626,12 @@ |
| 108612 | 108626 | } |
| 108613 | 108627 | #ifdef SQLITE_ENABLE_STAT3 |
| 108614 | 108628 | if( pNew->u.btree.nEq==1 && pProbe->nSample ){ |
| 108615 | 108629 | tRowcnt nOut = 0; |
| 108616 | 108630 | if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ |
| 108631 | + testcase( pTerm->eOperator & WO_EQ ); |
| 108632 | + testcase( pTerm->eOperator & WO_ISNULL ); |
| 108617 | 108633 | rc = whereEqualScanEst(pParse, pProbe, pTerm->pExpr->pRight, &nOut); |
| 108618 | 108634 | }else if( (pTerm->eOperator & WO_IN) |
| 108619 | 108635 | && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ |
| 108620 | 108636 | rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut); |
| 108621 | 108637 | } |
| | @@ -108682,10 +108698,12 @@ |
| 108682 | 108698 | static Bitmask columnsInIndex(Index *pIdx){ |
| 108683 | 108699 | Bitmask m = 0; |
| 108684 | 108700 | int j; |
| 108685 | 108701 | for(j=pIdx->nColumn-1; j>=0; j--){ |
| 108686 | 108702 | int x = pIdx->aiColumn[j]; |
| 108703 | + testcase( x==BMS-1 ); |
| 108704 | + testcase( x==BMS-2 ); |
| 108687 | 108705 | if( x<BMS-1 ) m |= MASKBIT(x); |
| 108688 | 108706 | } |
| 108689 | 108707 | return m; |
| 108690 | 108708 | } |
| 108691 | 108709 | |
| | @@ -108855,12 +108873,11 @@ |
| 108855 | 108873 | /* |
| 108856 | 108874 | ** Add all WhereLoop objects for a table of the join identified by |
| 108857 | 108875 | ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. |
| 108858 | 108876 | */ |
| 108859 | 108877 | static int whereLoopAddVirtual( |
| 108860 | | - WhereLoopBuilder *pBuilder, /* WHERE clause information */ |
| 108861 | | - Bitmask mExtra /* Extra prerequesites for using this table */ |
| 108878 | + WhereLoopBuilder *pBuilder /* WHERE clause information */ |
| 108862 | 108879 | ){ |
| 108863 | 108880 | WhereInfo *pWInfo; /* WHERE analysis context */ |
| 108864 | 108881 | Parse *pParse; /* The parsing context */ |
| 108865 | 108882 | WhereClause *pWC; /* The WHERE clause */ |
| 108866 | 108883 | struct SrcList_item *pSrc; /* The FROM clause term to search */ |
| | @@ -108894,11 +108911,14 @@ |
| 108894 | 108911 | pNew->wsFlags = WHERE_VIRTUALTABLE; |
| 108895 | 108912 | pNew->nLTerm = 0; |
| 108896 | 108913 | pNew->u.vtab.needFree = 0; |
| 108897 | 108914 | pUsage = pIdxInfo->aConstraintUsage; |
| 108898 | 108915 | nConstraint = pIdxInfo->nConstraint; |
| 108899 | | - if( whereLoopResize(db, pNew, nConstraint) ) return SQLITE_NOMEM; |
| 108916 | + if( whereLoopResize(db, pNew, nConstraint) ){ |
| 108917 | + sqlite3DbFree(db, pIdxInfo); |
| 108918 | + return SQLITE_NOMEM; |
| 108919 | + } |
| 108900 | 108920 | |
| 108901 | 108921 | for(iPhase=0; iPhase<=3; iPhase++){ |
| 108902 | 108922 | if( !seenIn && (iPhase&1)!=0 ){ |
| 108903 | 108923 | iPhase++; |
| 108904 | 108924 | if( iPhase>3 ) break; |
| | @@ -108911,13 +108931,14 @@ |
| 108911 | 108931 | switch( iPhase ){ |
| 108912 | 108932 | case 0: /* Constants without IN operator */ |
| 108913 | 108933 | pIdxCons->usable = 0; |
| 108914 | 108934 | if( (pTerm->eOperator & WO_IN)!=0 ){ |
| 108915 | 108935 | seenIn = 1; |
| 108916 | | - }else if( pTerm->prereqRight!=0 ){ |
| 108936 | + } |
| 108937 | + if( pTerm->prereqRight!=0 ){ |
| 108917 | 108938 | seenVar = 1; |
| 108918 | | - }else{ |
| 108939 | + }else if( (pTerm->eOperator & WO_IN)==0 ){ |
| 108919 | 108940 | pIdxCons->usable = 1; |
| 108920 | 108941 | } |
| 108921 | 108942 | break; |
| 108922 | 108943 | case 1: /* Constants with IN operators */ |
| 108923 | 108944 | assert( seenIn ); |
| | @@ -108958,15 +108979,20 @@ |
| 108958 | 108979 | ){ |
| 108959 | 108980 | rc = SQLITE_ERROR; |
| 108960 | 108981 | sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName); |
| 108961 | 108982 | goto whereLoopAddVtab_exit; |
| 108962 | 108983 | } |
| 108984 | + testcase( iTerm==nConstraint-1 ); |
| 108985 | + testcase( j==0 ); |
| 108986 | + testcase( j==pWC->nTerm-1 ); |
| 108963 | 108987 | pTerm = &pWC->a[j]; |
| 108964 | 108988 | pNew->prereq |= pTerm->prereqRight; |
| 108965 | 108989 | assert( iTerm<pNew->nLSlot ); |
| 108966 | 108990 | pNew->aLTerm[iTerm] = pTerm; |
| 108967 | 108991 | if( iTerm>mxTerm ) mxTerm = iTerm; |
| 108992 | + testcase( iTerm==15 ); |
| 108993 | + testcase( iTerm==16 ); |
| 108968 | 108994 | if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm; |
| 108969 | 108995 | if( (pTerm->eOperator & WO_IN)!=0 ){ |
| 108970 | 108996 | if( pUsage[i].omit==0 ){ |
| 108971 | 108997 | /* Do not attempt to use an IN constraint if the virtual table |
| 108972 | 108998 | ** says that the equivalent EQ constraint cannot be safely omitted. |
| | @@ -109066,11 +109092,11 @@ |
| 109066 | 109092 | sBest.maskSelf = 0; |
| 109067 | 109093 | sBest.rSetup = 0; |
| 109068 | 109094 | sBest.rRun = 0; |
| 109069 | 109095 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 109070 | 109096 | if( IsVirtual(pItem->pTab) ){ |
| 109071 | | - rc = whereLoopAddVirtual(&sSubBuild, mExtra); |
| 109097 | + rc = whereLoopAddVirtual(&sSubBuild); |
| 109072 | 109098 | }else |
| 109073 | 109099 | #endif |
| 109074 | 109100 | { |
| 109075 | 109101 | rc = whereLoopAddBtree(&sSubBuild, mExtra); |
| 109076 | 109102 | } |
| | @@ -109123,11 +109149,11 @@ |
| 109123 | 109149 | if( ((pItem->jointype|priorJoinType) & (JT_LEFT|JT_CROSS))!=0 ){ |
| 109124 | 109150 | mExtra = mPrior; |
| 109125 | 109151 | } |
| 109126 | 109152 | priorJoinType = pItem->jointype; |
| 109127 | 109153 | if( IsVirtual(pItem->pTab) ){ |
| 109128 | | - rc = whereLoopAddVirtual(pBuilder, mExtra); |
| 109154 | + rc = whereLoopAddVirtual(pBuilder); |
| 109129 | 109155 | }else{ |
| 109130 | 109156 | rc = whereLoopAddBtree(pBuilder, mExtra); |
| 109131 | 109157 | } |
| 109132 | 109158 | if( rc==SQLITE_OK ){ |
| 109133 | 109159 | rc = whereLoopAddOr(pBuilder, mExtra); |
| | @@ -109153,11 +109179,10 @@ |
| 109153 | 109179 | WhereInfo *pWInfo, /* The WHERE clause */ |
| 109154 | 109180 | ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ |
| 109155 | 109181 | WherePath *pPath, /* The WherePath to check */ |
| 109156 | 109182 | u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */ |
| 109157 | 109183 | u16 nLoop, /* Number of entries in pPath->aLoop[] */ |
| 109158 | | - u8 isLastLoop, /* True if pLast is the inner-most loop */ |
| 109159 | 109184 | WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ |
| 109160 | 109185 | Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ |
| 109161 | 109186 | ){ |
| 109162 | 109187 | u8 revSet; /* True if rev is known */ |
| 109163 | 109188 | u8 rev; /* Composite sort order */ |
| | @@ -109214,10 +109239,11 @@ |
| 109214 | 109239 | return pLast->u.vtab.isOrdered; |
| 109215 | 109240 | } |
| 109216 | 109241 | if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; |
| 109217 | 109242 | |
| 109218 | 109243 | nOrderBy = pOrderBy->nExpr; |
| 109244 | + testcase( nOrderBy==BMS-1 ); |
| 109219 | 109245 | if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ |
| 109220 | 109246 | isOrderDistinct = 1; |
| 109221 | 109247 | obDone = MASKBIT(nOrderBy)-1; |
| 109222 | 109248 | orderDistinctMask = 0; |
| 109223 | 109249 | ready = 0; |
| | @@ -109238,11 +109264,11 @@ |
| 109238 | 109264 | if( pOBExpr->op!=TK_COLUMN ) continue; |
| 109239 | 109265 | if( pOBExpr->iTable!=iCur ) continue; |
| 109240 | 109266 | pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, |
| 109241 | 109267 | ~ready, WO_EQ|WO_ISNULL, 0); |
| 109242 | 109268 | if( pTerm==0 ) continue; |
| 109243 | | - if( pOBExpr->iColumn>=0 ){ |
| 109269 | + if( (pTerm->eOperator&WO_EQ)!=0 && pOBExpr->iColumn>=0 ){ |
| 109244 | 109270 | const char *z1, *z2; |
| 109245 | 109271 | pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); |
| 109246 | 109272 | if( !pColl ) pColl = db->pDfltColl; |
| 109247 | 109273 | z1 = pColl->zName; |
| 109248 | 109274 | pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr); |
| | @@ -109262,34 +109288,10 @@ |
| 109262 | 109288 | }else{ |
| 109263 | 109289 | nColumn = pIndex->nColumn; |
| 109264 | 109290 | isOrderDistinct = pIndex->onError!=OE_None; |
| 109265 | 109291 | } |
| 109266 | 109292 | |
| 109267 | | - /* For every term of the index that is constrained by == or IS NULL, |
| 109268 | | - ** mark off corresponding ORDER BY terms wherever they occur |
| 109269 | | - ** in the ORDER BY clause. |
| 109270 | | - */ |
| 109271 | | - for(i=0; i<pLoop->u.btree.nEq; i++){ |
| 109272 | | - pTerm = pLoop->aLTerm[i]; |
| 109273 | | - if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))==0 ) continue; |
| 109274 | | - iColumn = pTerm->u.leftColumn; |
| 109275 | | - for(j=0; j<nOrderBy; j++){ |
| 109276 | | - if( MASKBIT(j) & obSat ) continue; |
| 109277 | | - pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[j].pExpr); |
| 109278 | | - if( pOBExpr->op!=TK_COLUMN ) continue; |
| 109279 | | - if( pOBExpr->iTable!=iCur ) continue; |
| 109280 | | - if( pOBExpr->iColumn!=iColumn ) continue; |
| 109281 | | - if( iColumn>=0 ){ |
| 109282 | | - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[j].pExpr); |
| 109283 | | - if( !pColl ) pColl = db->pDfltColl; |
| 109284 | | - if( sqlite3StrICmp(pColl->zName, pIndex->azColl[i])!=0 ) continue; |
| 109285 | | - } |
| 109286 | | - obSat |= MASKBIT(j); |
| 109287 | | - } |
| 109288 | | - if( obSat==obDone ) return 1; |
| 109289 | | - } |
| 109290 | | - |
| 109291 | 109293 | /* Loop through all columns of the index and deal with the ones |
| 109292 | 109294 | ** that are not constrained by == or IN. |
| 109293 | 109295 | */ |
| 109294 | 109296 | rev = revSet = 0; |
| 109295 | 109297 | distinctColumns = 0; |
| | @@ -109298,11 +109300,14 @@ |
| 109298 | 109300 | |
| 109299 | 109301 | /* Skip over == and IS NULL terms */ |
| 109300 | 109302 | if( j<pLoop->u.btree.nEq |
| 109301 | 109303 | && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 |
| 109302 | 109304 | ){ |
| 109303 | | - if( i & WO_ISNULL ) isOrderDistinct = 0; |
| 109305 | + if( i & WO_ISNULL ){ |
| 109306 | + testcase( isOrderDistinct ); |
| 109307 | + isOrderDistinct = 0; |
| 109308 | + } |
| 109304 | 109309 | continue; |
| 109305 | 109310 | } |
| 109306 | 109311 | |
| 109307 | 109312 | /* Get the column number in the table (iColumn) and sort order |
| 109308 | 109313 | ** (revIdx) for the j-th column of the index. |
| | @@ -109312,10 +109317,11 @@ |
| 109312 | 109317 | iColumn = pIndex->aiColumn[j]; |
| 109313 | 109318 | revIdx = pIndex->aSortOrder[j]; |
| 109314 | 109319 | if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; |
| 109315 | 109320 | }else{ |
| 109316 | 109321 | /* The ROWID column at the end */ |
| 109322 | + assert( j==nColumn ); |
| 109317 | 109323 | iColumn = -1; |
| 109318 | 109324 | revIdx = 0; |
| 109319 | 109325 | } |
| 109320 | 109326 | |
| 109321 | 109327 | /* An unconstrained column that might be NULL means that this |
| | @@ -109335,10 +109341,12 @@ |
| 109335 | 109341 | bOnce = 1; |
| 109336 | 109342 | isMatch = 0; |
| 109337 | 109343 | for(i=0; bOnce && i<nOrderBy; i++){ |
| 109338 | 109344 | if( MASKBIT(i) & obSat ) continue; |
| 109339 | 109345 | pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); |
| 109346 | + testcase( wctrlFlags & WHERE_GROUPBY ); |
| 109347 | + testcase( wctrlFlags & WHERE_DISTINCTBY ); |
| 109340 | 109348 | if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; |
| 109341 | 109349 | if( pOBExpr->op!=TK_COLUMN ) continue; |
| 109342 | 109350 | if( pOBExpr->iTable!=iCur ) continue; |
| 109343 | 109351 | if( pOBExpr->iColumn!=iColumn ) continue; |
| 109344 | 109352 | if( iColumn>=0 ){ |
| | @@ -109348,11 +109356,14 @@ |
| 109348 | 109356 | } |
| 109349 | 109357 | isMatch = 1; |
| 109350 | 109358 | break; |
| 109351 | 109359 | } |
| 109352 | 109360 | if( isMatch ){ |
| 109353 | | - if( iColumn<0 ) distinctColumns = 1; |
| 109361 | + if( iColumn<0 ){ |
| 109362 | + testcase( distinctColumns==0 ); |
| 109363 | + distinctColumns = 1; |
| 109364 | + } |
| 109354 | 109365 | obSat |= MASKBIT(i); |
| 109355 | 109366 | if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ |
| 109356 | 109367 | /* Make sure the sort order is compatible in an ORDER BY clause. |
| 109357 | 109368 | ** Sort order is irrelevant for a GROUP BY clause. */ |
| 109358 | 109369 | if( revSet ){ |
| | @@ -109363,15 +109374,21 @@ |
| 109363 | 109374 | revSet = 1; |
| 109364 | 109375 | } |
| 109365 | 109376 | } |
| 109366 | 109377 | }else{ |
| 109367 | 109378 | /* No match found */ |
| 109368 | | - if( j==0 || j<nColumn ) isOrderDistinct = 0; |
| 109379 | + if( j==0 || j<nColumn ){ |
| 109380 | + testcase( isOrderDistinct!=0 ); |
| 109381 | + isOrderDistinct = 0; |
| 109382 | + } |
| 109369 | 109383 | break; |
| 109370 | 109384 | } |
| 109371 | 109385 | } /* end Loop over all index columns */ |
| 109372 | | - if( distinctColumns ) isOrderDistinct = 1; |
| 109386 | + if( distinctColumns ){ |
| 109387 | + testcase( isOrderDistinct==0 ); |
| 109388 | + isOrderDistinct = 1; |
| 109389 | + } |
| 109373 | 109390 | } /* end-if not one-row */ |
| 109374 | 109391 | |
| 109375 | 109392 | /* Mark off any other ORDER BY terms that reference pLoop */ |
| 109376 | 109393 | if( isOrderDistinct ){ |
| 109377 | 109394 | orderDistinctMask |= pLoop->maskSelf; |
| | @@ -109385,11 +109402,10 @@ |
| 109385 | 109402 | } |
| 109386 | 109403 | } |
| 109387 | 109404 | } /* End the loop over all WhereLoops from outer-most down to inner-most */ |
| 109388 | 109405 | if( obSat==obDone ) return 1; |
| 109389 | 109406 | if( !isOrderDistinct ) return 0; |
| 109390 | | - if( isLastLoop ) return 1; |
| 109391 | 109407 | return -1; |
| 109392 | 109408 | } |
| 109393 | 109409 | |
| 109394 | 109410 | #ifdef WHERETRACE_ENABLED |
| 109395 | 109411 | /* For debugging use only: */ |
| | @@ -109492,11 +109508,11 @@ |
| 109492 | 109508 | rCost = whereCostAdd(rCost, pFrom->rCost); |
| 109493 | 109509 | maskNew = pFrom->maskLoop | pWLoop->maskSelf; |
| 109494 | 109510 | if( !isOrderedValid ){ |
| 109495 | 109511 | switch( wherePathSatisfiesOrderBy(pWInfo, |
| 109496 | 109512 | pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, |
| 109497 | | - iLoop, iLoop==nLoop-1, pWLoop, &revMask) ){ |
| 109513 | + iLoop, pWLoop, &revMask) ){ |
| 109498 | 109514 | case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ |
| 109499 | 109515 | isOrdered = 1; |
| 109500 | 109516 | isOrderedValid = 1; |
| 109501 | 109517 | break; |
| 109502 | 109518 | case 0: /* No. pFrom+pWLoop will require a separate sort */ |
| | @@ -109511,10 +109527,11 @@ |
| 109511 | 109527 | revMask = pFrom->revLoop; |
| 109512 | 109528 | } |
| 109513 | 109529 | /* Check to see if pWLoop should be added to the mxChoice best so far */ |
| 109514 | 109530 | for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){ |
| 109515 | 109531 | if( pTo->maskLoop==maskNew && pTo->isOrderedValid==isOrderedValid ){ |
| 109532 | + testcase( jj==nTo-1 ); |
| 109516 | 109533 | break; |
| 109517 | 109534 | } |
| 109518 | 109535 | } |
| 109519 | 109536 | if( jj>=nTo ){ |
| 109520 | 109537 | if( nTo>=mxChoice && rCost>=mxCost ){ |
| | @@ -109554,12 +109571,14 @@ |
| 109554 | 109571 | sqlite3DebugPrintf(" vs %s cost=%-3d order=%c\n", |
| 109555 | 109572 | wherePathName(pTo, iLoop+1, 0), pTo->rCost, |
| 109556 | 109573 | pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); |
| 109557 | 109574 | } |
| 109558 | 109575 | #endif |
| 109576 | + testcase( pTo->rCost==rCost ); |
| 109559 | 109577 | continue; |
| 109560 | 109578 | } |
| 109579 | + testcase( pTo->rCost==rCost+1 ); |
| 109561 | 109580 | /* A new and better score for a previously created equivalent path */ |
| 109562 | 109581 | #ifdef WHERETRACE_ENABLED |
| 109563 | 109582 | if( sqlite3WhereTrace&0x4 ){ |
| 109564 | 109583 | sqlite3DebugPrintf( |
| 109565 | 109584 | "Update %s cost=%-3d order=%c", |
| | @@ -109618,13 +109637,16 @@ |
| 109618 | 109637 | return SQLITE_ERROR; |
| 109619 | 109638 | } |
| 109620 | 109639 | |
| 109621 | 109640 | /* Find the lowest cost path. pFrom will be left pointing to that path */ |
| 109622 | 109641 | pFrom = aFrom; |
| 109642 | + assert( nFrom==1 ); |
| 109643 | +#if 0 /* The following is needed if nFrom is ever more than 1 */ |
| 109623 | 109644 | for(ii=1; ii<nFrom; ii++){ |
| 109624 | 109645 | if( pFrom->rCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; |
| 109625 | 109646 | } |
| 109647 | +#endif |
| 109626 | 109648 | assert( pWInfo->nLevel==nLoop ); |
| 109627 | 109649 | /* Load the lowest cost path into pWInfo */ |
| 109628 | 109650 | for(iLoop=0; iLoop<nLoop; iLoop++){ |
| 109629 | 109651 | WhereLevel *pLevel = pWInfo->a + iLoop; |
| 109630 | 109652 | pLevel->pWLoop = pWLoop = pFrom->aLoop[iLoop]; |
| | @@ -109635,11 +109657,11 @@ |
| 109635 | 109657 | && pWInfo->pDistinct |
| 109636 | 109658 | && nRowEst |
| 109637 | 109659 | ){ |
| 109638 | 109660 | Bitmask notUsed; |
| 109639 | 109661 | int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pDistinct, pFrom, |
| 109640 | | - WHERE_DISTINCTBY, nLoop-1, 1, pFrom->aLoop[nLoop-1], ¬Used); |
| 109662 | + WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); |
| 109641 | 109663 | if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; |
| 109642 | 109664 | } |
| 109643 | 109665 | if( pFrom->isOrdered ){ |
| 109644 | 109666 | if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ |
| 109645 | 109667 | pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; |
| | @@ -110012,11 +110034,11 @@ |
| 110012 | 110034 | } |
| 110013 | 110035 | } |
| 110014 | 110036 | if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ |
| 110015 | 110037 | pWInfo->revMask = (Bitmask)(-1); |
| 110016 | 110038 | } |
| 110017 | | - if( pParse->nErr || db->mallocFailed ){ |
| 110039 | + if( pParse->nErr || NEVER(db->mallocFailed) ){ |
| 110018 | 110040 | goto whereBeginError; |
| 110019 | 110041 | } |
| 110020 | 110042 | #ifdef WHERETRACE_ENABLED |
| 110021 | 110043 | if( sqlite3WhereTrace ){ |
| 110022 | 110044 | int ii; |
| | @@ -110062,11 +110084,10 @@ |
| 110062 | 110084 | /* Open all tables in the pTabList and any indices selected for |
| 110063 | 110085 | ** searching those tables. |
| 110064 | 110086 | */ |
| 110065 | 110087 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ |
| 110066 | 110088 | notReady = ~(Bitmask)0; |
| 110067 | | - pWInfo->nRowOut = (WhereCost)1; |
| 110068 | 110089 | for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){ |
| 110069 | 110090 | Table *pTab; /* Table to open */ |
| 110070 | 110091 | int iDb; /* Index of database containing table/index */ |
| 110071 | 110092 | struct SrcList_item *pTabItem; |
| 110072 | 110093 | WhereLoop *pLoop; |
| | @@ -110089,12 +110110,12 @@ |
| 110089 | 110110 | #endif |
| 110090 | 110111 | if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 |
| 110091 | 110112 | && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ |
| 110092 | 110113 | int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead; |
| 110093 | 110114 | sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); |
| 110094 | | - testcase( pTab->nCol==BMS-1 ); |
| 110095 | | - testcase( pTab->nCol==BMS ); |
| 110115 | + testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 ); |
| 110116 | + testcase( !pWInfo->okOnePass && pTab->nCol==BMS ); |
| 110096 | 110117 | if( !pWInfo->okOnePass && pTab->nCol<BMS ){ |
| 110097 | 110118 | Bitmask b = pTabItem->colUsed; |
| 110098 | 110119 | int n = 0; |
| 110099 | 110120 | for(; b; b=b>>1, n++){} |
| 110100 | 110121 | sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, |
| | @@ -110231,16 +110252,14 @@ |
| 110231 | 110252 | if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_TEMP_INDEX))==0 ){ |
| 110232 | 110253 | sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); |
| 110233 | 110254 | } |
| 110234 | 110255 | } |
| 110235 | 110256 | |
| 110236 | | - /* If this scan uses an index, make code substitutions to read data |
| 110237 | | - ** from the index in preference to the table. Sometimes, this means |
| 110238 | | - ** the table need never be read from. This is a performance boost, |
| 110239 | | - ** as the vdbe level waits until the table is read before actually |
| 110240 | | - ** seeking the table cursor to the record corresponding to the current |
| 110241 | | - ** position in the index. |
| 110257 | + /* If this scan uses an index, make VDBE code substitutions to read data |
| 110258 | + ** from the index instead of from the table where possible. In some cases |
| 110259 | + ** this optimization prevents the table from ever being read, which can |
| 110260 | + ** yield a significant performance boost. |
| 110242 | 110261 | ** |
| 110243 | 110262 | ** Calls to the code generator in between sqlite3WhereBegin and |
| 110244 | 110263 | ** sqlite3WhereEnd will have created code that references the table |
| 110245 | 110264 | ** directly. This loop scans all that code looking for opcodes |
| 110246 | 110265 | ** that reference the table and converts them into opcodes that |
| 110247 | 110266 | |