aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/attach.c2
-rw-r--r--src/btree.c28
-rw-r--r--src/build.c2
-rw-r--r--src/expr.c35
-rw-r--r--src/main.c2
-rw-r--r--src/memjournal.c158
-rw-r--r--src/os_win.c2
-rw-r--r--src/pager.c27
-rw-r--r--src/pragma.c29
-rw-r--r--src/select.c20
-rw-r--r--src/sqliteInt.h40
-rw-r--r--src/tclsqlite.c14
-rw-r--r--src/test1.c2
-rw-r--r--src/update.c2
-rw-r--r--src/util.c13
-rw-r--r--src/vdbe.c17
-rw-r--r--src/vdbeInt.h4
-rw-r--r--src/where.c123
-rw-r--r--src/wherecode.c10
19 files changed, 298 insertions, 232 deletions
diff --git a/src/attach.c b/src/attach.c
index 484a5a110..ea378a40a 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -161,7 +161,7 @@ static void attachFunc(
#endif
sqlite3BtreeLeave(aNew->pBt);
}
- aNew->safety_level = 3;
+ aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
aNew->zName = sqlite3DbStrDup(db, zName);
if( rc==SQLITE_OK && aNew->zName==0 ){
rc = SQLITE_NOMEM_BKPT;
diff --git a/src/btree.c b/src/btree.c
index 036e63a01..18e6be9f3 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -2864,9 +2864,25 @@ static int lockBtree(BtShared *pBt){
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
- }else if( isOpen==0 ){
- releasePage(pPage1);
- return SQLITE_OK;
+ }else{
+#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
+ sqlite3 *db;
+ Db *pDb;
+ if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
+ while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
+ if( pDb->bSyncSet==0
+ && pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
+ ){
+ pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
+ sqlite3PagerSetFlags(pBt->pPager,
+ pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
+ }
+ }
+#endif
+ if( isOpen==0 ){
+ releasePage(pPage1);
+ return SQLITE_OK;
+ }
}
rc = SQLITE_NOTADB;
}
@@ -7556,9 +7572,9 @@ static int balance_nonroot(
** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
- ** Note that this can never happen in an SQLite data file, as all
- ** cells are at least 4 bytes. It only happens in b-trees used
- ** to evaluate "IN (SELECT ...)" and similar clauses.
+ ** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
+ ** and WITHOUT ROWID tables with exactly one column which is the
+ ** primary key.
*/
if( b.szCell[j]==4 ){
assert(leafCorrection==4);
diff --git a/src/build.c b/src/build.c
index a32dfbd02..e89c74446 100644
--- a/src/build.c
+++ b/src/build.c
@@ -1135,7 +1135,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
char aff = SQLITE_AFF_NUMERIC;
const char *zChar = 0;
- if( zIn==0 ) return aff;
+ assert( zIn!=0 );
while( zIn[0] ){
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
zIn++;
diff --git a/src/expr.c b/src/expr.c
index 8a6973219..3672d02df 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1568,23 +1568,22 @@ int sqlite3IsRowid(const char *z){
}
/*
-** Return true if we are able to the IN operator optimization on a
-** query of the form
-**
-** x IN (SELECT ...)
-**
-** Where the SELECT... clause is as specified by the parameter to this
-** routine.
-**
-** The Select object passed in has already been preprocessed and no
-** errors have been found.
+** pX is the RHS of an IN operator. If pX is a SELECT statement
+** that can be simplified to a direct table access, then return
+** a pointer to the SELECT statement. If pX is not a SELECT statement,
+** or if the SELECT statement needs to be manifested into a transient
+** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
-static int isCandidateForInOpt(Select *p){
+static Select *isCandidateForInOpt(Expr *pX){
+ Select *p;
SrcList *pSrc;
ExprList *pEList;
+ Expr *pRes;
Table *pTab;
- if( p==0 ) return 0; /* right-hand side of IN is SELECT */
+ if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
+ if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
+ p = pX->x.pSelect;
if( p->pPrior ) return 0; /* Not a compound SELECT */
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
@@ -1600,13 +1599,15 @@ static int isCandidateForInOpt(Select *p){
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
pTab = pSrc->a[0].pTab;
- if( NEVER(pTab==0) ) return 0;
+ assert( pTab!=0 );
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
pEList = p->pEList;
if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
- if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
- return 1;
+ pRes = pEList->a[0].pExpr;
+ if( pRes->op!=TK_COLUMN ) return 0; /* Result is a column */
+ assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
+ return p;
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -1738,15 +1739,13 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
** satisfy the query. This is preferable to generating a new
** ephemeral table.
*/
- p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
- if( pParse->nErr==0 && isCandidateForInOpt(p) ){
+ if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
Expr *pExpr; /* Expression <column> */
i16 iCol; /* Index of column <column> */
i16 iDb; /* Database idx for pTab */
- assert( p ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
diff --git a/src/main.c b/src/main.c
index 422b970cc..40a192e16 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2899,7 +2899,7 @@ static int openDatabase(
** database it is OFF. This matches the pager layer defaults.
*/
db->aDb[0].zName = "main";
- db->aDb[0].safety_level = PAGER_SYNCHRONOUS_FULL;
+ db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
db->aDb[1].zName = "temp";
db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
diff --git a/src/memjournal.c b/src/memjournal.c
index 04780df99..b81682de8 100644
--- a/src/memjournal.c
+++ b/src/memjournal.c
@@ -69,7 +69,6 @@ struct MemJournal {
int flags; /* xOpen flags */
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
const char *zJournal; /* Name of the journal file */
- sqlite3_file *pReal; /* The "real" underlying file descriptor */
};
/*
@@ -83,41 +82,42 @@ static int memjrnlRead(
sqlite_int64 iOfst /* Begin reading at this offset */
){
MemJournal *p = (MemJournal *)pJfd;
- if( p->pReal ){
- return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
- }else if( (iAmt+iOfst)>p->endpoint.iOffset ){
+ u8 *zOut = zBuf;
+ int nRead = iAmt;
+ int iChunkOffset;
+ FileChunk *pChunk;
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
- }else{
- u8 *zOut = zBuf;
- int nRead = iAmt;
- int iChunkOffset;
- FileChunk *pChunk;
-
- if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
- sqlite3_int64 iOff = 0;
- for(pChunk=p->pFirst;
- ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
- pChunk=pChunk->pNext
- ){
- iOff += p->nChunkSize;
- }
- }else{
- pChunk = p->readpoint.pChunk;
- }
+ }
+#endif
- iChunkOffset = (int)(iOfst%p->nChunkSize);
- do {
- int iSpace = p->nChunkSize - iChunkOffset;
- int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
- memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
- zOut += nCopy;
- nRead -= iSpace;
- iChunkOffset = 0;
- } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
- p->readpoint.iOffset = iOfst+iAmt;
- p->readpoint.pChunk = pChunk;
+ assert( (iAmt+iOfst)<=p->endpoint.iOffset );
+ if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
+ sqlite3_int64 iOff = 0;
+ for(pChunk=p->pFirst;
+ ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
+ pChunk=pChunk->pNext
+ ){
+ iOff += p->nChunkSize;
+ }
+ }else{
+ pChunk = p->readpoint.pChunk;
}
+ iChunkOffset = (int)(iOfst%p->nChunkSize);
+ do {
+ int iSpace = p->nChunkSize - iChunkOffset;
+ int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
+ memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
+ zOut += nCopy;
+ nRead -= iSpace;
+ iChunkOffset = 0;
+ } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
+ p->readpoint.iOffset = iOfst+iAmt;
+ p->readpoint.pChunk = pChunk;
+
return SQLITE_OK;
}
@@ -138,37 +138,37 @@ static void memjrnlFreeChunks(MemJournal *p){
** Flush the contents of memory to a real file on disk.
*/
static int memjrnlCreateFile(MemJournal *p){
- int rc = SQLITE_OK;
- if( !p->pReal ){
- sqlite3_file *pReal = (sqlite3_file *)&p[1];
- rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
- if( rc==SQLITE_OK ){
- int nChunk = p->nChunkSize;
- i64 iOff = 0;
- FileChunk *pIter;
- p->pReal = pReal;
- for(pIter=p->pFirst; pIter && rc==SQLITE_OK; pIter=pIter->pNext){
- int nWrite = nChunk;
- if( pIter==p->endpoint.pChunk ){
- nWrite = p->endpoint.iOffset % p->nChunkSize;
- if( nWrite==0 ) nWrite = p->nChunkSize;
- }
- rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nWrite, iOff);
- iOff += nWrite;
- }
- if( rc!=SQLITE_OK ){
- /* If an error occurred while writing to the file, close it before
- ** returning. This way, SQLite uses the in-memory journal data to
- ** roll back changes made to the internal page-cache before this
- ** function was called. */
- sqlite3OsClose(pReal);
- p->pReal = 0;
- }else{
- /* No error has occurred. Free the in-memory buffers. */
- memjrnlFreeChunks(p);
+ int rc;
+ sqlite3_file *pReal = (sqlite3_file*)p;
+ MemJournal copy = *p;
+
+ memset(p, 0, sizeof(MemJournal));
+ rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
+ if( rc==SQLITE_OK ){
+ int nChunk = copy.nChunkSize;
+ i64 iOff = 0;
+ FileChunk *pIter;
+ for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
+ if( iOff + nChunk > copy.endpoint.iOffset ){
+ nChunk = copy.endpoint.iOffset - iOff;
}
+ rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
+ if( rc ) break;
+ iOff += nChunk;
+ }
+ if( rc==SQLITE_OK ){
+ /* No error has occurred. Free the in-memory buffers. */
+ memjrnlFreeChunks(&copy);
}
}
+ if( rc!=SQLITE_OK ){
+ /* If an error occurred while creating or writing to the file, restore
+ ** the original before returning. This way, SQLite uses the in-memory
+ ** journal data to roll back changes made to the internal page-cache
+ ** before this function was called. */
+ sqlite3OsClose(pReal);
+ *p = copy;
+ }
return rc;
}
@@ -186,16 +186,12 @@ static int memjrnlWrite(
int nWrite = iAmt;
u8 *zWrite = (u8 *)zBuf;
- /* If the file has already been created on disk. */
- if( p->pReal ){
- return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
- }
-
- /* If the file should be created now. */
- else if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
+ /* If the file should be created now, create it and write the new data
+ ** into the file on disk. */
+ if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
int rc = memjrnlCreateFile(p);
if( rc==SQLITE_OK ){
- rc = memjrnlWrite(pJfd, zBuf, iAmt, iOfst);
+ rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
}
return rc;
}
@@ -208,10 +204,15 @@ static int memjrnlWrite(
** atomic-write optimization. In this case the first 28 bytes of the
** journal file may be written as part of committing the transaction. */
assert( iOfst==p->endpoint.iOffset || iOfst==0 );
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
- }else{
+ }else
+#else
+ assert( iOfst>0 || p->pFirst==0 );
+#endif
+ {
while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
@@ -255,9 +256,7 @@ static int memjrnlWrite(
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
- if( p->pReal ){
- return sqlite3OsTruncate(p->pReal, size);
- }else if( size==0 ){
+ if( ALWAYS(size==0) ){
memjrnlFreeChunks(p);
p->nSize = 0;
p->endpoint.pChunk = 0;
@@ -274,7 +273,6 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
static int memjrnlClose(sqlite3_file *pJfd){
MemJournal *p = (MemJournal *)pJfd;
memjrnlFreeChunks(p);
- if( p->pReal ) sqlite3OsClose(p->pReal);
return SQLITE_OK;
}
@@ -285,10 +283,7 @@ static int memjrnlClose(sqlite3_file *pJfd){
** syncing an in-memory journal is a no-op.
*/
static int memjrnlSync(sqlite3_file *pJfd, int flags){
- MemJournal *p = (MemJournal *)pJfd;
- if( p->pReal ){
- return sqlite3OsSync(p->pReal, flags);
- }
+ UNUSED_PARAMETER2(pJfd, flags);
return SQLITE_OK;
}
@@ -297,9 +292,6 @@ static int memjrnlSync(sqlite3_file *pJfd, int flags){
*/
static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
MemJournal *p = (MemJournal *)pJfd;
- if( p->pReal ){
- return sqlite3OsFileSize(p->pReal, pSize);
- }
*pSize = (sqlite_int64) p->endpoint.iOffset;
return SQLITE_OK;
}
@@ -354,7 +346,7 @@ int sqlite3JournalOpen(
** it using the sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
** made on the journal file-handle. */
- memset(p, 0, sizeof(MemJournal) + (pVfs ? pVfs->szOsFile : 0));
+ memset(p, 0, sizeof(MemJournal));
if( nSpill==0 ){
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
}
@@ -403,7 +395,7 @@ int sqlite3JournalCreate(sqlite3_file *p){
** or false otherwise.
*/
int sqlite3JournalIsInMemory(sqlite3_file *p){
- return p->pMethods==&MemJournalMethods && ((MemJournal*)p)->pReal==0;
+ return p->pMethods==&MemJournalMethods;
}
/*
@@ -411,5 +403,5 @@ int sqlite3JournalIsInMemory(sqlite3_file *p){
** pVfs to create the underlying on-disk files.
*/
int sqlite3JournalSize(sqlite3_vfs *pVfs){
- return pVfs->szOsFile + sizeof(MemJournal);
+ return MAX(pVfs->szOsFile, sizeof(MemJournal));
}
diff --git a/src/os_win.c b/src/os_win.c
index af6b1c814..6ff50c554 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -3257,7 +3257,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
- case SQLITE_LAST_ERRNO: {
+ case SQLITE_FCNTL_LAST_ERRNO: {
*(int*)pArg = (int)pFile->lastErrno;
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
diff --git a/src/pager.c b/src/pager.c
index f045ce0ef..c18b3a32f 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -428,19 +428,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
*/
#define MAX_SECTOR_SIZE 0x10000
-/*
-** If the option SQLITE_EXTRA_DURABLE option is set at compile-time, then
-** SQLite will do extra fsync() operations when synchronous==FULL to help
-** ensure that transactions are durable across a power failure. Most
-** applications are happy as long as transactions are consistent across
-** a power failure, and are perfectly willing to lose the last transaction
-** in exchange for the extra performance of avoiding directory syncs.
-** And so the default SQLITE_EXTRA_DURABLE setting is off.
-*/
-#ifndef SQLITE_EXTRA_DURABLE
-# define SQLITE_EXTRA_DURABLE 0
-#endif
-
/*
** An instance of the following structure is allocated for each active
@@ -3460,7 +3447,7 @@ void sqlite3PagerShrink(Pager *pPager){
** 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.
@@ -3480,6 +3467,10 @@ void sqlite3PagerShrink(Pager *pPager){
** 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
@@ -3487,7 +3478,8 @@ void sqlite3PagerShrink(Pager *pPager){
** 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
@@ -4818,11 +4810,7 @@ act_like_temp_file:
assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
-#if SQLITE_EXTRA_DURABLE
- pPager->extraSync = 1;
-#else
pPager->extraSync = 0;
-#endif
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
@@ -7179,6 +7167,7 @@ int sqlite3PagerWalCallback(Pager *pPager){
*/
int sqlite3PagerWalSupported(Pager *pPager){
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
+ if( pPager->noLock ) return 0;
return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
}
diff --git a/src/pragma.c b/src/pragma.c
index 1d6291431..70c2950c8 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -993,6 +993,7 @@ void sqlite3Pragma(
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
if( iLevel==0 ) iLevel = 1;
pDb->safety_level = iLevel;
+ pDb->bSyncSet = 1;
setAllPagerFlags(db);
}
}
@@ -1438,6 +1439,7 @@ void sqlite3Pragma(
for(i=0; i<db->nDb; i++){
HashElem *x;
Hash *pTbls;
+ int *aRoot;
int cnt = 0;
if( OMIT_TEMPDB && i==1 ) continue;
@@ -1451,31 +1453,34 @@ void sqlite3Pragma(
/* Do an integrity check of the B-Tree
**
- ** Begin by filling registers 2, 3, ... with the root pages numbers
+ ** Begin by finding the root pages numbers
** for all tables and indices in the database.
*/
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
- for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
- if( HasRowid(pTab) ){
- sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
- VdbeComment((v, "%s", pTab->zName));
- cnt++;
- }
+ if( HasRowid(pTab) ) cnt++;
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ cnt++; }
+ }
+ aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
+ if( aRoot==0 ) break;
+ for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ Table *pTab = sqliteHashData(x);
+ Index *pIdx;
+ if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
- VdbeComment((v, "%s", pIdx->zName));
- cnt++;
+ aRoot[cnt++] = pIdx->tnum;
}
}
+ aRoot[cnt] = 0;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, cnt+8 );
+ pParse->nMem = MAX( pParse->nMem, 14 );
/* Do the b-tree integrity checks */
- sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
+ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
diff --git a/src/select.c b/src/select.c
index c9bc389b2..a62581efc 100644
--- a/src/select.c
+++ b/src/select.c
@@ -4970,10 +4970,24 @@ int sqlite3Select(
}
/* Generate code to implement the subquery
+ **
+ ** The subquery is implemented as a co-routine if all of these are true:
+ ** (1) The subquery is guaranteed to be the outer loop (so that it
+ ** does not need to be computed more than once)
+ ** (2) The ALL keyword after SELECT is omitted. (Applications are
+ ** allowed to say "SELECT ALL" instead of just "SELECT" to disable
+ ** the use of co-routines.)
+ ** (3) Co-routines are not disabled using sqlite3_test_control()
+ ** with SQLITE_TESTCTRL_OPTIMIZATIONS.
+ **
+ ** TODO: Are there other reasons beside (1) to use a co-routine
+ ** implementation?
*/
- if( pTabList->nSrc==1
- && (p->selFlags & SF_All)==0
- && OptimizationEnabled(db, SQLITE_SubqCoroutine)
+ if( i==0
+ && (pTabList->nSrc==1
+ || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
+ && (p->selFlags & SF_All)==0 /* (2) */
+ && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e1e37b61d..de357537e 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -452,6 +452,13 @@
#endif
/*
+** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
+*/
+#ifdef SQLITE_OMIT_EXPLAIN
+# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#endif
+
+/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits. This macro is used inside of various testcase()
** macros to verify that we have tested SQLite for large-file support.
@@ -1003,10 +1010,39 @@ typedef struct With With;
#include "vdbe.h"
#include "pager.h"
#include "pcache.h"
-
#include "os.h"
#include "mutex.h"
+/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default
+** synchronous setting to EXTRA. It is no longer supported.
+*/
+#ifdef SQLITE_EXTRA_DURABLE
+# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE
+# define SQLITE_DEFAULT_SYNCHRONOUS 3
+#endif
+
+/*
+** Default synchronous levels.
+**
+** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
+** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
+**
+** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS
+** OFF 1 0
+** NORMAL 2 1
+** FULL 3 2
+** EXTRA 4 3
+**
+** The "PRAGMA synchronous" statement also uses the zero-based numbers.
+** In other words, the zero-based numbers are used for all external interfaces
+** and the one-based values are used internally.
+*/
+#ifndef SQLITE_DEFAULT_SYNCHRONOUS
+# define SQLITE_DEFAULT_SYNCHRONOUS (PAGER_SYNCHRONOUS_FULL-1)
+#endif
+#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
+# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
+#endif
/*
** Each database file to be accessed by the system is an instance
@@ -1019,6 +1055,7 @@ struct Db {
char *zName; /* Name of this database */
Btree *pBt; /* The B*Tree structure for this database file */
u8 safety_level; /* How aggressive at syncing data to disk */
+ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */
Schema *pSchema; /* Pointer to database schema (possibly shared) */
};
@@ -2361,6 +2398,7 @@ struct IdList {
*/
#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.
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 164664a6e..96b5691f1 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -2659,7 +2659,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** Change the encryption key on the currently open database.
*/
case DB_REKEY: {
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
int nKey;
void *pKey;
#endif
@@ -2667,7 +2667,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_WrongNumArgs(interp, 2, objv, "KEY");
return TCL_ERROR;
}
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
rc = sqlite3_rekey(pDb->db, pKey, nKey);
if( rc ){
@@ -3101,7 +3101,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zVfs = 0;
int flags;
Tcl_DString translatedFilename;
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
void *pKey = 0;
int nKey = 0;
#endif
@@ -3130,7 +3130,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_OK;
}
if( strcmp(zArg,"-has-codec")==0 ){
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
Tcl_AppendResult(interp,"1",(char*)0);
#else
Tcl_AppendResult(interp,"0",(char*)0);
@@ -3141,7 +3141,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
for(i=3; i+1<objc; i+=2){
zArg = Tcl_GetString(objv[i]);
if( strcmp(zArg,"-key")==0 ){
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
#endif
}else if( strcmp(zArg, "-vfs")==0 ){
@@ -3199,7 +3199,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_WrongNumArgs(interp, 1, objv,
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
" ?-key CODECKEY?"
#endif
);
@@ -3225,7 +3225,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{
zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc));
}
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
if( p->db ){
sqlite3_key(p->db, pKey, nKey);
}
diff --git a/src/test1.c b/src/test1.c
index 744b400b2..8ad653ca6 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -651,7 +651,7 @@ static int test_key(
int argc, /* Number of arguments */
char **argv /* Text of each argument */
){
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
sqlite3 *db;
const char *zKey;
int nKey;
diff --git a/src/update.c b/src/update.c
index 1e6cb83b4..c147eaaad 100644
--- a/src/update.c
+++ b/src/update.c
@@ -268,7 +268,7 @@ void sqlite3Update(
** 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);
diff --git a/src/util.c b/src/util.c
index 6aead47fa..d6a6f6b95 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1424,9 +1424,14 @@ u64 sqlite3LogEstToInt(LogEst x){
x /= 10;
if( n>=5 ) n -= 2;
else if( n>=1 ) n -= 1;
- if( x>=3 ){
- return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3);
- }
- return (n+8)>>(3-x);
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
+ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
+ if( x>60 ) return (u64)LARGEST_INT64;
+#else
+ /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
+ ** possible to this routine is 310, resulting in a maximum x of 31 */
+ assert( x<=60 );
+#endif
+ return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
}
#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
diff --git a/src/vdbe.c b/src/vdbe.c
index 7a47ef8b8..2757a624e 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -5482,7 +5482,7 @@ case OP_DropTrigger: {
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
-/* Opcode: IntegrityCk P1 P2 P3 * P5
+/* Opcode: IntegrityCk P1 P2 P3 P4 P5
**
** Do an analysis of the currently open database. Store in
** register P1 the text of an error message describing any problems.
@@ -5493,9 +5493,8 @@ case OP_DropTrigger: {
** In other words, the analysis stops as soon as reg(P1) errors are
** seen. Reg(P1) is updated with the number of errors remaining.
**
-** The root page numbers of all tables in the database are integer
-** stored in reg(P1), reg(P1+1), reg(P1+2), .... There are P2 tables
-** total.
+** The root page numbers of all tables in the database are integers
+** stored in P4_INTARRAY argument.
**
** If P5 is not zero, the check is done on the auxiliary database
** file, not the main database file.
@@ -5505,30 +5504,24 @@ case OP_DropTrigger: {
case OP_IntegrityCk: {
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
- int j; /* Loop counter */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
assert( p->bIsReader );
nRoot = pOp->p2;
+ aRoot = pOp->p4.ai;
assert( nRoot>0 );
- aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(nRoot+1) );
- if( aRoot==0 ) goto no_mem;
+ assert( aRoot[nRoot]==0 );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pnErr = &aMem[pOp->p3];
assert( (pnErr->flags & MEM_Int)!=0 );
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
- for(j=0; j<nRoot; j++){
- aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
- }
- aRoot[j] = 0;
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
(int)pnErr->u.i, &nErr);
- sqlite3DbFree(db, aRoot);
pnErr->u.i -= nErr;
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 448163302..1218009d0 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -381,16 +381,16 @@ struct Vdbe {
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
+ bft expired:1; /* True if the VM needs to be recompiled */
+ bft doingRerun:1; /* True if rerunning after an auto-reprepare */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
bft explain:2; /* True if EXPLAIN present on SQL command */
bft changeCntOn:1; /* True to update the change-counter */
- bft expired:1; /* True if the VM needs to be recompiled */
bft runOnlyOnce:1; /* Automatically expire on reset */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
bft isPrepareV2:1; /* True if prepared with prepare_v2() */
- bft doingRerun:1; /* True if rerunning after an auto-reprepare */
int nChange; /* Number of db changes made since last reset */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
diff --git a/src/where.c b/src/where.c
index ea62617c5..83d72ee39 100644
--- a/src/where.c
+++ b/src/where.c
@@ -934,7 +934,6 @@ static sqlite3_index_info *allocateIndexInfo(
*/
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);
@@ -953,12 +952,16 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
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; i<p->nConstraint; 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;
}
@@ -1976,6 +1979,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
WhereLoop **ppPrev, *p;
WhereInfo *pWInfo = pBuilder->pWInfo;
sqlite3 *db = pWInfo->pParse->db;
+ int rc;
/* If pBuilder->pOrSet is defined, then only keep track of the costs
** and prereqs.
@@ -2058,14 +2062,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
whereLoopDelete(db, pToDel);
}
}
- whereLoopXfer(db, p, pTemplate);
+ rc = whereLoopXfer(db, p, pTemplate);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
Index *pIndex = p->u.btree.pIndex;
if( pIndex && pIndex->tnum==0 ){
p->u.btree.pIndex = 0;
}
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -2554,7 +2558,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
*/
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 */
@@ -2654,7 +2658,7 @@ static int whereLoopAddBtree(
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);
}
}
@@ -2675,7 +2679,7 @@ static int whereLoopAddBtree(
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);
@@ -2762,7 +2766,7 @@ static int whereLoopAddBtree(
** * 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.
**
@@ -2771,9 +2775,9 @@ static int whereLoopAddBtree(
*/
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 */
){
@@ -2788,9 +2792,9 @@ static int whereLoopAddVirtualOne(
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. */
@@ -2807,10 +2811,9 @@ static int whereLoopAddVirtualOne(
/* Initialize the output fields of the sqlite3_index_info structure */
memset(pUsage, 0, sizeof(pUsage[0])*nConstraint);
- if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
+ assert( pIdxInfo->needToFreeIdxStr==0 );
pIdxInfo->idxStr = 0;
pIdxInfo->idxNum = 0;
- pIdxInfo->needToFreeIdxStr = 0;
pIdxInfo->orderByConsumed = 0;
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
pIdxInfo->estimatedRows = 25;
@@ -2835,9 +2838,10 @@ static int whereLoopAddVirtualOne(
|| 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 );
@@ -2859,7 +2863,7 @@ static int whereLoopAddVirtualOne(
** together. */
pIdxInfo->orderByConsumed = 0;
pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
- *pbIn = 1;
+ *pbIn = 1; assert( (mExclude & WO_IN)==0 );
}
}
}
@@ -2883,13 +2887,16 @@ static int whereLoopAddVirtualOne(
}else{
pNew->wsFlags &= ~WHERE_ONEROW;
}
- whereLoopInsert(pBuilder, pNew);
+ rc = whereLoopInsert(pBuilder, pNew);
if( pNew->u.vtab.needFree ){
sqlite3_free(pNew->u.vtab.idxStr);
pNew->u.vtab.needFree = 0;
}
+ WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
+ *pbIn, (sqlite3_uint64)mPrereq,
+ (sqlite3_uint64)(pNew->prereq & ~mPrereq)));
- return SQLITE_OK;
+ return rc;
}
@@ -2897,8 +2904,8 @@ static int whereLoopAddVirtualOne(
** 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
@@ -2909,18 +2916,18 @@ static int whereLoopAddVirtualOne(
**
** ... 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 */
@@ -2934,14 +2941,14 @@ static int whereLoopAddVirtual(
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;
@@ -2954,15 +2961,15 @@ static int whereLoopAddVirtual(
}
/* First call xBestIndex() with all constraints usable. */
- rc = whereLoopAddVirtualOne(pBuilder, mExtra, (Bitmask)(-1), 0, p, &bIn);
- mBest = pNew->prereq & ~mExtra;
+ WHERETRACE(0x40, (" VirtualOne: all usable\n"));
+ rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, &bIn);
/* 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.
- */
- if( mBest ){
+ ** that does not require any source tables (IOW: a plan with mBest==0),
+ ** then there is no point in making any further calls to xBestIndex()
+ ** since they will all return the same result (if the xBestIndex()
+ ** implementation is sane). */
+ if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
int seenZero = 0; /* True if a plan with no prereqs seen */
int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */
Bitmask mPrev = 0;
@@ -2970,32 +2977,36 @@ static int whereLoopAddVirtual(
/* 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;
+ if( bIn ){
+ WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
+ 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; i<nConstraint; i++){
Bitmask mThis = (
- pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mExtra
+ pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq
);
if( mThis>mPrev && mThis<mNext ) mNext = mThis;
}
mPrev = mNext;
- if( mNext==(Bitmask)(-1) ) break;
+ if( mNext==ALLBITS ) break;
if( mNext==mBest || mNext==mBestNoIn ) continue;
- rc = whereLoopAddVirtualOne(pBuilder, mExtra, mNext|mExtra, 0, p, &bIn);
- if( pNew->prereq==mExtra ){
+ WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
+ (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
+ rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mNext|mPrereq, 0, p, &bIn);
+ if( pNew->prereq==mPrereq ){
seenZero = 1;
if( bIn==0 ) seenZeroNoIN = 1;
}
@@ -3005,7 +3016,8 @@ static int whereLoopAddVirtual(
** 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);
+ WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
+ rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, 0, p, &bIn);
if( bIn==0 ) seenZeroNoIN = 1;
}
@@ -3013,7 +3025,8 @@ static int whereLoopAddVirtual(
** 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);
+ WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
+ rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, WO_IN, p, &bIn);
}
}
@@ -3029,7 +3042,7 @@ static int whereLoopAddVirtual(
*/
static int whereLoopAddOr(
WhereLoopBuilder *pBuilder,
- Bitmask mExtra,
+ Bitmask mPrereq,
Bitmask mUnusable
){
WhereInfo *pWInfo = pBuilder->pWInfo;
@@ -3090,14 +3103,14 @@ static int whereLoopAddOr(
#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 ){
@@ -3154,7 +3167,7 @@ static int whereLoopAddOr(
*/
static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
WhereInfo *pWInfo = pBuilder->pWInfo;
- Bitmask mExtra = 0;
+ Bitmask mPrereq = 0;
Bitmask mPrior = 0;
int iTab;
SrcList *pTabList = pWInfo->pTabList;
@@ -3175,7 +3188,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
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) ){
@@ -3185,12 +3198,12 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
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;
@@ -4280,7 +4293,7 @@ WhereInfo *sqlite3WhereBegin(
}
}
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
- pWInfo->revMask = (Bitmask)(-1);
+ pWInfo->revMask = ALLBITS;
}
if( pParse->nErr || NEVER(db->mallocFailed) ){
goto whereBeginError;
diff --git a/src/wherecode.c b/src/wherecode.c
index bfc52fb47..3705aab51 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -882,7 +882,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
for(j=0; j<nConstraint; j++){
int iTarget = iReg+j+2;
pTerm = pLoop->aLTerm[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;
@@ -915,7 +915,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** 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 );
@@ -932,8 +932,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( pCompare ){
pCompare->pLeft = pTerm->pExpr->pLeft;
pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
- if( pRight ) pRight->iTable = iReg+j+2;
- sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
+ if( pRight ){
+ pRight->iTable = iReg+j+2;
+ sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
+ }
pCompare->pLeft = 0;
sqlite3ExprDelete(db, pCompare);
}