Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -3466,11 +3466,11 @@ ** Adjust settings of the pager to those specified in the pgFlags parameter. ** ** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness ** of the database to damage due to OS crashes or power failures by ** changing the number of syncs()s when writing the journals. -** There are three levels: +** There are four levels: ** ** OFF sqlite3OsSync() is never called. This is the default ** for temporary and transient files. ** ** NORMAL The journal is synced once before writes begin on the @@ -3485,19 +3485,24 @@ ** of the journal header - being written in between the two ** syncs). If we assume that writing a ** single disk sector is atomic, then this mode provides ** assurance that the journal will not be corrupted to the ** point of causing damage to the database during rollback. +** +** EXTRA This is like FULL except that is also syncs the directory +** that contains the rollback journal after the rollback +** journal is unlinked. ** ** The above is for a rollback-journal mode. For WAL mode, OFF continues ** to mean that no syncs ever occur. NORMAL means that the WAL is synced ** prior to the start of checkpoint and that the database file is synced ** at the conclusion of the checkpoint if the entire content of the WAL ** was written back into the database. But no sync operations occur for ** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL ** file is synced following each commit operation, in addition to the -** syncs associated with NORMAL. +** syncs associated with NORMAL. There is no difference between FULL +** and EXTRA for WAL mode. ** ** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The ** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync ** using fcntl(F_FULLFSYNC). SQLITE_SYNC_NORMAL means to do an ** ordinary fsync() call. There is no difference between SQLITE_SYNC_FULL Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -2361,10 +2361,11 @@ /* ** A bit in a Bitmask */ #define MASKBIT(n) (((Bitmask)1)<<(n)) #define MASKBIT32(n) (((unsigned int)1)<<(n)) +#define ALLBITS ((Bitmask)-1) /* ** The following structure describes the FROM clause of a SELECT statement. ** Each table or subquery in the FROM clause is a separate element of ** the SrcList.a[] array. Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -266,11 +266,11 @@ /* The SET expressions are not actually used inside the WHERE loop. ** So reset the colUsed mask. Unless this is a virtual table. In that ** case, set all bits of the colUsed mask (to ensure that the virtual ** table implementation makes all columns available). */ - pTabList->a[0].colUsed = IsVirtual(pTab) ? (Bitmask)-1 : 0; + pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0; hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -932,11 +932,10 @@ ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates ** that this is required. */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; - int i; int rc; TRACE_IDX_INPUTS(p); rc = pVtab->pModule->xBestIndex(pVtab, p); TRACE_IDX_OUTPUTS(p); @@ -951,16 +950,20 @@ } } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; +#if 0 + /* This error is now caught by the caller. + ** Search for "xBestIndex malfunction" below */ for(i=0; inConstraint; i++){ if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){ sqlite3ErrorMsg(pParse, "table %s: xBestIndex returned an invalid plan", pTab->zName); } } +#endif return pParse->nErr; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ @@ -2552,11 +2555,11 @@ ** performance of using an index is far better than the worst-case performance ** of a full table scan. */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - Bitmask mExtra /* Extra prerequesites for using this table */ + Bitmask mPrereq /* Extra prerequesites for using this table */ ){ WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ Index sPk; /* A fake index object for the primary key */ LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ @@ -2652,11 +2655,11 @@ ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_AUTO_INDEX; - pNew->prereq = mExtra | pTerm->prereqRight; + pNew->prereq = mPrereq | pTerm->prereqRight; rc = whereLoopInsert(pBuilder, pNew); } } } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ @@ -2673,11 +2676,11 @@ pNew->u.btree.nEq = 0; pNew->nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; pNew->rSetup = 0; - pNew->prereq = mExtra; + pNew->prereq = mPrereq; pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 ); @@ -2760,22 +2763,22 @@ ** * Argument mUsable indicates that its prerequisites are available, and ** ** * It is not one of the operators specified in the mExclude mask passed ** as the fourth argument (which in practice is either WO_IN or 0). ** -** Argument mExtra is a mask of tables that must be scanned before the +** Argument mPrereq is a mask of tables that must be scanned before the ** virtual table in question. These are added to the plans prerequisites ** before it is added to pBuilder. ** ** Output parameter *pbIn is set to true if the plan added to pBuilder ** uses one or more WO_IN terms, or false otherwise. */ static int whereLoopAddVirtualOne( WhereLoopBuilder *pBuilder, - Bitmask mExtra, /* Mask of tables that must be used. */ - Bitmask mUsable, /* Mask of usable prereqs */ - u16 mExclude, /* Exclude terms for this operator */ + Bitmask mPrereq, /* Mask of tables that must be used. */ + Bitmask mUsable, /* Mask of usable tables */ + u16 mExclude, /* Exclude terms using these operators */ sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ int *pbIn /* OUT: True if plan uses an IN(...) op */ ){ WhereClause *pWC = pBuilder->pWC; struct sqlite3_index_constraint *pIdxCons; @@ -2786,13 +2789,13 @@ WhereLoop *pNew = pBuilder->pNew; Parse *pParse = pBuilder->pWInfo->pParse; struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab]; int nConstraint = pIdxInfo->nConstraint; - assert( (mUsable & mExtra)==mExtra ); + assert( (mUsable & mPrereq)==mPrereq ); *pbIn = 0; - pNew->prereq = mExtra; + pNew->prereq = mPrereq; /* Set the usable flag on the subset of constraints identified by ** arguments mUsable and mExclude. */ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; iiTermOffset; if( iTerm>=nConstraint || j<0 || j>=pWC->nTerm || pNew->aLTerm[iTerm]!=0 + || pIdxCons->usable==0 ){ rc = SQLITE_ERROR; - sqlite3ErrorMsg(pParse,"%s.xBestIndex() malfunction",pSrc->pTab->zName); + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); return rc; } testcase( iTerm==nConstraint-1 ); testcase( j==0 ); testcase( j==pWC->nTerm-1 ); @@ -2857,11 +2861,11 @@ ** is not necessarily related to the order of output terms and ** (2) Multiple outputs from a single IN value will not merge ** together. */ pIdxInfo->orderByConsumed = 0; pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; - *pbIn = 1; + *pbIn = 1; assert( (mExclude & WO_IN)==0 ); } } } pNew->nLTerm = mxTerm+1; @@ -2895,12 +2899,12 @@ /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. ** -** If there are no LEFT or CROSS JOIN joins in the query, both mExtra and -** mUnusable are set to 0. Otherwise, mExtra is a mask of all FROM clause +** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and +** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause ** entries that occur before the virtual table in the FROM clause and are ** separated from it by at least one LEFT or CROSS JOIN. Similarly, the ** mUnusable mask contains all FROM clause entries that occur after the ** virtual table and are separated from it by at least one LEFT or ** CROSS JOIN. @@ -2907,22 +2911,22 @@ ** ** For example, if the query were: ** ** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6; ** -** then mExtra corresponds to (t1, t2) and mUnusable to (t5, t6). +** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6). ** -** All the tables in mExtra must be scanned before the current virtual +** All the tables in mPrereq must be scanned before the current virtual ** table. So any terms for which all prerequisites are satisfied by -** mExtra may be specified as "usable" in all calls to xBestIndex. +** mPrereq may be specified as "usable" in all calls to xBestIndex. ** Conversely, all tables in mUnusable must be scanned after the current ** virtual table, so any terms for which the prerequisites overlap with ** mUnusable should always be configured as "not-usable" for xBestIndex. */ static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - Bitmask mExtra, /* Tables that must be scanned before this one */ + Bitmask mPrereq, /* Tables that must be scanned before this one */ Bitmask mUnusable /* Tables that must be scanned after this one */ ){ int rc = SQLITE_OK; /* Return code */ WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ @@ -2932,18 +2936,18 @@ int nConstraint; /* Number of constraints in p */ int bIn; /* True if plan uses IN(...) operator */ WhereLoop *pNew; Bitmask mBest; /* Tables used by best possible plan */ - assert( (mExtra & mUnusable)==0 ); + assert( (mPrereq & mUnusable)==0 ); pWInfo = pBuilder->pWInfo; pParse = pWInfo->pParse; pWC = pBuilder->pWC; pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; assert( IsVirtual(pSrc->pTab) ); - p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc,pBuilder->pOrderBy); + p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; pNew->nLTerm = 0; pNew->u.vtab.needFree = 0; @@ -2952,12 +2956,12 @@ sqlite3DbFree(pParse->db, p); return SQLITE_NOMEM_BKPT; } /* First call xBestIndex() with all constraints usable. */ - rc = whereLoopAddVirtualOne(pBuilder, mExtra, (Bitmask)(-1), 0, p, &bIn); - mBest = pNew->prereq & ~mExtra; + rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, &bIn); + mBest = pNew->prereq & ~mPrereq; /* If the call to xBestIndex() with all terms enabled produced a plan ** that does not require any source tables, there is no point in making ** any further calls - if the xBestIndex() method is sane they will all ** return the same plan anyway. @@ -2969,53 +2973,54 @@ Bitmask mBestNoIn = 0; /* If the plan produced by the earlier call uses an IN(...) term, call ** xBestIndex again, this time with IN(...) terms disabled. */ if( rc==SQLITE_OK && bIn ){ - rc = whereLoopAddVirtualOne(pBuilder, mExtra, (Bitmask)-1, WO_IN, p,&bIn); - mBestNoIn = pNew->prereq & ~mExtra; + rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, WO_IN, p, &bIn); + assert( bIn==0 ); + mBestNoIn = pNew->prereq & ~mPrereq; if( mBestNoIn==0 ){ seenZero = 1; - if( bIn==0 ) seenZeroNoIN = 1; + seenZeroNoIN = 1; } } - /* Call xBestIndex once for each distinct value of (prereqRight & ~mExtra) + /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) ** in the set of terms that apply to the current virtual table. */ while( rc==SQLITE_OK ){ int i; - Bitmask mNext = (Bitmask)(-1); + Bitmask mNext = ALLBITS; assert( mNext>0 ); for(i=0; ia[p->aConstraint[i].iTermOffset].prereqRight & ~mExtra + pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq ); if( mThis>mPrev && mThisprereq==mExtra ){ + rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mNext|mPrereq, 0, p, &bIn); + if( pNew->prereq==mPrereq ){ seenZero = 1; if( bIn==0 ) seenZeroNoIN = 1; } } /* If the calls to xBestIndex() in the above loop did not find a plan ** that requires no source tables at all (i.e. one guaranteed to be ** usable), make a call here with all source tables disabled */ if( rc==SQLITE_OK && seenZero==0 ){ - rc = whereLoopAddVirtualOne(pBuilder, mExtra, mExtra, 0, p, &bIn); + rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, 0, p, &bIn); if( bIn==0 ) seenZeroNoIN = 1; } /* If the calls to xBestIndex() have so far failed to find a plan ** that requires no source tables at all and does not use an IN(...) ** operator, make a final call to obtain one here. */ if( rc==SQLITE_OK && seenZeroNoIN==0 ){ - rc = whereLoopAddVirtualOne(pBuilder, mExtra, mExtra, WO_IN, p, &bIn); + rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, WO_IN, p, &bIn); } } if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); sqlite3DbFree(pParse->db, p); @@ -3027,11 +3032,11 @@ ** Add WhereLoop entries to handle OR terms. This works for either ** btrees or virtual tables. */ static int whereLoopAddOr( WhereLoopBuilder *pBuilder, - Bitmask mExtra, + Bitmask mPrereq, Bitmask mUnusable ){ WhereInfo *pWInfo = pBuilder->pWInfo; WhereClause *pWC; WhereLoop *pNew; @@ -3088,18 +3093,18 @@ } } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ - rc = whereLoopAddVirtual(&sSubBuild, mExtra, mUnusable); + rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif { - rc = whereLoopAddBtree(&sSubBuild, mExtra); + rc = whereLoopAddBtree(&sSubBuild, mPrereq); } if( rc==SQLITE_OK ){ - rc = whereLoopAddOr(&sSubBuild, mExtra, mUnusable); + rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } assert( rc==SQLITE_OK || sCur.n==0 ); if( sCur.n==0 ){ sSum.n = 0; break; @@ -3152,11 +3157,11 @@ /* ** Add all WhereLoop objects for all tables */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo = pBuilder->pWInfo; - Bitmask mExtra = 0; + Bitmask mPrereq = 0; Bitmask mPrior = 0; int iTab; SrcList *pTabList = pWInfo->pTabList; struct SrcList_item *pItem; struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel]; @@ -3173,26 +3178,26 @@ pNew->iTab = iTab; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ - mExtra = mPrior; + mPrereq = mPrior; } priorJointype = pItem->fg.jointype; if( IsVirtual(pItem->pTab) ){ struct SrcList_item *p; for(p=&pItem[1]; pfg.jointype & (JT_LEFT|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } - rc = whereLoopAddVirtual(pBuilder, mExtra, mUnusable); + rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); }else{ - rc = whereLoopAddBtree(pBuilder, mExtra); + rc = whereLoopAddBtree(pBuilder, mPrereq); } if( rc==SQLITE_OK ){ - rc = whereLoopAddOr(pBuilder, mExtra, mUnusable); + rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; } @@ -4278,11 +4283,11 @@ wherePathSolver(pWInfo, pWInfo->nRowOut+1); if( db->mallocFailed ) goto whereBeginError; } } if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ - pWInfo->revMask = (Bitmask)(-1); + pWInfo->revMask = ALLBITS; } if( pParse->nErr || NEVER(db->mallocFailed) ){ goto whereBeginError; } #ifdef WHERETRACE_ENABLED Index: src/wherecode.c ================================================================== --- src/wherecode.c +++ src/wherecode.c @@ -880,11 +880,11 @@ iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; jaLTerm[j]; - if( pTerm==0 ) continue; + if( NEVER(pTerm==0) ) continue; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); addrNotFound = pLevel->addrNxt; }else{ sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); @@ -913,11 +913,11 @@ /* Reload the constraint value into reg[iReg+j+2]. The same value ** was loaded into the same register prior to the OP_VFilter, but ** the xFilter implementation might have changed the datatype or ** encoding of the value in the register, so it *must* be reloaded. */ assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed ); - if( pLevel->u.in.aInLoop!=0 ){ + if( !db->mallocFailed ){ assert( iIn>0 ); pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop); assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid ); assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 ); assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 ); Index: test/vtab6.test ================================================================== --- test/vtab6.test +++ test/vtab6.test @@ -564,15 +564,15 @@ do_test vtab6-11.4.1 { catchsql { SELECT a, b, c FROM ab NATURAL JOIN bc; } -} {1 {table ab: xBestIndex returned an invalid plan}} +} {1 {ab.xBestIndex malfunction}} do_test vtab6-11.4.2 { catchsql { SELECT a, b, c FROM bc NATURAL JOIN ab; } -} {1 {table bc: xBestIndex returned an invalid plan}} +} {1 {bc.xBestIndex malfunction}} unset ::echo_module_ignore_usable finish_test