mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Merge the latest trunk changes into the threads branch.
FossilOrigin-Name: 39ac79cffe716f88af0871bdd206231b6a6511ff
This commit is contained in:
@@ -1624,12 +1624,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
|
||||
if( !zMaster
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|
||||
|| !isOpen(pPager->jfd)
|
||||
){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pPager->setMaster = 1;
|
||||
assert( isOpen(pPager->jfd) );
|
||||
assert( pPager->journalHdr <= pPager->journalOff );
|
||||
|
||||
/* Calculate the length in bytes and the checksum of zMaster */
|
||||
|
||||
231
src/where.c
231
src/where.c
@@ -3711,6 +3711,124 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the set of WHERE clause terms used by pA is a proper
|
||||
** subset of the WHERE clause terms used by pB.
|
||||
*/
|
||||
static int whereLoopProperSubset(const WhereLoop *pA, const WhereLoop *pB){
|
||||
int i, j;
|
||||
assert( pA->nLTerm<pB->nLTerm ); /* Checked by calling function */
|
||||
for(j=0, i=pA->nLTerm-1; i>=0 && j>=0; i--){
|
||||
for(j=pB->nLTerm-1; j>=0; j--){
|
||||
if( pB->aLTerm[j]==pA->aLTerm[i] ) break;
|
||||
}
|
||||
}
|
||||
return j>=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
|
||||
** that:
|
||||
**
|
||||
** (1) pTemplate costs less than any other WhereLoops that are a proper
|
||||
** subset of pTemplate
|
||||
**
|
||||
** (2) pTemplate costs more than any other WhereLoops for which pTemplate
|
||||
** is a proper subset.
|
||||
**
|
||||
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
|
||||
** WHERE clause terms than Y and that every WHERE clause term used by X is
|
||||
** also used by Y.
|
||||
*/
|
||||
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
|
||||
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
|
||||
for(; p; p=p->pNextLoop){
|
||||
if( p->iTab!=pTemplate->iTab ) continue;
|
||||
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
|
||||
if( p->nLTerm<pTemplate->nLTerm
|
||||
&& (p->rRun<pTemplate->rRun || (p->rRun==pTemplate->rRun &&
|
||||
p->nOut<=pTemplate->nOut))
|
||||
&& whereLoopProperSubset(p, pTemplate)
|
||||
){
|
||||
pTemplate->rRun = p->rRun;
|
||||
pTemplate->nOut = p->nOut - 1;
|
||||
}else
|
||||
if( p->nLTerm>pTemplate->nLTerm
|
||||
&& (p->rRun>pTemplate->rRun || (p->rRun==pTemplate->rRun &&
|
||||
p->nOut>=pTemplate->nOut))
|
||||
&& whereLoopProperSubset(pTemplate, p)
|
||||
){
|
||||
pTemplate->rRun = p->rRun;
|
||||
pTemplate->nOut = p->nOut + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Search the list of WhereLoops in *ppPrev looking for one that can be
|
||||
** supplanted by pTemplate.
|
||||
**
|
||||
** Return NULL if the WhereLoop list contains an entry that can supplant
|
||||
** pTemplate, in other words if pTemplate does not belong on the list.
|
||||
**
|
||||
** If pX is a WhereLoop that pTemplate can supplant, then return the
|
||||
** link that points to pX.
|
||||
**
|
||||
** If pTemplate cannot supplant any existing element of the list but needs
|
||||
** to be added to the list, then return a pointer to the tail of the list.
|
||||
*/
|
||||
static WhereLoop **whereLoopFindLesser(
|
||||
WhereLoop **ppPrev,
|
||||
const WhereLoop *pTemplate
|
||||
){
|
||||
WhereLoop *p;
|
||||
for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){
|
||||
if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
|
||||
/* If either the iTab or iSortIdx values for two WhereLoop are different
|
||||
** then those WhereLoops need to be considered separately. Neither is
|
||||
** a candidate to replace the other. */
|
||||
continue;
|
||||
}
|
||||
/* In the current implementation, the rSetup value is either zero
|
||||
** or the cost of building an automatic index (NlogN) and the NlogN
|
||||
** is the same for compatible WhereLoops. */
|
||||
assert( p->rSetup==0 || pTemplate->rSetup==0
|
||||
|| p->rSetup==pTemplate->rSetup );
|
||||
|
||||
/* whereLoopAddBtree() always generates and inserts the automatic index
|
||||
** case first. Hence compatible candidate WhereLoops never have a larger
|
||||
** rSetup. Call this SETUP-INVARIANT */
|
||||
assert( p->rSetup>=pTemplate->rSetup );
|
||||
|
||||
/* If existing WhereLoop p is better than pTemplate, pTemplate can be
|
||||
** discarded. WhereLoop p is better if:
|
||||
** (1) p has no more dependencies than pTemplate, and
|
||||
** (2) p has an equal or lower cost than pTemplate
|
||||
*/
|
||||
if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */
|
||||
&& p->rSetup<=pTemplate->rSetup /* (2a) */
|
||||
&& p->rRun<=pTemplate->rRun /* (2b) */
|
||||
&& p->nOut<=pTemplate->nOut /* (2c) */
|
||||
){
|
||||
return 0; /* Discard pTemplate */
|
||||
}
|
||||
|
||||
/* If pTemplate is always better than p, then cause p to be overwritten
|
||||
** with pTemplate. pTemplate is better than p if:
|
||||
** (1) pTemplate has no more dependences than p, and
|
||||
** (2) pTemplate has an equal or lower cost than p.
|
||||
*/
|
||||
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
|
||||
&& p->rRun>=pTemplate->rRun /* (2a) */
|
||||
&& p->nOut>=pTemplate->nOut /* (2b) */
|
||||
){
|
||||
assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
|
||||
break; /* Cause p to be overwritten by pTemplate */
|
||||
}
|
||||
}
|
||||
return ppPrev;
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert or replace a WhereLoop entry using the template supplied.
|
||||
**
|
||||
@@ -3720,25 +3838,23 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
** fewer dependencies than the template. Otherwise a new WhereLoop is
|
||||
** added based on the template.
|
||||
**
|
||||
** If pBuilder->pOrSet is not NULL then we only care about only the
|
||||
** If pBuilder->pOrSet is not NULL then we care about only the
|
||||
** prerequisites and rRun and nOut costs of the N best loops. That
|
||||
** information is gathered in the pBuilder->pOrSet object. This special
|
||||
** processing mode is used only for OR clause processing.
|
||||
**
|
||||
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
|
||||
** still might overwrite similar loops with the new template if the
|
||||
** template is better. Loops may be overwritten if the following
|
||||
** new template is better. Loops may be overwritten if the following
|
||||
** conditions are met:
|
||||
**
|
||||
** (1) They have the same iTab.
|
||||
** (2) They have the same iSortIdx.
|
||||
** (3) The template has same or fewer dependencies than the current loop
|
||||
** (4) The template has the same or lower cost than the current loop
|
||||
** (5) The template uses more terms of the same index but has no additional
|
||||
** dependencies
|
||||
*/
|
||||
static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
WhereLoop **ppPrev, *p, *pNext = 0;
|
||||
WhereLoop **ppPrev, *p;
|
||||
WhereInfo *pWInfo = pBuilder->pWInfo;
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
|
||||
@@ -3761,64 +3877,23 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Search for an existing WhereLoop to overwrite, or which takes
|
||||
** priority over pTemplate.
|
||||
/* Look for an existing WhereLoop to replace with pTemplate
|
||||
*/
|
||||
for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){
|
||||
if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
|
||||
/* If either the iTab or iSortIdx values for two WhereLoop are different
|
||||
** then those WhereLoops need to be considered separately. Neither is
|
||||
** a candidate to replace the other. */
|
||||
continue;
|
||||
}
|
||||
/* In the current implementation, the rSetup value is either zero
|
||||
** or the cost of building an automatic index (NlogN) and the NlogN
|
||||
** is the same for compatible WhereLoops. */
|
||||
assert( p->rSetup==0 || pTemplate->rSetup==0
|
||||
|| p->rSetup==pTemplate->rSetup );
|
||||
whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
|
||||
ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
|
||||
|
||||
/* whereLoopAddBtree() always generates and inserts the automatic index
|
||||
** case first. Hence compatible candidate WhereLoops never have a larger
|
||||
** rSetup. Call this SETUP-INVARIANT */
|
||||
assert( p->rSetup>=pTemplate->rSetup );
|
||||
|
||||
if( (p->prereq & pTemplate->prereq)==p->prereq
|
||||
&& p->rSetup<=pTemplate->rSetup
|
||||
&& p->rRun<=pTemplate->rRun
|
||||
&& p->nOut<=pTemplate->nOut
|
||||
){
|
||||
/* This branch taken when p is equal or better than pTemplate in
|
||||
** all of (1) dependencies (2) setup-cost, (3) run-cost, and
|
||||
** (4) number of output rows. */
|
||||
assert( p->rSetup==pTemplate->rSetup );
|
||||
if( p->prereq==pTemplate->prereq
|
||||
&& p->nLTerm<pTemplate->nLTerm
|
||||
&& (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0
|
||||
&& (p->u.btree.pIndex==pTemplate->u.btree.pIndex
|
||||
|| pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm)
|
||||
){
|
||||
/* Overwrite an existing WhereLoop with an similar one that uses
|
||||
** more terms of the index */
|
||||
pNext = p->pNextLoop;
|
||||
break;
|
||||
}else{
|
||||
/* pTemplate is not helpful.
|
||||
** Return without changing or adding anything */
|
||||
goto whereLoopInsert_noop;
|
||||
}
|
||||
}
|
||||
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
|
||||
&& p->rRun>=pTemplate->rRun
|
||||
&& p->nOut>=pTemplate->nOut
|
||||
){
|
||||
/* Overwrite an existing WhereLoop with a better one: one that is
|
||||
** better at one of (1) dependencies, (2) setup-cost, (3) run-cost
|
||||
** or (4) number of output rows, and is no worse in any of those
|
||||
** categories. */
|
||||
assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
|
||||
pNext = p->pNextLoop;
|
||||
break;
|
||||
if( ppPrev==0 ){
|
||||
/* There already exists a WhereLoop on the list that is better
|
||||
** than pTemplate, so just ignore pTemplate */
|
||||
#if WHERETRACE_ENABLED /* 0x8 */
|
||||
if( sqlite3WhereTrace & 0x8 ){
|
||||
sqlite3DebugPrintf("ins-noop: ");
|
||||
whereLoopPrint(pTemplate, pBuilder->pWC);
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
p = *ppPrev;
|
||||
}
|
||||
|
||||
/* If we reach this point it means that either p[] should be overwritten
|
||||
@@ -3836,13 +3911,33 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
}
|
||||
#endif
|
||||
if( p==0 ){
|
||||
p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
|
||||
/* Allocate a new WhereLoop to add to the end of the list */
|
||||
*ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
whereLoopInit(p);
|
||||
p->pNextLoop = 0;
|
||||
}else{
|
||||
/* We will be overwriting WhereLoop p[]. But before we do, first
|
||||
** go through the rest of the list and delete any other entries besides
|
||||
** p[] that are also supplated by pTemplate */
|
||||
WhereLoop **ppTail = &p->pNextLoop;
|
||||
WhereLoop *pToDel;
|
||||
while( *ppTail ){
|
||||
ppTail = whereLoopFindLesser(ppTail, pTemplate);
|
||||
if( NEVER(ppTail==0) ) break;
|
||||
pToDel = *ppTail;
|
||||
if( pToDel==0 ) break;
|
||||
*ppTail = pToDel->pNextLoop;
|
||||
#if WHERETRACE_ENABLED /* 0x8 */
|
||||
if( sqlite3WhereTrace & 0x8 ){
|
||||
sqlite3DebugPrintf("ins-del: ");
|
||||
whereLoopPrint(pToDel, pBuilder->pWC);
|
||||
}
|
||||
#endif
|
||||
whereLoopDelete(db, pToDel);
|
||||
}
|
||||
}
|
||||
whereLoopXfer(db, p, pTemplate);
|
||||
p->pNextLoop = pNext;
|
||||
*ppPrev = p;
|
||||
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
|
||||
Index *pIndex = p->u.btree.pIndex;
|
||||
if( pIndex && pIndex->tnum==0 ){
|
||||
@@ -3850,16 +3945,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
/* Jump here if the insert is a no-op */
|
||||
whereLoopInsert_noop:
|
||||
#if WHERETRACE_ENABLED /* 0x8 */
|
||||
if( sqlite3WhereTrace & 0x8 ){
|
||||
sqlite3DebugPrintf("ins-noop: ");
|
||||
whereLoopPrint(pTemplate, pBuilder->pWC);
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user