From f1b5f5b855d767170826f2cbb79b802df676f09c Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 2 May 2013 00:15:01 +0000 Subject: [PATCH 001/144] Begin inserting some experimental code for the next generation query planner. FossilOrigin-Name: ccaf4c3f7e1ec45e058d594d9b5c26818a37722a --- manifest | 17 +-- manifest.uuid | 2 +- src/sqliteInt.h | 1 + src/where.c | 273 +++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 249 insertions(+), 44 deletions(-) diff --git a/manifest b/manifest index a5bd0b436b..75d4e526f5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\suse\sa\stransitive\sconstraint\sto\san\sIN\soperator\swhere\sthe\sRHS\sis\sa\nconstant\sif\sthere\sexists\sa\sdirect\s==\soperator\sto\sanother\stable\sin\san\souter\nloop. -D 2013-05-01T17:58:35.871 +C Begin\sinserting\ssome\sexperimental\scode\sfor\sthe\snext\sgeneration\squery\splanner. +D 2013-05-02T00:15:01.231 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -194,7 +194,7 @@ F src/shell.c 5d527e5d08f05ec2c43ff194ea44bf62b974f4c9 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h de835c584032769461c123a564381f9808542c0e +F src/sqliteInt.h 0d76a0aa7c64536c6f55d11a8f9f40df0636af6a F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 12d4200eb6ae991cad02367c391db076ac1af1b0 +F src/where.c fc62bea654f27d5787bc428cd8f3f176d764f785 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 329478cbed06f93652de50abdb31a6b41af02b9e -R cc457983507eee39e1b071292dee5b26 +P faedaeace9c7ed9a8aaf96700caee09db0c0c061 +R 84f8c9b09f28282800936ed72686b19f +T *branch * nextgen-query-plan-exp +T *sym-nextgen-query-plan-exp * +T -sym-trunk * U drh -Z 944723cfd5dfa8d16765eaab2fd82886 +Z 18faca4b1f68b4b3514e189f395d77ff diff --git a/manifest.uuid b/manifest.uuid index f88e8ae7a8..016ae611b1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -faedaeace9c7ed9a8aaf96700caee09db0c0c061 \ No newline at end of file +ccaf4c3f7e1ec45e058d594d9b5c26818a37722a \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b041b3fb6e..7a405b2fb1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2065,6 +2065,7 @@ struct WhereInfo { int iBreak; /* Jump here to break out of the loop */ int nLevel; /* Number of nested loop */ struct WhereClause *pWC; /* Decomposition of the WHERE clause */ + struct WhereLoop *pLoops; /* List of all WhereLoop objects */ double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ double nRowOut; /* Estimated number of output rows */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ diff --git a/src/where.c b/src/where.c index 2de894c3e7..f44ab496c0 100644 --- a/src/where.c +++ b/src/where.c @@ -39,6 +39,43 @@ typedef struct WhereMaskSet WhereMaskSet; typedef struct WhereOrInfo WhereOrInfo; typedef struct WhereAndInfo WhereAndInfo; typedef struct WhereCost WhereCost; +typedef struct WhereLoop WhereLoop; +typedef struct WherePath WherePath; +typedef struct WhereTerm WhereTerm; + +/* +** Each instance of this object represents a way of evaluating one +** term of a join. The WhereClause object holds a table of these +** objects using (iTab,prereq,iOb,nOb) as the primary key. Note that the +** same join term might have multiple associated WhereLoop objects. +*/ +struct WhereLoop { + Bitmask prereq; /* Bitmask of other loops that must run first */ + int iTab; /* Index of the table coded by this loop */ + u16 iOb, nOb; /* ORDER BY terms satisfied by this strategy */ + double rSetup; /* One-time setup cost (ex: create transient index) */ + double rRun; /* Cost of running each loop */ + double nOut; /* Estimated number of output rows */ + u32 wsFlags; /* WHERE_* flags describing the plan */ + u16 nEq; /* Number of equality constraints */ + u16 nTerm; /* Number of entries in aTerm[] */ + Index *pIndex; /* Index used */ + WhereTerm *aTerm; /* WhereTerms used */ + WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ +}; + +/* +** Each instance of this object holds a sequence of WhereLoop objects +** that implement some or all of the entire query plan. +*/ +struct WherePath { + Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ + double nRow; /* Estimated number of rows generated by this path */ + double rCost; /* Total cost of this path */ + WhereLoop *aLoop[1]; /* Array of WhereLoop objects implementing this path */ + WherePath *pNextPath; /* Next path in order of increasing cost */ + WherePath *pPrevPath; /* Previous path in cost order */ +}; /* ** The query generator uses an array of instances of this structure to @@ -91,7 +128,6 @@ typedef struct WhereCost WhereCost; ** in prereqRight and prereqAll. The default is 64 bits, hence SQLite ** is only able to process joins with 64 or fewer tables. */ -typedef struct WhereTerm WhereTerm; struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression that is this term */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ @@ -1793,9 +1829,9 @@ static void bestOrClauseIndex(WhereBestIdx *p){ sBOI.pDistinct = 0; sBOI.ppIdxInfo = 0; for(pOrTerm=pOrWC->a; pOrTerma), (pTerm - pWC->a) - )); + ));*/ if( (pOrTerm->eOperator& WO_AND)!=0 ){ sBOI.pWC = &pOrTerm->u.pAndInfo->wc; bestIndex(&sBOI); @@ -1822,15 +1858,15 @@ static void bestOrClauseIndex(WhereBestIdx *p){ /* If there is an ORDER BY clause, increase the scan cost to account ** for the cost of the sort. */ if( p->pOrderBy!=0 ){ - WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n", - rTotal, rTotal+nRow*estLog(nRow))); + /*WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n", + rTotal, rTotal+nRow*estLog(nRow)));*/ rTotal += nRow*estLog(nRow); } /* If the cost of scanning using this OR term for optimization is ** less than the current cost stored in pCost, replace the contents ** of pCost. */ - WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow)); + /*WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));*/ if( rTotalcost.rCost ){ p->cost.rCost = rTotal; p->cost.used = used; @@ -1927,8 +1963,8 @@ static void bestAutomaticIndex(WhereBestIdx *p){ pWCEnd = &pWC->a[pWC->nTerm]; for(pTerm=pWC->a; pTermnotReady) ){ - WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n", - p->cost.rCost, costTempIdx)); + /*WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n", + p->cost.rCost, costTempIdx));*/ p->cost.rCost = costTempIdx; p->cost.plan.nRow = logN + 1; p->cost.plan.wsFlags = WHERE_TEMP_INDEX; @@ -2113,7 +2149,7 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){ int nOrderBy; sqlite3_index_info *pIdxInfo; - WHERETRACE(("Recomputing index info for %s...\n", pSrc->pTab->zName)); + /*WHERETRACE(("Recomputing index info for %s...\n", pSrc->pTab->zName));*/ /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ @@ -2222,7 +2258,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ int i; int rc; - WHERETRACE(("xBestIndex for %s\n", pTab->zName)); + /*WHERETRACE(("xBestIndex for %s\n", pTab->zName));*/ TRACE_IDX_INPUTS(p); rc = pVtab->pModule->xBestIndex(pVtab, p); TRACE_IDX_OUTPUTS(p); @@ -2733,8 +2769,8 @@ static int whereRangeScanEst( }else{ *pRangeDiv = (double)p->aiRowEst[0]/(double)(iUpper - iLower); } - WHERETRACE(("range scan regions: %u..%u div=%g\n", - (u32)iLower, (u32)iUpper, *pRangeDiv)); + /*WHERETRACE(("range scan regions: %u..%u div=%g\n", + (u32)iLower, (u32)iUpper, *pRangeDiv));*/ return SQLITE_OK; } } @@ -2791,7 +2827,7 @@ static int whereEqualScanEst( if( pRhs==0 ) return SQLITE_NOTFOUND; rc = whereKeyStats(pParse, p, pRhs, 0, a); if( rc==SQLITE_OK ){ - WHERETRACE(("equality scan regions: %d\n", (int)a[1])); + /*WHERETRACE(("equality scan regions: %d\n", (int)a[1]));*/ *pnRow = a[1]; } whereEqualScanEst_cancel: @@ -2837,7 +2873,7 @@ static int whereInScanEst( if( rc==SQLITE_OK ){ if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0]; *pnRow = nRowEst; - WHERETRACE(("IN row estimate: est=%g\n", nRowEst)); + /*WHERETRACE(("IN row estimate: est=%g\n", nRowEst));*/ } return rc; } @@ -3049,10 +3085,10 @@ static int isSortingIndex( }else{ Expr *pRight = pConstraint->pExpr->pRight; if( pRight->op==TK_COLUMN ){ - WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)", - pRight->iTable, pRight->iColumn)); + /*WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)", + pRight->iTable, pRight->iColumn));*/ isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn); - WHERETRACE((" -> isEq=%d\n", isEq)); + /*WHERETRACE((" -> isEq=%d\n", isEq));*/ /* If the constraint is of the form X=Y where Y is an ordered value ** in an outer loop, then make sure the sort order of Y matches the @@ -3319,10 +3355,10 @@ static void bestBtreeIndex(WhereBestIdx *p){ WhereTerm *pFirstTerm = 0; /* First term matching the index */ #endif - WHERETRACE(( + /*WHERETRACE(( " %s(%s):\n", pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk") - )); + ));*/ memset(&pc, 0, sizeof(pc)); pc.plan.nOBSat = nPriorSat; @@ -3403,10 +3439,10 @@ static void bestBtreeIndex(WhereBestIdx *p){ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){ int bRev = 2; int bObUnique = 0; - WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat)); + /*WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat));*/ pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev, &bObUnique); - WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n", - bRev, bObUnique, pc.plan.nOBSat)); + /*WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n", + bRev, bObUnique, pc.plan.nOBSat));*/ if( nPriorSatnotReady, log10N, pc.plan.nRow, pc.rCost, pc.used, pc.plan.nOBSat - )); + ));*/ /* If this index is the best we have seen so far, then record this ** index and its cost in the p->cost structure. @@ -3677,9 +3713,9 @@ static void bestBtreeIndex(WhereBestIdx *p){ || p->cost.plan.u.pIdx==pSrc->pIndex ); - WHERETRACE((" best index is %s cost=%.1f\n", + /*WHERETRACE((" best index is %s cost=%.1f\n", p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk", - p->cost.rCost)); + p->cost.rCost));*/ bestOrClauseIndex(p); bestAutomaticIndex(p); @@ -4928,6 +4964,13 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */ #endif /* SQLITE_TEST */ +/* +** Delete a WhereLoop object +*/ +static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ + sqlite3DbFree(db, p->aTerm); + sqlite3DbFree(db, p); +} /* ** Free a WhereInfo structure @@ -4953,10 +4996,140 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } } whereClauseClear(pWInfo->pWC); + while( pWInfo->pLoops ){ + WhereLoop *p = pWInfo->pLoops; + pWInfo->pLoops = p->pNextLoop; + whereLoopDelete(db, p); + } sqlite3DbFree(db, pWInfo); } } +/* +** Insert or replace a WhereLoop entry using the template supplied. +** +** An existing WhereLoop entry might be overwritten if the new template +** is better and has fewer dependencies. Or the template will be ignored +** and no insert will occur if an existing WhereLoop is faster and has +** fewer dependencies than the template. Otherwise a new WhereLoop is +** added based no the template. +*/ +static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ + WhereLoop **ppPrev, *p; + sqlite3 *db = pWInfo->pParse->db; + + /* Search for an existing WhereLoop to overwrite, or which takes + ** priority over pTemplate. + */ + for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ + if( p->iTab!=pTemplate->iTab ) continue; + if( (p->prereq & pTemplate->prereq)==p->prereq + && p->nOb>=pTemplate->nOb + && p->iOb==pTemplate->iOb + && p->rSetup<=pTemplate->rSetup + && p->rRun<=pTemplate->rRun + ){ + /* Already holding an equal or better WhereLoop. + ** Return without changing or adding anything */ + return SQLITE_OK; + } + if( (p->prereq & pTemplate->prereq)==pTemplate->prereq + && p->nOb<=pTemplate->nOb + && p->iOb==pTemplate->iOb + && p->rSetup>=pTemplate->rSetup + && p->rRun>=pTemplate->rRun + ){ + /* Overwrite an existing WhereLoop with a better one */ + sqlite3DbFree(db, p->aTerm); + *ppPrev = p->pNextLoop; + break; + } + } + + /* If we reach this point it means that either p[] should be overwritten + ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new + ** WhereLoop and insert it. + */ + if( p==0 ){ + p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); + if( p==0 ) return SQLITE_NOMEM; + } + *p = *pTemplate; + p->pNextLoop = pWInfo->pLoops; + pWInfo->pLoops = p; + if( pTemplate->nTerm<=0 ) return SQLITE_OK; + p->aTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0])); + if( p->aTerm==0 ){ + p->nTerm = 0; + return SQLITE_NOMEM; + } + memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0])); + return SQLITE_OK; +} + +/* +** Add all WhereLoop objects for the iTab-th table of the join. That +** table is guaranteed to be a b-tree table, not a virtual table. +*/ +static void whereLoopAddBtree( + WhereInfo *pWInfo, /* WHERE clause information */ + int iTab, /* The table to process */ + Bitmask mExtra /* Extra prerequesites for using this table */ +){ + WhereLoop *pNew; /* Template WhereLoop object */ + sqlite3 *db = pWInfo->pParse->db; + + pNew = sqlite3DbMallocZero(db, sizeof(*pNew)); + if( pNew==0 ) return; + + /* Insert a full table scan */ + pNew->iTab = iTab; + pNew->rSetup = (double)0; + pNew->rRun = (double)1000000; + pNew->nOut = (double)1000000; + whereLoopInsert(pWInfo, pNew); + + whereLoopDelete(db, pNew); +} + +/* +** Add all WhereLoop objects for the iTab-th table of the join. That +** table is guaranteed to be a virtual table. +*/ +static void whereLoopAddVirtual( + WhereInfo *pWInfo, /* WHERE clause information */ + int iTab, /* The table to process */ + Bitmask mExtra /* Extra prerequesites for using this table */ +){ +} + +/* +** Add all WhereLoop objects for all tables +*/ +static void whereLoopAddAll(WhereInfo *pWInfo){ + Bitmask mExtra = 0; + Bitmask mPrior = 0; + int iTab; + SrcList *pTabList = pWInfo->pTabList; + struct SrcList_item *pItem; + WhereClause *pWC = pWInfo->pWC; + sqlite3 *db = pWInfo->pParse->db; + + /* Loop over the tables in the join, from left to right */ + for(iTab=0, pItem=pTabList->a; iTabnSrc; iTab++, pItem++){ + if( IsVirtual(pItem->pTab) ){ + whereLoopAddVirtual(pWInfo, iTab, mExtra); + }else{ + whereLoopAddBtree(pWInfo, iTab, mExtra); + } + mPrior |= getMask(pWC->pMaskSet, pItem->iCursor); + if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ + mExtra = mPrior; + } + if( db->mallocFailed ) break; + } +} + /* ** Generate the beginning of the loop used for WHERE clause processing. @@ -5187,6 +5360,35 @@ WhereInfo *sqlite3WhereBegin( pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } + /* Construct the WhereLoop objects */ + WHERETRACE(("*** Optimizer Start ***\n")); + whereLoopAddAll(pWInfo); + + /* Display all of the WhereLoop objects if wheretrace is enabled */ +#if defined(SQLITE_DEBUG) \ + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) + if( sqlite3WhereTrace ){ + WhereLoop *p; + int nb = 2*((nTabList+15)/16); + for(p=pWInfo->pLoops; p; p=p->pNextLoop){ + struct SrcList_item *pItem = pTabList->a + p->iTab; + Table *pTab = pItem->pTab; + sqlite3DebugPrintf("%02d.%0*llx", p->iTab, nb, p->prereq); + sqlite3DebugPrintf(" %s", + pItem->zAlias ? pItem->zAlias : pTab->zName); + if( p->pIndex ){ + sqlite3DebugPrintf(" index %s nEq %d", p->pIndex->zName, p->nEq); + }else{ + sqlite3DebugPrintf("\n"); + } + sqlite3DebugPrintf(" wsFlags %08x OB %d,%d nTerm %d\n", + p->wsFlags, p->iOb, p->nOb, p->nTerm); + sqlite3DebugPrintf(" cost %.2e + %.2e nOut %.2e\n", + p->prereq, p->rSetup, p->rRun, p->nOut); + } + } +#endif + /* Chose the best index to use for each table in the FROM clause. ** ** This loop fills in the following fields: @@ -5207,7 +5409,6 @@ WhereInfo *sqlite3WhereBegin( sWBI.n = nTabList; sWBI.pDistinct = pDistinct; andFlags = ~0; - WHERETRACE(("*** Optimizer Start ***\n")); for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.ipIndex==0 ) nUnconstrained++; - WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n", - j, sWBI.pSrc->pTab->zName, isOptimal)); + /*WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n", + j, sWBI.pSrc->pTab->zName, isOptimal));*/ assert( sWBI.pSrc->pTab ); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(sWBI.pSrc->pTab) ){ @@ -5335,9 +5536,9 @@ WhereInfo *sqlite3WhereBegin( ** for the outer loop that table which benefits the least from ** being in the inner loop. The following code scales the ** outer loop cost estimate to accomplish that. */ - WHERETRACE((" scaling cost from %.1f to %.1f\n", + /*WHERETRACE((" scaling cost from %.1f to %.1f\n", sWBI.cost.rCost, - sWBI.cost.rCost/pWInfo->a[j].rOptCost)); + sWBI.cost.rCost/pWInfo->a[j].rOptCost));*/ sWBI.cost.rCost /= pWInfo->a[j].rOptCost; } @@ -5367,11 +5568,11 @@ WhereInfo *sqlite3WhereBegin( || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */ ){ - WHERETRACE((" === table %d (%s) is best so far\n" + /*WHERETRACE((" === table %d (%s) is best so far\n" " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n", j, sWBI.pSrc->pTab->zName, sWBI.cost.rCost, sWBI.cost.plan.nRow, - sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags)); + sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));*/ bestPlan = sWBI.cost; bestJ = j; } @@ -5388,11 +5589,11 @@ WhereInfo *sqlite3WhereBegin( testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 ); testcase( bestJ>iFrom && bestJa[bestJ+1].jointype & JT_LEFT)!=0 ); - WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n" + /*WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n" " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n", bestJ, pTabList->a[bestJ].pTab->zName, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow, - bestPlan.plan.nOBSat, bestPlan.plan.wsFlags)); + bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));*/ if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){ assert( pWInfo->eDistinct==0 ); pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; From 1c8148fffb49cb540e0c97f0700a0f3c0c0db52d Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 4 May 2013 20:25:23 +0000 Subject: [PATCH 002/144] In where.c, make findTerm() a wrapper around methods to a new WhereScan object which is capable of finding all suitable matching terms, not just the first. This check-in includes some prototype functions for building WhereLoop objects. FossilOrigin-Name: dd92b8fa929badaf2f79e8a00c83667a9d589096 --- manifest | 15 +- manifest.uuid | 2 +- src/where.c | 381 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 292 insertions(+), 106 deletions(-) diff --git a/manifest b/manifest index 75d4e526f5..a36fbf25aa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Begin\sinserting\ssome\sexperimental\scode\sfor\sthe\snext\sgeneration\squery\splanner. -D 2013-05-02T00:15:01.231 +C In\swhere.c,\smake\sfindTerm()\sa\swrapper\saround\smethods\sto\sa\snew\sWhereScan\sobject\nwhich\sis\scapable\sof\sfinding\sall\ssuitable\smatching\sterms,\snot\sjust\sthe\sfirst.\nThis\scheck-in\sincludes\ssome\sprototype\sfunctions\sfor\sbuilding\sWhereLoop\sobjects. +D 2013-05-04T20:25:23.612 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c fc62bea654f27d5787bc428cd8f3f176d764f785 +F src/where.c 173347e4598207467401e1952bdee983cf0bf087 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,10 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P faedaeace9c7ed9a8aaf96700caee09db0c0c061 -R 84f8c9b09f28282800936ed72686b19f -T *branch * nextgen-query-plan-exp -T *sym-nextgen-query-plan-exp * -T -sym-trunk * +P ccaf4c3f7e1ec45e058d594d9b5c26818a37722a +R d516c3475d503fb543da6770e30ae39a U drh -Z 18faca4b1f68b4b3514e189f395d77ff +Z 4a8c637fc587086861ee6817f8b965a6 diff --git a/manifest.uuid b/manifest.uuid index 016ae611b1..36eaec293a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ccaf4c3f7e1ec45e058d594d9b5c26818a37722a \ No newline at end of file +dd92b8fa929badaf2f79e8a00c83667a9d589096 \ No newline at end of file diff --git a/src/where.c b/src/where.c index f44ab496c0..14120339d2 100644 --- a/src/where.c +++ b/src/where.c @@ -42,6 +42,8 @@ typedef struct WhereCost WhereCost; typedef struct WhereLoop WhereLoop; typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; +typedef struct WhereLoopBuilder WhereLoopBuilder; +typedef struct WhereScan WhereScan; /* ** Each instance of this object represents a way of evaluating one @@ -60,7 +62,7 @@ struct WhereLoop { u16 nEq; /* Number of equality constraints */ u16 nTerm; /* Number of entries in aTerm[] */ Index *pIndex; /* Index used */ - WhereTerm *aTerm; /* WhereTerms used */ + WhereTerm **aTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ }; @@ -161,6 +163,23 @@ struct WhereTerm { # define TERM_VNULL 0x00 /* Disabled if not using stat3 */ #endif +/* +** An instance of the WhereScan object is used as an iterator for locating +** terms in the WHERE clause that are useful to the query planner. +*/ +struct WhereScan { + WhereTerm *pCurrent; /* Most recent match */ + WhereClause *pOrigWC; /* Original, innermost WhereClause */ + WhereClause *pWC; /* WhereClause currently being scanned */ + char *zCollName; /* Must have this collating sequence, if not NULL */ + char idxaff; /* Must match this affinity, if zCollName!=NULL */ + unsigned char nEquiv; /* Number of entries in aEquiv[] */ + unsigned char iEquiv; /* Next unused slot in aEquiv[] */ + u32 opMask; /* Acceptable operators */ + int k; /* Resume scanning at this->pWC->a[this->k] */ + int aEquiv[22]; /* Cursor,Column pairs for equivalence classes */ +}; + /* ** An instance of the following structure holds all information about a ** WHERE clause. Mostly this is a container for one or more WhereTerms. @@ -247,6 +266,19 @@ struct WhereCost { Bitmask used; /* Bitmask of cursors used by this plan */ }; +/* +** This object is a factory for WhereLoop objects for a particular query. +*/ +struct WhereLoopBuilder { + WhereInfo *pWInfo; /* Information about this WHERE */ + sqlite3 *db; /* Database connection */ + Parse *pParse; /* Parsing context */ + WhereClause *pWC; /* WHERE clause terms */ + SrcList *pTabList; /* FROM clause */ + ExprList *pOrderBy; /* ORDER BY clause */ + WhereLoop *pNew; /* Template WhereLoop */ +}; + /* ** Bitmasks for the operators that indices are able to exploit. An ** OR-ed combination of these values can be used when searching for @@ -661,6 +693,114 @@ static u16 operatorMask(int op){ return c; } +/* +** Advance to the next WhereTerm that matches according to the criteria +** established when the pScan object was initialized by whereScanInit(). +** Return NULL if there are no more matching WhereTerms. +*/ +WhereTerm *whereScanNext(WhereScan *pScan){ + int iCur; /* The cursor on the LHS of the term */ + int iColumn; /* The column on the LHS of the term. -1 for IPK */ + Expr *pX; /* An expression being tested */ + WhereClause *pWC; /* Shorthand for pScan->pWC */ + WhereTerm *pTerm; /* The term being tested */ + + while( pScan->iEquiv<=pScan->nEquiv ){ + iCur = pScan->aEquiv[pScan->iEquiv-2]; + iColumn = pScan->aEquiv[pScan->iEquiv-1]; + while( (pWC = pScan->pWC)!=0 ){ + for(pTerm=pWC->a+pScan->k; pScan->knTerm; pScan->k++, pTerm++){ + if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn ){ + if( (pTerm->eOperator & WO_EQUIV)!=0 + && pScan->nEquivaEquiv) + ){ + int j; + pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight); + assert( pX->op==TK_COLUMN ); + for(j=0; jnEquiv; j+=2){ + if( pScan->aEquiv[j]==pX->iTable + && pScan->aEquiv[j+1]==pX->iColumn ){ + break; + } + } + if( j==pScan->nEquiv ){ + pScan->aEquiv[j] = pX->iTable; + pScan->aEquiv[j+1] = pX->iColumn; + pScan->nEquiv += 2; + } + } + if( (pTerm->eOperator & pScan->opMask)!=0 ){ + /* Verify the affinity and collating sequence match */ + if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){ + CollSeq *pColl; + pX = pTerm->pExpr; + if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ + continue; + } + assert(pX->pLeft); + pColl = sqlite3BinaryCompareCollSeq(pWC->pParse, + pX->pLeft, pX->pRight); + if( pColl==0 ) pColl = pWC->pParse->db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ + continue; + } + } + pScan->pCurrent = pTerm; + pScan->k++; + return pTerm; + } + } + } + pWC = pScan->pWC = pScan->pWC->pOuter; + pScan->k = 0; + } + pScan->pWC = pScan->pOrigWC; + pScan->k = 0; + pScan->iEquiv += 2; + } + pScan->pCurrent = 0; + return 0; +} + +/* +** Initialize a WHERE clause scanner object. Return a pointer to the +** first match. Return NULL if there are no matches. +** +** The scanner will be searching the WHERE clause pWC. It will look +** for terms of the form "X " where X is column iColumn of table +** iCur. The must be one of the operators described by opMask. +** +** If X is not the INTEGER PRIMARY KEY then X must be compatible with +** index pIdx. +*/ +WhereTerm *whereScanInit( + WhereScan *pScan, /* The WhereScan object being initialized */ + WhereClause *pWC, /* The WHERE clause to be scanned */ + int iCur, /* Cursor to scan for */ + int iColumn, /* Column to scan for */ + u32 opMask, /* Operator(s) to scan for */ + Index *pIdx /* Must be compatible with this index */ +){ + int j; + + memset(pScan, 0, sizeof(*pScan)); + pScan->pOrigWC = pWC; + pScan->pWC = pWC; + if( pIdx && iColumn>=0 ){ + pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; + for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ + if( NEVER(j>=pIdx->nColumn) ) return 0; + } + pScan->zCollName = pIdx->azColl[j]; + } + pScan->opMask = opMask; + pScan->aEquiv[0] = iCur; + pScan->aEquiv[1] = iColumn; + pScan->nEquiv = 2; + pScan->iEquiv = 2; + return whereScanNext(pScan); +} + /* ** Search for a term in the WHERE clause that is of the form "X " ** where X is a reference to the iColumn of table iCur and is one of @@ -692,84 +832,20 @@ static WhereTerm *findTerm( u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ){ - WhereTerm *pTerm; /* Term being examined as possible result */ - WhereTerm *pResult = 0; /* The answer to return */ - WhereClause *pWCOrig = pWC; /* Original pWC value */ - int j, k; /* Loop counters */ - Expr *pX; /* Pointer to an expression */ - Parse *pParse; /* Parsing context */ - int iOrigCol = iColumn; /* Original value of iColumn */ - int nEquiv = 2; /* Number of entires in aEquiv[] */ - int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */ - int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */ + WhereTerm *pResult = 0; + WhereTerm *p; + WhereScan scan; - assert( iCur>=0 ); - aEquiv[0] = iCur; - aEquiv[1] = iColumn; - for(;;){ - for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){ - for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ - if( pTerm->leftCursor==iCur - && pTerm->u.leftColumn==iColumn - ){ - if( (pTerm->prereqRight & notReady)==0 - && (pTerm->eOperator & op & WO_ALL)!=0 - ){ - if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){ - CollSeq *pColl; - char idxaff; - - pX = pTerm->pExpr; - pParse = pWC->pParse; - idxaff = pIdx->pTable->aCol[iOrigCol].affinity; - if( !sqlite3IndexAffinityOk(pX, idxaff) ){ - continue; - } - - /* Figure out the collation sequence required from an index for - ** it to be useful for optimising expression pX. Store this - ** value in variable pColl. - */ - assert(pX->pLeft); - pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight); - if( pColl==0 ) pColl = pParse->db->pDfltColl; - - for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){ - if( NEVER(j>=pIdx->nColumn) ) return 0; - } - if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){ - continue; - } - } - if( pTerm->prereqRight==0 && (pTerm->eOperator&WO_EQ)!=0 ){ - pResult = pTerm; - goto findTerm_success; - }else if( pResult==0 ){ - pResult = pTerm; - } - } - if( (pTerm->eOperator & WO_EQUIV)!=0 - && nEquivpExpr->pRight); - assert( pX->op==TK_COLUMN ); - for(j=0; jiTable && aEquiv[j+1]==pX->iColumn ) break; - } - if( j==nEquiv ){ - aEquiv[j] = pX->iTable; - aEquiv[j+1] = pX->iColumn; - nEquiv += 2; - } - } - } + p = whereScanInit(&scan, pWC, iCur, iColumn, op, pIdx); + while( p ){ + if( (p->prereqRight & notReady)==0 ){ + if( p->prereqRight==0 && (p->eOperator&WO_EQ)!=0 ){ + return p; } + if( pResult==0 ) pResult = p; } - if( iEquiv>=nEquiv ) break; - iCur = aEquiv[iEquiv++]; - iColumn = aEquiv[iEquiv++]; + p = whereScanNext(&scan); } -findTerm_success: return pResult; } @@ -5058,38 +5134,139 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ p->pNextLoop = pWInfo->pLoops; pWInfo->pLoops = p; if( pTemplate->nTerm<=0 ) return SQLITE_OK; + if( p->pIndex && p->pIndex->tnum==0 ) p->pIndex = 0; p->aTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0])); if( p->aTerm==0 ){ p->nTerm = 0; + sqlite3DbFree(db, p); return SQLITE_NOMEM; } memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0])); return SQLITE_OK; } +/* +** We have so far matched pBuilder->pNew->nEq terms of the index pIndex. +** Try to match one more. +** +** If pProbe->tnum==0, that means pIndex is a fake index used for the +** INTEGER PRIMARY KEY. +*/ +static void whereLoopAddBtreeIndex( + WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ + struct SrcList_item *pSrc, /* FROM clause term being analyzed */ + Index *pProbe, /* An index on pSrc */ + int nInMul /* Number of iterations due to IN */ +){ + sqlite3 *db; /* Database connection malloc context */ + WhereLoop *pNew; /* Template WhereLoop under construction */ + WhereTerm *pTerm; /* A WhereTerm under consideration */ + int eqTermMask; /* Valid equality operators */ + WhereScan scan; /* Iterator for WHERE terms */ + + db = pBuilder->db; + pNew = pBuilder->pNew; + if( db->mallocFailed ) return; + + if( pProbe->tnum<=0 || (pSrc->jointype & JT_LEFT)!=0 ){ + eqTermMask = WO_EQ|WO_IN; + }else{ + eqTermMask = WO_EQ|WO_IN|WO_ISNULL; + } + + + if( pNew->nEqnColumn ){ + int iCol; /* Index of the column in the table */ + + + iCol = pProbe->aiColumn[pNew->nEq]; + pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, + eqTermMask, iCol>=0 ? pProbe : 0); + pNew->nEq++; + for(; pTerm!=0; pTerm = whereScanNext(&scan)){ + pNew->aTerm[pNew->nEq-1] = pTerm; + + } + pNew->nEq--; + + } +} + /* ** Add all WhereLoop objects for the iTab-th table of the join. That ** table is guaranteed to be a b-tree table, not a virtual table. */ static void whereLoopAddBtree( - WhereInfo *pWInfo, /* WHERE clause information */ - int iTab, /* The table to process */ - Bitmask mExtra /* Extra prerequesites for using this table */ + WhereLoopBuilder *pBuilder, /* WHERE clause information */ + int iTab, /* The table to process */ + Bitmask mExtra /* Extra prerequesites for using this table */ ){ - WhereLoop *pNew; /* Template WhereLoop object */ - sqlite3 *db = pWInfo->pParse->db; + Index *pProbe; /* An index we are evaluating */ + int eqTermMask; /* Current mask of valid equality operators */ + Index sPk; /* A fake index object for the primary key */ + tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ + int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ + struct SrcList_item *pSrc; /* The FROM clause btree term to add */ + sqlite3 *db; /* The database connection */ + WhereLoop *pNew; /* Template WhereLoop object */ - pNew = sqlite3DbMallocZero(db, sizeof(*pNew)); - if( pNew==0 ) return; - + pNew = pBuilder->pNew; + db = pBuilder->db; + pSrc = pBuilder->pTabList->a + iTab; + + if( pSrc->pIndex ){ + /* An INDEXED BY clause specifies a particular index to use */ + pProbe = pSrc->pIndex; + }else{ + /* There is no INDEXED BY clause. Create a fake Index object in local + ** variable sPk to represent the rowid primary key index. Make this + ** fake index the first in a chain of Index objects with all of the real + ** indices to follow */ + Index *pFirst; /* First of real indices on the table */ + memset(&sPk, 0, sizeof(Index)); + sPk.nColumn = 1; + sPk.aiColumn = &aiColumnPk; + sPk.aiRowEst = aiRowEstPk; + sPk.onError = OE_Replace; + sPk.pTable = pSrc->pTab; + aiRowEstPk[0] = pSrc->pTab->nRowEst; + aiRowEstPk[1] = 1; + pFirst = pSrc->pTab->pIndex; + if( pSrc->notIndexed==0 ){ + /* The real indices of the table are only considered if the + ** NOT INDEXED qualifier is omitted from the FROM clause */ + sPk.pNext = pFirst; + } + pProbe = &sPk; + } + + /* Loop over all indices + */ + for(; pProbe; pProbe=pProbe->pNext){ + pNew->prereq = mExtra; + pNew->iTab = iTab; + pNew->nEq = 0; + pNew->nTerm = 0; + pNew->aTerm = sqlite3DbRealloc(db, pNew->aTerm, + (pProbe->nColumn+1)*sizeof(pNew->aTerm[0])); + if( pNew->aTerm==0 ) break; + pNew->pIndex = pProbe; + + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); + + /* If there was an INDEXED BY clause, then only that one index is + ** considered. */ + if( pSrc->pIndex ) break; + } + +#if 0 /* Insert a full table scan */ pNew->iTab = iTab; pNew->rSetup = (double)0; pNew->rRun = (double)1000000; pNew->nOut = (double)1000000; - whereLoopInsert(pWInfo, pNew); - - whereLoopDelete(db, pNew); + whereLoopInsert(pBuilder->pWInfo, pNew); +#endif } /* @@ -5097,30 +5274,32 @@ static void whereLoopAddBtree( ** table is guaranteed to be a virtual table. */ static void whereLoopAddVirtual( - WhereInfo *pWInfo, /* WHERE clause information */ - int iTab, /* The table to process */ - Bitmask mExtra /* Extra prerequesites for using this table */ + WhereLoopBuilder *pBuilder, /* WHERE clause information */ + int iTab, /* The table to process */ + Bitmask mExtra /* Extra prerequesites for using this table */ ){ } /* ** Add all WhereLoop objects for all tables */ -static void whereLoopAddAll(WhereInfo *pWInfo){ +static void whereLoopAddAll(WhereLoopBuilder *pBuilder){ Bitmask mExtra = 0; Bitmask mPrior = 0; int iTab; - SrcList *pTabList = pWInfo->pTabList; + SrcList *pTabList = pBuilder->pTabList; struct SrcList_item *pItem; - WhereClause *pWC = pWInfo->pWC; - sqlite3 *db = pWInfo->pParse->db; + WhereClause *pWC = pBuilder->pWC; + sqlite3 *db = pBuilder->db; /* Loop over the tables in the join, from left to right */ + pBuilder->pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); + if( pBuilder->pNew==0 ) return; for(iTab=0, pItem=pTabList->a; iTabnSrc; iTab++, pItem++){ if( IsVirtual(pItem->pTab) ){ - whereLoopAddVirtual(pWInfo, iTab, mExtra); + whereLoopAddVirtual(pBuilder, iTab, mExtra); }else{ - whereLoopAddBtree(pWInfo, iTab, mExtra); + whereLoopAddBtree(pBuilder, iTab, mExtra); } mPrior |= getMask(pWC->pMaskSet, pItem->iCursor); if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ @@ -5128,6 +5307,8 @@ static void whereLoopAddAll(WhereInfo *pWInfo){ } if( db->mallocFailed ) break; } + whereLoopDelete(db, pBuilder->pNew); + pBuilder->pNew = 0; } @@ -5234,6 +5415,7 @@ WhereInfo *sqlite3WhereBegin( Vdbe *v = pParse->pVdbe; /* The virtual database engine */ Bitmask notReady; /* Cursors that are not yet positioned */ WhereBestIdx sWBI; /* Best index search context */ + WhereLoopBuilder sWLB; /* The WhereLoop builder */ WhereMaskSet *pMaskSet; /* The expression mask set */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */ int iFrom; /* First unused FROM clause element */ @@ -5245,6 +5427,11 @@ WhereInfo *sqlite3WhereBegin( /* Variable initialization */ memset(&sWBI, 0, sizeof(sWBI)); sWBI.pParse = pParse; + memset(&sWLB, 0, sizeof(sWLB)); + sWLB.pParse = pParse; + sWLB.db = pParse->db; + sWLB.pTabList = pTabList; + sWLB.pOrderBy = pOrderBy; /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask @@ -5290,6 +5477,8 @@ WhereInfo *sqlite3WhereBegin( pWInfo->savedNQueryLoop = pParse->nQueryLoop; pMaskSet = (WhereMaskSet*)&sWBI.pWC[1]; sWBI.aLevel = pWInfo->a; + sWLB.pWInfo = pWInfo; + sWLB.pWC = pWInfo->pWC; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ @@ -5362,7 +5551,7 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(("*** Optimizer Start ***\n")); - whereLoopAddAll(pWInfo); + /*whereLoopAddAll(&sWLB);*/ /* Display all of the WhereLoop objects if wheretrace is enabled */ #if defined(SQLITE_DEBUG) \ From f1645f084376428d018930ef72f1e304cfab29dc Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 7 May 2013 19:44:38 +0000 Subject: [PATCH 003/144] Inserting a few WhereLoop objects without leaking memory. Costs are not correct. Inequality and IN constraints are not implemented. FossilOrigin-Name: e8881a8b2f25f38bc8ff77619f96f38fe530d13b --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 41 ++++++++++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index a36fbf25aa..29d28aecb0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\swhere.c,\smake\sfindTerm()\sa\swrapper\saround\smethods\sto\sa\snew\sWhereScan\sobject\nwhich\sis\scapable\sof\sfinding\sall\ssuitable\smatching\sterms,\snot\sjust\sthe\sfirst.\nThis\scheck-in\sincludes\ssome\sprototype\sfunctions\sfor\sbuilding\sWhereLoop\sobjects. -D 2013-05-04T20:25:23.612 +C Inserting\sa\sfew\sWhereLoop\sobjects\swithout\sleaking\smemory.\s\sCosts\sare\nnot\scorrect.\s\sInequality\sand\sIN\sconstraints\sare\snot\simplemented. +D 2013-05-07T19:44:38.531 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 173347e4598207467401e1952bdee983cf0bf087 +F src/where.c e987a4ff2818b812f902361c1131fef4a8f95a41 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ccaf4c3f7e1ec45e058d594d9b5c26818a37722a -R d516c3475d503fb543da6770e30ae39a +P dd92b8fa929badaf2f79e8a00c83667a9d589096 +R 20c9cc42b7ec6059ab1cb985542962e1 U drh -Z 4a8c637fc587086861ee6817f8b965a6 +Z 6dee1758f1f268139b7d8139f9ade772 diff --git a/manifest.uuid b/manifest.uuid index 36eaec293a..62ed5b5e8a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dd92b8fa929badaf2f79e8a00c83667a9d589096 \ No newline at end of file +e8881a8b2f25f38bc8ff77619f96f38fe530d13b \ No newline at end of file diff --git a/src/where.c b/src/where.c index 14120339d2..4776a2b231 100644 --- a/src/where.c +++ b/src/where.c @@ -5163,6 +5163,7 @@ static void whereLoopAddBtreeIndex( WhereTerm *pTerm; /* A WhereTerm under consideration */ int eqTermMask; /* Valid equality operators */ WhereScan scan; /* Iterator for WHERE terms */ + WhereLoop savedLoop; db = pBuilder->db; pNew = pBuilder->pNew; @@ -5182,13 +5183,26 @@ static void whereLoopAddBtreeIndex( iCol = pProbe->aiColumn[pNew->nEq]; pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, eqTermMask, iCol>=0 ? pProbe : 0); + savedLoop = *pNew; pNew->nEq++; + pNew->nTerm++; for(; pTerm!=0; pTerm = whereScanNext(&scan)){ pNew->aTerm[pNew->nEq-1] = pTerm; - + pNew->nOut = (double)(pProbe->aiRowEst[pNew->nEq] * nInMul); + pNew->rSetup = (double)0; + pNew->rRun = pNew->nOut; + pNew->prereq = savedLoop.prereq | pTerm->prereqRight; + if( pProbe->tnum<=0 ){ + pNew->wsFlags = savedLoop.wsFlags | WHERE_ROWID_EQ; + }else{ + pNew->wsFlags = savedLoop.wsFlags | WHERE_COLUMN_EQ; + } + whereLoopInsert(pBuilder->pWInfo, pNew); + if( pNew->nEqnColumn ){ + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul); + } } - pNew->nEq--; - + *pNew = savedLoop; } } @@ -5202,7 +5216,6 @@ static void whereLoopAddBtree( Bitmask mExtra /* Extra prerequesites for using this table */ ){ Index *pProbe; /* An index we are evaluating */ - int eqTermMask; /* Current mask of valid equality operators */ Index sPk; /* A fake index object for the primary key */ tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ @@ -5243,13 +5256,15 @@ static void whereLoopAddBtree( /* Loop over all indices */ for(; pProbe; pProbe=pProbe->pNext){ + WhereTerm **paTerm; pNew->prereq = mExtra; pNew->iTab = iTab; pNew->nEq = 0; pNew->nTerm = 0; - pNew->aTerm = sqlite3DbRealloc(db, pNew->aTerm, - (pProbe->nColumn+1)*sizeof(pNew->aTerm[0])); - if( pNew->aTerm==0 ) break; + paTerm = sqlite3DbRealloc(db, pNew->aTerm, + (pProbe->nColumn+1)*sizeof(pNew->aTerm[0])); + if( paTerm==0 ) break; + pNew->aTerm = paTerm; pNew->pIndex = pProbe; whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); @@ -5551,7 +5566,7 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(("*** Optimizer Start ***\n")); - /*whereLoopAddAll(&sWLB);*/ + whereLoopAddAll(&sWLB); /* Display all of the WhereLoop objects if wheretrace is enabled */ #if defined(SQLITE_DEBUG) \ @@ -5563,16 +5578,16 @@ WhereInfo *sqlite3WhereBegin( struct SrcList_item *pItem = pTabList->a + p->iTab; Table *pTab = pItem->pTab; sqlite3DebugPrintf("%02d.%0*llx", p->iTab, nb, p->prereq); - sqlite3DebugPrintf(" %s", + sqlite3DebugPrintf(" %5s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( p->pIndex ){ - sqlite3DebugPrintf(" index %s nEq %d", p->pIndex->zName, p->nEq); + sqlite3DebugPrintf(".%-5s %2d", p->pIndex->zName, p->nEq); }else{ - sqlite3DebugPrintf("\n"); + sqlite3DebugPrintf("%9s",""); } - sqlite3DebugPrintf(" wsFlags %08x OB %d,%d nTerm %d\n", + sqlite3DebugPrintf(" fg %08x OB %d,%d N %2d", p->wsFlags, p->iOb, p->nOb, p->nTerm); - sqlite3DebugPrintf(" cost %.2e + %.2e nOut %.2e\n", + sqlite3DebugPrintf(" cost %.2g+%.2g,%.2g\n", p->prereq, p->rSetup, p->rRun, p->nOut); } } From 43fe25fcef6f0fa329c2a9748bc3794d783e12b9 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 7 May 2013 23:06:23 +0000 Subject: [PATCH 004/144] Continued progress on generating good WhereLoop objects for the new query planner. FossilOrigin-Name: 15cc8a16482777d8e138c4d0863faf8d54fef33a --- manifest | 12 ++--- manifest.uuid | 2 +- src/where.c | 134 +++++++++++++++++++++++++++++++++++--------------- 3 files changed, 101 insertions(+), 47 deletions(-) diff --git a/manifest b/manifest index 29d28aecb0..c79d6f38fd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Inserting\sa\sfew\sWhereLoop\sobjects\swithout\sleaking\smemory.\s\sCosts\sare\nnot\scorrect.\s\sInequality\sand\sIN\sconstraints\sare\snot\simplemented. -D 2013-05-07T19:44:38.531 +C Continued\sprogress\son\sgenerating\sgood\sWhereLoop\sobjects\sfor\sthe\snew\squery\nplanner. +D 2013-05-07T23:06:23.630 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e987a4ff2818b812f902361c1131fef4a8f95a41 +F src/where.c e957c2c6fd7b421ea6dd1ff11d254c80d0b11638 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P dd92b8fa929badaf2f79e8a00c83667a9d589096 -R 20c9cc42b7ec6059ab1cb985542962e1 +P e8881a8b2f25f38bc8ff77619f96f38fe530d13b +R 90f142cd2d5094cb6ddc049cebfe5b6d U drh -Z 6dee1758f1f268139b7d8139f9ade772 +Z d9519f5b83b11415ad77247122aa0d25 diff --git a/manifest.uuid b/manifest.uuid index 62ed5b5e8a..82bc167f3b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e8881a8b2f25f38bc8ff77619f96f38fe530d13b \ No newline at end of file +15cc8a16482777d8e138c4d0863faf8d54fef33a \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4776a2b231..56568989aa 100644 --- a/src/where.c +++ b/src/where.c @@ -315,6 +315,7 @@ struct WhereLoopBuilder { */ #define WHERE_ROWID_EQ 0x00001000 /* rowid=EXPR or rowid IN (...) */ #define WHERE_ROWID_RANGE 0x00002000 /* rowidEXPR */ +#define WHERE_IPK 0x00004000 /* x is the INTEGER PRIMARY KEY */ #define WHERE_COLUMN_EQ 0x00010000 /* x=EXPR or x IN (...) or x IS NULL */ #define WHERE_COLUMN_RANGE 0x00020000 /* xEXPR */ #define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */ @@ -710,6 +711,15 @@ WhereTerm *whereScanNext(WhereScan *pScan){ iColumn = pScan->aEquiv[pScan->iEquiv-1]; while( (pWC = pScan->pWC)!=0 ){ for(pTerm=pWC->a+pScan->k; pScan->knTerm; pScan->k++, pTerm++){ + if( pTerm->iParent>=0 ){ + WhereTerm *pParent = &pWC->a[pTerm->iParent]; + int j; + for(j=pScan->iEquiv-4; j>=0; j-=2 ){ + if( pParent->leftCursor==pScan->aEquiv[j] + && pParent->u.leftColumn==pScan->aEquiv[j+1] ) break; + } + if( j>=0 ) continue; + } if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaEquiv) @@ -5091,7 +5101,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** added based no the template. */ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ - WhereLoop **ppPrev, *p; + WhereLoop **ppPrev, *p, *pNext = 0, *pToFree = 0; sqlite3 *db = pWInfo->pParse->db; /* Search for an existing WhereLoop to overwrite, or which takes @@ -5117,7 +5127,7 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ ){ /* Overwrite an existing WhereLoop with a better one */ sqlite3DbFree(db, p->aTerm); - *ppPrev = p->pNextLoop; + pNext = p->pNextLoop; break; } } @@ -5127,18 +5137,19 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ ** WhereLoop and insert it. */ if( p==0 ){ - p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); + p = pToFree = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; } *p = *pTemplate; - p->pNextLoop = pWInfo->pLoops; - pWInfo->pLoops = p; - if( pTemplate->nTerm<=0 ) return SQLITE_OK; + p->pNextLoop = pNext; + *ppPrev = p; + p->aTerm = 0; if( p->pIndex && p->pIndex->tnum==0 ) p->pIndex = 0; + if( pTemplate->nTerm<=0 ) return SQLITE_OK; p->aTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0])); if( p->aTerm==0 ){ p->nTerm = 0; - sqlite3DbFree(db, p); + sqlite3DbFree(db, pToFree); return SQLITE_NOMEM; } memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0])); @@ -5154,6 +5165,7 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ */ static void whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ + Bitmask maskSelf, /* Bitmask for table being scanned */ struct SrcList_item *pSrc, /* FROM clause term being analyzed */ Index *pProbe, /* An index on pSrc */ int nInMul /* Number of iterations due to IN */ @@ -5161,18 +5173,22 @@ static void whereLoopAddBtreeIndex( sqlite3 *db; /* Database connection malloc context */ WhereLoop *pNew; /* Template WhereLoop under construction */ WhereTerm *pTerm; /* A WhereTerm under consideration */ - int eqTermMask; /* Valid equality operators */ + int opMask; /* Valid operators for constraints */ WhereScan scan; /* Iterator for WHERE terms */ - WhereLoop savedLoop; + WhereLoop savedLoop; /* Saved original content of pNew[] */ db = pBuilder->db; pNew = pBuilder->pNew; if( db->mallocFailed ) return; - if( pProbe->tnum<=0 || (pSrc->jointype & JT_LEFT)!=0 ){ - eqTermMask = WO_EQ|WO_IN; + assert( pNew->nEqnColumn ); + assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); + if( pNew->wsFlags & WHERE_BTM_LIMIT ){ + opMask = WO_LT|WO_LE; + }else if( pProbe->tnum<=0 || (pSrc->jointype & JT_LEFT)!=0 ){ + opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE; }else{ - eqTermMask = WO_EQ|WO_IN|WO_ISNULL; + opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE; } @@ -5182,24 +5198,42 @@ static void whereLoopAddBtreeIndex( iCol = pProbe->aiColumn[pNew->nEq]; pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, - eqTermMask, iCol>=0 ? pProbe : 0); + opMask, iCol>=0 ? pProbe : 0); savedLoop = *pNew; - pNew->nEq++; - pNew->nTerm++; + pNew->rSetup = (double)0; for(; pTerm!=0; pTerm = whereScanNext(&scan)){ - pNew->aTerm[pNew->nEq-1] = pTerm; - pNew->nOut = (double)(pProbe->aiRowEst[pNew->nEq] * nInMul); - pNew->rSetup = (double)0; - pNew->rRun = pNew->nOut; - pNew->prereq = savedLoop.prereq | pTerm->prereqRight; - if( pProbe->tnum<=0 ){ - pNew->wsFlags = savedLoop.wsFlags | WHERE_ROWID_EQ; - }else{ - pNew->wsFlags = savedLoop.wsFlags | WHERE_COLUMN_EQ; + int nIn = 1; + pNew->nEq = savedLoop.nEq; + pNew->nTerm = savedLoop.nTerm; + pNew->aTerm[pNew->nTerm++] = pTerm; + pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~maskSelf; + if( pTerm->eOperator & WO_IN ){ + Expr *pExpr = pTerm->pExpr; + pNew->wsFlags |= WHERE_COLUMN_IN; + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */ + nIn = 25; + }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ + /* "x IN (value, value, ...)" */ + nIn = pExpr->x.pList->nExpr; + } + pNew->nEq++; + pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul * nIn; + }else if( pTerm->eOperator & (WO_EQ|WO_ISNULL) ){ + pNew->wsFlags |= WHERE_COLUMN_EQ; + pNew->nEq++; + pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul; + }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ + pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; + pNew->nOut = savedLoop.nOut/3; + }else if( pTerm->eOperator & (WO_LT|WO_LE) ){ + pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; + pNew->nOut = savedLoop.nOut/3; } + pNew->rRun = pNew->nOut + estLog(pProbe->aiRowEst[0])*nIn; whereLoopInsert(pBuilder->pWInfo, pNew); - if( pNew->nEqnColumn ){ - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul); + if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->nEqnColumn ){ + whereLoopAddBtreeIndex(pBuilder, maskSelf, pSrc, pProbe, nInMul*nIn); } } *pNew = savedLoop; @@ -5222,10 +5256,12 @@ static void whereLoopAddBtree( struct SrcList_item *pSrc; /* The FROM clause btree term to add */ sqlite3 *db; /* The database connection */ WhereLoop *pNew; /* Template WhereLoop object */ + Bitmask maskSelf; /* Mask for iTab */ pNew = pBuilder->pNew; db = pBuilder->db; pSrc = pBuilder->pTabList->a + iTab; + maskSelf = getMask(pBuilder->pWC->pMaskSet, iTab); if( pSrc->pIndex ){ /* An INDEXED BY clause specifies a particular index to use */ @@ -5253,6 +5289,19 @@ static void whereLoopAddBtree( pProbe = &sPk; } + /* Insert a full table scan */ + pNew->iTab = iTab; + pNew->nEq = 0; + pNew->nTerm = 0; + pNew->rSetup = (double)0; + pNew->prereq = 0; + pNew->pIndex = 0; + pNew->wsFlags = 0; + pNew->iOb = pNew->nOb = 0; + pNew->rRun = (double)pSrc->pTab->nRowEst; + pNew->nOut = (double)pSrc->pTab->nRowEst; + whereLoopInsert(pBuilder->pWInfo, pNew); + /* Loop over all indices */ for(; pProbe; pProbe=pProbe->pNext){ @@ -5261,27 +5310,32 @@ static void whereLoopAddBtree( pNew->iTab = iTab; pNew->nEq = 0; pNew->nTerm = 0; + if( pProbe->tnum<=0 ){ + /* Integer primary key index */ + pNew->wsFlags = WHERE_IPK; + }else{ + Bitmask m = pSrc->colUsed; + int j; + for(j=pProbe->nColumn-1; j>=0; j--){ + int x = pProbe->aiColumn[j]; + if( xwsFlags = m==0 ? WHERE_IDX_ONLY : 0; + } paTerm = sqlite3DbRealloc(db, pNew->aTerm, (pProbe->nColumn+1)*sizeof(pNew->aTerm[0])); if( paTerm==0 ) break; pNew->aTerm = paTerm; pNew->pIndex = pProbe; - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); + whereLoopAddBtreeIndex(pBuilder, maskSelf, pSrc, pProbe, 1); /* If there was an INDEXED BY clause, then only that one index is ** considered. */ if( pSrc->pIndex ) break; } - -#if 0 - /* Insert a full table scan */ - pNew->iTab = iTab; - pNew->rSetup = (double)0; - pNew->rRun = (double)1000000; - pNew->nOut = (double)1000000; - whereLoopInsert(pBuilder->pWInfo, pNew); -#endif } /* @@ -5578,16 +5632,16 @@ WhereInfo *sqlite3WhereBegin( struct SrcList_item *pItem = pTabList->a + p->iTab; Table *pTab = pItem->pTab; sqlite3DebugPrintf("%02d.%0*llx", p->iTab, nb, p->prereq); - sqlite3DebugPrintf(" %5s", + sqlite3DebugPrintf(" %6s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( p->pIndex ){ - sqlite3DebugPrintf(".%-5s %2d", p->pIndex->zName, p->nEq); + sqlite3DebugPrintf(".%-8s %2d", p->pIndex->zName, p->nEq); }else{ - sqlite3DebugPrintf("%9s",""); + sqlite3DebugPrintf("%12s",""); } sqlite3DebugPrintf(" fg %08x OB %d,%d N %2d", p->wsFlags, p->iOb, p->nOb, p->nTerm); - sqlite3DebugPrintf(" cost %.2g+%.2g,%.2g\n", + sqlite3DebugPrintf(" cost %.4g,%.4g,%.4g\n", p->prereq, p->rSetup, p->rRun, p->nOut); } } From a18f3d271e52dd964491417cce401dee96449148 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 8 May 2013 03:05:41 +0000 Subject: [PATCH 005/144] Add the NGQP solver. FossilOrigin-Name: 5d37587c50d8932b6357bfd03152a851510a4317 --- manifest | 14 +-- manifest.uuid | 2 +- src/sqliteInt.h | 1 + src/where.c | 273 +++++++++++++++++++++++++++++++++++------------- 4 files changed, 207 insertions(+), 83 deletions(-) diff --git a/manifest b/manifest index c79d6f38fd..53780d9f27 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Continued\sprogress\son\sgenerating\sgood\sWhereLoop\sobjects\sfor\sthe\snew\squery\nplanner. -D 2013-05-07T23:06:23.630 +C Add\sthe\sNGQP\ssolver. +D 2013-05-08T03:05:41.388 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -194,7 +194,7 @@ F src/shell.c 5d527e5d08f05ec2c43ff194ea44bf62b974f4c9 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 0d76a0aa7c64536c6f55d11a8f9f40df0636af6a +F src/sqliteInt.h aee09cf5ee7d5e899246affdd8c3cf58f086ade5 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e957c2c6fd7b421ea6dd1ff11d254c80d0b11638 +F src/where.c cac7c10d422ece684740285366285ef06529796f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P e8881a8b2f25f38bc8ff77619f96f38fe530d13b -R 90f142cd2d5094cb6ddc049cebfe5b6d +P 15cc8a16482777d8e138c4d0863faf8d54fef33a +R 6dc017dbdcd8ab4e7013a1e96308cbfe U drh -Z d9519f5b83b11415ad77247122aa0d25 +Z 6f2b95a5959d577b5b6c3e6985beb9a5 diff --git a/manifest.uuid b/manifest.uuid index 82bc167f3b..379ce7b07e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -15cc8a16482777d8e138c4d0863faf8d54fef33a \ No newline at end of file +5d37587c50d8932b6357bfd03152a851510a4317 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7a405b2fb1..86b123749c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2021,6 +2021,7 @@ struct WhereLevel { Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; double rOptCost; /* "Optimal" cost for this level */ + struct WhereLoop *pWLoop; /* The selected WhereLoop object */ /* The following field is really not part of the current level. But ** we need a place to cache virtual table index information for each diff --git a/src/where.c b/src/where.c index 56568989aa..e87d2ae643 100644 --- a/src/where.c +++ b/src/where.c @@ -53,6 +53,7 @@ typedef struct WhereScan WhereScan; */ struct WhereLoop { Bitmask prereq; /* Bitmask of other loops that must run first */ + Bitmask maskSelf; /* Bitmask identifying table iTab */ int iTab; /* Index of the table coded by this loop */ u16 iOb, nOb; /* ORDER BY terms satisfied by this strategy */ double rSetup; /* One-time setup cost (ex: create transient index) */ @@ -74,9 +75,7 @@ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ double nRow; /* Estimated number of rows generated by this path */ double rCost; /* Total cost of this path */ - WhereLoop *aLoop[1]; /* Array of WhereLoop objects implementing this path */ - WherePath *pNextPath; /* Next path in order of increasing cost */ - WherePath *pPrevPath; /* Previous path in cost order */ + WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ }; /* @@ -5050,6 +5049,30 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */ #endif /* SQLITE_TEST */ +#if defined(SQLITE_DEBUG) \ + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) +/* +** Print a WhereLoop object for debugging purposes +*/ +static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ + int nb = 2*((pTabList->nSrc+15)/16); + struct SrcList_item *pItem = pTabList->a + p->iTab; + Table *pTab = pItem->pTab; + sqlite3DebugPrintf("%02d.%0*llx", p->iTab, nb, p->prereq); + sqlite3DebugPrintf(" %6s", + pItem->zAlias ? pItem->zAlias : pTab->zName); + if( p->pIndex ){ + sqlite3DebugPrintf(".%-8s %2d", p->pIndex->zName, p->nEq); + }else{ + sqlite3DebugPrintf("%12s",""); + } + sqlite3DebugPrintf(" fg %08x OB %d,%d N %2d", + p->wsFlags, p->iOb, p->nOb, p->nTerm); + sqlite3DebugPrintf(" cost %.4g,%.4g,%.4g\n", + p->prereq, p->rSetup, p->rRun, p->nOut); +} +#endif + /* ** Delete a WhereLoop object */ @@ -5102,6 +5125,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ */ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p, *pNext = 0, *pToFree = 0; + WhereTerm **paTerm = 0; sqlite3 *db = pWInfo->pParse->db; /* Search for an existing WhereLoop to overwrite, or which takes @@ -5127,6 +5151,8 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ ){ /* Overwrite an existing WhereLoop with a better one */ sqlite3DbFree(db, p->aTerm); + p->aTerm = 0; + p->nTerm = 0; pNext = p->pNextLoop; break; } @@ -5140,19 +5166,21 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ p = pToFree = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; } + if( pTemplate->nTerm ){ + paTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0])); + if( paTerm==0 ){ + sqlite3DbFree(db, pToFree); + return SQLITE_NOMEM; + } + } *p = *pTemplate; p->pNextLoop = pNext; *ppPrev = p; - p->aTerm = 0; + p->aTerm = paTerm; if( p->pIndex && p->pIndex->tnum==0 ) p->pIndex = 0; - if( pTemplate->nTerm<=0 ) return SQLITE_OK; - p->aTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0])); - if( p->aTerm==0 ){ - p->nTerm = 0; - sqlite3DbFree(db, pToFree); - return SQLITE_NOMEM; + if( pTemplate->nTerm ){ + memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0])); } - memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0])); return SQLITE_OK; } @@ -5165,7 +5193,6 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ */ static void whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ - Bitmask maskSelf, /* Bitmask for table being scanned */ struct SrcList_item *pSrc, /* FROM clause term being analyzed */ Index *pProbe, /* An index on pSrc */ int nInMul /* Number of iterations due to IN */ @@ -5176,6 +5203,7 @@ static void whereLoopAddBtreeIndex( int opMask; /* Valid operators for constraints */ WhereScan scan; /* Iterator for WHERE terms */ WhereLoop savedLoop; /* Saved original content of pNew[] */ + int iCol; /* Index of the column in the table */ db = pBuilder->db; pNew = pBuilder->pNew; @@ -5191,53 +5219,47 @@ static void whereLoopAddBtreeIndex( opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE; } - - if( pNew->nEqnColumn ){ - int iCol; /* Index of the column in the table */ - - - iCol = pProbe->aiColumn[pNew->nEq]; - pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, - opMask, iCol>=0 ? pProbe : 0); - savedLoop = *pNew; - pNew->rSetup = (double)0; - for(; pTerm!=0; pTerm = whereScanNext(&scan)){ - int nIn = 1; - pNew->nEq = savedLoop.nEq; - pNew->nTerm = savedLoop.nTerm; - pNew->aTerm[pNew->nTerm++] = pTerm; - pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~maskSelf; - if( pTerm->eOperator & WO_IN ){ - Expr *pExpr = pTerm->pExpr; - pNew->wsFlags |= WHERE_COLUMN_IN; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */ - nIn = 25; - }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ - /* "x IN (value, value, ...)" */ - nIn = pExpr->x.pList->nExpr; - } - pNew->nEq++; - pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul * nIn; - }else if( pTerm->eOperator & (WO_EQ|WO_ISNULL) ){ - pNew->wsFlags |= WHERE_COLUMN_EQ; - pNew->nEq++; - pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul; - }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ - pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; - pNew->nOut = savedLoop.nOut/3; - }else if( pTerm->eOperator & (WO_LT|WO_LE) ){ - pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; - pNew->nOut = savedLoop.nOut/3; - } - pNew->rRun = pNew->nOut + estLog(pProbe->aiRowEst[0])*nIn; - whereLoopInsert(pBuilder->pWInfo, pNew); - if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->nEqnColumn ){ - whereLoopAddBtreeIndex(pBuilder, maskSelf, pSrc, pProbe, nInMul*nIn); + iCol = pProbe->aiColumn[pNew->nEq]; + pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, + opMask, iCol>=0 ? pProbe : 0); + savedLoop = *pNew; + pNew->rSetup = (double)0; + for(; pTerm!=0; pTerm = whereScanNext(&scan)){ + int nIn = 1; + pNew->nEq = savedLoop.nEq; + pNew->nTerm = savedLoop.nTerm; + pNew->aTerm[pNew->nTerm++] = pTerm; + pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~pNew->maskSelf; + if( pTerm->eOperator & WO_IN ){ + Expr *pExpr = pTerm->pExpr; + pNew->wsFlags |= WHERE_COLUMN_IN; + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */ + nIn = 25; + }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ + /* "x IN (value, value, ...)" */ + nIn = pExpr->x.pList->nExpr; } + pNew->nEq++; + pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul * nIn; + }else if( pTerm->eOperator & (WO_EQ|WO_ISNULL) ){ + pNew->wsFlags |= WHERE_COLUMN_EQ; + pNew->nEq++; + pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul; + }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ + pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; + pNew->nOut = savedLoop.nOut/3; + }else if( pTerm->eOperator & (WO_LT|WO_LE) ){ + pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; + pNew->nOut = savedLoop.nOut/3; + } + pNew->rRun = pNew->nOut + estLog(pProbe->aiRowEst[0])*nIn; + whereLoopInsert(pBuilder->pWInfo, pNew); + if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->nEqnColumn ){ + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul*nIn); } - *pNew = savedLoop; } + *pNew = savedLoop; } /* @@ -5256,12 +5278,11 @@ static void whereLoopAddBtree( struct SrcList_item *pSrc; /* The FROM clause btree term to add */ sqlite3 *db; /* The database connection */ WhereLoop *pNew; /* Template WhereLoop object */ - Bitmask maskSelf; /* Mask for iTab */ pNew = pBuilder->pNew; db = pBuilder->db; pSrc = pBuilder->pTabList->a + iTab; - maskSelf = getMask(pBuilder->pWC->pMaskSet, iTab); + pNew->maskSelf = getMask(pBuilder->pWC->pMaskSet, iTab); if( pSrc->pIndex ){ /* An INDEXED BY clause specifies a particular index to use */ @@ -5330,7 +5351,7 @@ static void whereLoopAddBtree( pNew->aTerm = paTerm; pNew->pIndex = pProbe; - whereLoopAddBtreeIndex(pBuilder, maskSelf, pSrc, pProbe, 1); + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); /* If there was an INDEXED BY clause, then only that one index is ** considered. */ @@ -5360,11 +5381,12 @@ static void whereLoopAddAll(WhereLoopBuilder *pBuilder){ struct SrcList_item *pItem; WhereClause *pWC = pBuilder->pWC; sqlite3 *db = pBuilder->db; + int nTabList = pBuilder->pWInfo->nLevel; /* Loop over the tables in the join, from left to right */ pBuilder->pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); if( pBuilder->pNew==0 ) return; - for(iTab=0, pItem=pTabList->a; iTabnSrc; iTab++, pItem++){ + for(iTab=0, pItem=pTabList->a; iTabpTab) ){ whereLoopAddVirtual(pBuilder, iTab, mExtra); }else{ @@ -5380,6 +5402,107 @@ static void whereLoopAddAll(WhereLoopBuilder *pBuilder){ pBuilder->pNew = 0; } +/* +** Given the list of WhereLoop objects on pWInfo->pLoops, this routine +** attempts to find the lowest cost path that visits each WhereLoop +** once. This path is then loaded into the pWInfo->a[].pWLoop fields. +** +** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation +** error occurs. +*/ +static int wherePathSolver(WhereInfo *pWInfo){ + const int mxChoice = 10; /* Maximum number of simultaneous paths tracked */ + int nLoop; /* Number of terms in the join */ + sqlite3 *db; /* The database connection */ + int iLoop; /* Loop counter over the terms of the join */ + int ii, jj; /* Loop counters */ + double rCost; /* Cost of a path */ + double mxCost; /* Maximum cost of a set of paths */ + int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ + WherePath *aFrom; /* All nFrom paths at the previous level */ + WherePath *aTo; /* The nTo best paths at the current level */ + WherePath *pFrom; /* An element of aFrom[] that we are working on */ + WherePath *pTo; /* An element of aTo[] that we are working on */ + WhereLoop *pWLoop; /* One of the WhereLoop objects */ + WhereLoop **pX; /* Used to divy up the pSpace memory */ + char *pSpace; /* Temporary memory used by this routine */ + + db = pWInfo->pParse->db; + nLoop = pWInfo->nLevel; + assert( nLoop<=pWInfo->pTabList->nSrc ); + + /* Allocate and initialize space for aTo and aFrom */ + ii = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; + pSpace = sqlite3DbMallocRaw(db, ii); + if( pSpace==0 ) return SQLITE_NOMEM; + aTo = (WherePath*)pSpace; + aFrom = aTo+mxChoice; + memset(aFrom, 0, sizeof(aFrom[0])); + pX = (WhereLoop**)(aFrom+mxChoice); + for(ii=0, pFrom=aTo; iiaLoop = pX; + } + + nFrom = 1; + for(iLoop=0; iLooppLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ + Bitmask maskNew; + if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; + if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; + rCost = pWLoop->rSetup + pWLoop->rRun*pFrom->nRow + pFrom->rCost; + maskNew = pFrom->maskLoop | pWLoop->maskSelf; + for(jj=0, pTo=aTo; jjmaskLoop!=maskNew; jj++){} + if( jj>=nTo ){ + if( nTo>=mxChoice && rCost>=mxCost ) continue; + if( nTo=mxCost; jj++){ assert(jj>0); } + } + pTo = &aTo[jj]; + } + pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; + pTo->nRow = pFrom->nRow * pWLoop->nOut; + pTo->rCost = rCost; + memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); + pTo->aLoop[iLoop] = pWLoop; + if( nTo>=mxChoice ){ + mxCost = aTo[0].rCost; + for(jj=1, pTo=&aTo[1]; jjrCost>mxCost ) mxCost = pTo->rCost; + } + } + } + } + + /* Swap the roles of aFrom and aTo in preparation for the next + ** cycle. */ + pFrom = aTo; + aTo = aFrom; + aFrom = pFrom; + nFrom = nTo; + } + + /* TEMPORARY */ + if( nFrom==0 ){ sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } + assert( nFrom>0 ); + + /* Find the lowest cost path and load it into pWInfo->a[].pWLoop */ + pFrom = aFrom; + for(ii=1; iirCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; + } + assert( pWInfo->nLevel==nLoop ); + for(iLoop=0; iLoopa[iLoop].pWLoop = pFrom->aLoop[iLoop]; + } + + /* Free temporary memory and return success */ + sqlite3DbFree(db, pSpace); + return SQLITE_OK; +} /* ** Generate the beginning of the loop used for WHERE clause processing. @@ -5621,28 +5744,28 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(("*** Optimizer Start ***\n")); whereLoopAddAll(&sWLB); + if( db->mallocFailed ) goto whereBeginError; /* Display all of the WhereLoop objects if wheretrace is enabled */ #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) if( sqlite3WhereTrace ){ WhereLoop *p; - int nb = 2*((nTabList+15)/16); for(p=pWInfo->pLoops; p; p=p->pNextLoop){ - struct SrcList_item *pItem = pTabList->a + p->iTab; - Table *pTab = pItem->pTab; - sqlite3DebugPrintf("%02d.%0*llx", p->iTab, nb, p->prereq); - sqlite3DebugPrintf(" %6s", - pItem->zAlias ? pItem->zAlias : pTab->zName); - if( p->pIndex ){ - sqlite3DebugPrintf(".%-8s %2d", p->pIndex->zName, p->nEq); - }else{ - sqlite3DebugPrintf("%12s",""); - } - sqlite3DebugPrintf(" fg %08x OB %d,%d N %2d", - p->wsFlags, p->iOb, p->nOb, p->nTerm); - sqlite3DebugPrintf(" cost %.4g,%.4g,%.4g\n", - p->prereq, p->rSetup, p->rRun, p->nOut); + whereLoopPrint(p, pTabList); + } + } +#endif + + wherePathSolver(pWInfo); + if( db->mallocFailed ) goto whereBeginError; +#if defined(SQLITE_DEBUG) \ + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) + if( sqlite3WhereTrace ){ + int ii; + sqlite3DebugPrintf("------------ Solution ----------------\n"); + for(ii=0; iia[ii].pWLoop, pTabList); } } #endif From f204dac1e33067f056ebb59634d771db53b3ebda Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 8 May 2013 03:22:07 +0000 Subject: [PATCH 006/144] Bug fixes in the solver. FossilOrigin-Name: b36034bbd19bc5677b26a6f60ca96eb2b37db373 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 53780d9f27..7b52c55ce1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sNGQP\ssolver. -D 2013-05-08T03:05:41.388 +C Bug\sfixes\sin\sthe\ssolver. +D 2013-05-08T03:22:07.536 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c cac7c10d422ece684740285366285ef06529796f +F src/where.c 22da73b779e8892a59fcd03835ddf7c3e63a305c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 15cc8a16482777d8e138c4d0863faf8d54fef33a -R 6dc017dbdcd8ab4e7013a1e96308cbfe +P 5d37587c50d8932b6357bfd03152a851510a4317 +R 0e4e284cdf8cf22ac3d57735e7fe3f80 U drh -Z 6f2b95a5959d577b5b6c3e6985beb9a5 +Z bad1f86f1f7d261e6176b4a4726658c0 diff --git a/manifest.uuid b/manifest.uuid index 379ce7b07e..27876fbc73 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5d37587c50d8932b6357bfd03152a851510a4317 \ No newline at end of file +b36034bbd19bc5677b26a6f60ca96eb2b37db373 \ No newline at end of file diff --git a/src/where.c b/src/where.c index e87d2ae643..abd99f5a84 100644 --- a/src/where.c +++ b/src/where.c @@ -5443,6 +5443,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ pFrom->aLoop = pX; } + aFrom[0].nRow = (double)1; nFrom = 1; for(iLoop=0; iLoop=mxCost; jj++){ assert(jj>0); } } pTo = &aTo[jj]; + }else{ + if( pTo->rCost<=rCost ) continue; } pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; pTo->nRow = pFrom->nRow * pWLoop->nOut; @@ -5477,6 +5480,19 @@ static int wherePathSolver(WhereInfo *pWInfo){ } } +#if 0 + if( sqlite3WhereTrace ){ + sqlite3DebugPrintf("---- round %d ---- nTo=%d\n", iLoop, nTo); + for(ii=0; iipTabList); + } + } + } +#endif + /* Swap the roles of aFrom and aTo in preparation for the next ** cycle. */ pFrom = aTo; From a184fb87b8ba04e053454ab2591eb250beea2eb3 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 8 May 2013 04:22:59 +0000 Subject: [PATCH 007/144] More bug fixes to the WhereLoop generator and the solver in NGQP. Now finds the best plan for TPC-H Q8. This seems to prove the concept, but there is still much work to be done. FossilOrigin-Name: 8e5aad37529ec3042e3468acf15186f566e2df8a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 29 ++++++++++++++--------------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index 7b52c55ce1..10086d2469 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bug\sfixes\sin\sthe\ssolver. -D 2013-05-08T03:22:07.536 +C More\sbug\sfixes\sto\sthe\sWhereLoop\sgenerator\sand\sthe\ssolver\sin\sNGQP.\nNow\sfinds\sthe\sbest\splan\sfor\sTPC-H\sQ8.\s\sThis\sseems\sto\sprove\sthe\nconcept,\sbut\sthere\sis\sstill\smuch\swork\sto\sbe\sdone. +D 2013-05-08T04:22:59.354 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 22da73b779e8892a59fcd03835ddf7c3e63a305c +F src/where.c c02037efa641eb9f60f054a52bc4ef3c8230369a F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 5d37587c50d8932b6357bfd03152a851510a4317 -R 0e4e284cdf8cf22ac3d57735e7fe3f80 +P b36034bbd19bc5677b26a6f60ca96eb2b37db373 +R 133717a86de1df991cb6332a4c908d9a U drh -Z bad1f86f1f7d261e6176b4a4726658c0 +Z f247935a6bdcd4102bf6e24d9a3606bf diff --git a/manifest.uuid b/manifest.uuid index 27876fbc73..f6844eb427 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b36034bbd19bc5677b26a6f60ca96eb2b37db373 \ No newline at end of file +8e5aad37529ec3042e3468acf15186f566e2df8a \ No newline at end of file diff --git a/src/where.c b/src/where.c index abd99f5a84..1f198beab4 100644 --- a/src/where.c +++ b/src/where.c @@ -710,15 +710,6 @@ WhereTerm *whereScanNext(WhereScan *pScan){ iColumn = pScan->aEquiv[pScan->iEquiv-1]; while( (pWC = pScan->pWC)!=0 ){ for(pTerm=pWC->a+pScan->k; pScan->knTerm; pScan->k++, pTerm++){ - if( pTerm->iParent>=0 ){ - WhereTerm *pParent = &pWC->a[pTerm->iParent]; - int j; - for(j=pScan->iEquiv-4; j>=0; j-=2 ){ - if( pParent->leftCursor==pScan->aEquiv[j] - && pParent->u.leftColumn==pScan->aEquiv[j+1] ) break; - } - if( j>=0 ) continue; - } if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaEquiv) @@ -754,6 +745,13 @@ WhereTerm *whereScanNext(WhereScan *pScan){ continue; } } + if( (pTerm->eOperator & WO_EQ)!=0 + && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN + && pX->iTable==pScan->aEquiv[0] + && pX->iColumn==pScan->aEquiv[1] + ){ + continue; + } pScan->pCurrent = pTerm; pScan->k++; return pTerm; @@ -5058,13 +5056,14 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ int nb = 2*((pTabList->nSrc+15)/16); struct SrcList_item *pItem = pTabList->a + p->iTab; Table *pTab = pItem->pTab; - sqlite3DebugPrintf("%02d.%0*llx", p->iTab, nb, p->prereq); - sqlite3DebugPrintf(" %6s", + sqlite3DebugPrintf("%2d.%0*llx.%0*llx", + p->iTab, nb, p->maskSelf, nb, p->prereq); + sqlite3DebugPrintf(" %8s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( p->pIndex ){ - sqlite3DebugPrintf(".%-8s %2d", p->pIndex->zName, p->nEq); + sqlite3DebugPrintf(".%-12s %2d", p->pIndex->zName, p->nEq); }else{ - sqlite3DebugPrintf("%12s",""); + sqlite3DebugPrintf("%16s",""); } sqlite3DebugPrintf(" fg %08x OB %d,%d N %2d", p->wsFlags, p->iOb, p->nOb, p->nTerm); @@ -5282,7 +5281,7 @@ static void whereLoopAddBtree( pNew = pBuilder->pNew; db = pBuilder->db; pSrc = pBuilder->pTabList->a + iTab; - pNew->maskSelf = getMask(pBuilder->pWC->pMaskSet, iTab); + pNew->maskSelf = getMask(pBuilder->pWC->pMaskSet, pSrc->iCursor); if( pSrc->pIndex ){ /* An INDEXED BY clause specifies a particular index to use */ @@ -5460,7 +5459,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ if( nTo=mxCost; jj++){ assert(jj>0); } + for(jj=nTo-1; aTo[jj].rCost>=mxCost; jj--){ assert(jj>0); } } pTo = &aTo[jj]; }else{ From 4f58074a8083c751c46165e367601dc95b2e1d12 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 8 May 2013 14:13:51 +0000 Subject: [PATCH 008/144] Fix the wholenumber virtual table so that it returns higher costs for unconstrained usage. FossilOrigin-Name: ceff8955020cd1314bf1ab0af7d075fe2c0863e5 --- ext/misc/wholenumber.c | 8 +++++++- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ext/misc/wholenumber.c b/ext/misc/wholenumber.c index a6d79507c4..63369c6ac4 100644 --- a/ext/misc/wholenumber.c +++ b/ext/misc/wholenumber.c @@ -218,7 +218,13 @@ static int wholenumberBestIndex( ){ pIdxInfo->orderByConsumed = 1; } - pIdxInfo->estimatedCost = (double)1; + if( (idxNum & 12)==0 ){ + pIdxInfo->estimatedCost = (double)100000000; + }else if( (idxNum & 3)==0 ){ + pIdxInfo->estimatedCost = (double)5; + }else{ + pIdxInfo->estimatedCost = (double)1; + } return SQLITE_OK; } diff --git a/manifest b/manifest index 10086d2469..1b4299d8c9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\sbug\sfixes\sto\sthe\sWhereLoop\sgenerator\sand\sthe\ssolver\sin\sNGQP.\nNow\sfinds\sthe\sbest\splan\sfor\sTPC-H\sQ8.\s\sThis\sseems\sto\sprove\sthe\nconcept,\sbut\sthere\sis\sstill\smuch\swork\sto\sbe\sdone. -D 2013-05-08T04:22:59.354 +C Fix\sthe\swholenumber\svirtual\stable\sso\sthat\sit\sreturns\shigher\scosts\sfor\nunconstrained\susage. +D 2013-05-08T14:13:51.196 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -90,7 +90,7 @@ F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556 F ext/misc/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e F ext/misc/regexp.c c25c65fe775f5d9801fb8573e36ebe73f2c0c2e0 F ext/misc/spellfix.c f9d24a2b2617cee143b7841b453e4e1fd8f189cc -F ext/misc/wholenumber.c ce362368b9381ea48cbd951ade8df867eeeab014 +F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/rtree.c 757abea591d4ff67c0ff4e8f9776aeda86b18c14 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b36034bbd19bc5677b26a6f60ca96eb2b37db373 -R 133717a86de1df991cb6332a4c908d9a +P 8e5aad37529ec3042e3468acf15186f566e2df8a +R b3d674751906663b092b90a1bf5d9075 U drh -Z f247935a6bdcd4102bf6e24d9a3606bf +Z ebd03db274e88f39387d4aac452cd0be diff --git a/manifest.uuid b/manifest.uuid index f6844eb427..3eb60dca2b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8e5aad37529ec3042e3468acf15186f566e2df8a \ No newline at end of file +ceff8955020cd1314bf1ab0af7d075fe2c0863e5 \ No newline at end of file From 5346e95ddaf7bcd3b71effe47bfdb22461fa8a12 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 8 May 2013 14:14:26 +0000 Subject: [PATCH 009/144] NGQP working with virtualt tables, though many legacy tests fail and there are yet some memory leaks. FossilOrigin-Name: bd9327a9684b99978734ccd561eea1ad864ab13b --- manifest | 12 +- manifest.uuid | 2 +- src/where.c | 303 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 259 insertions(+), 58 deletions(-) diff --git a/manifest b/manifest index 1b4299d8c9..45446a4e34 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\swholenumber\svirtual\stable\sso\sthat\sit\sreturns\shigher\scosts\sfor\nunconstrained\susage. -D 2013-05-08T14:13:51.196 +C NGQP\sworking\swith\svirtualt\stables,\sthough\smany\slegacy\stests\sfail\sand\sthere\nare\syet\ssome\smemory\sleaks. +D 2013-05-08T14:14:26.339 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c c02037efa641eb9f60f054a52bc4ef3c8230369a +F src/where.c 409691bea5b1442e7cfdeca004c3f38208585ca4 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 8e5aad37529ec3042e3468acf15186f566e2df8a -R b3d674751906663b092b90a1bf5d9075 +P ceff8955020cd1314bf1ab0af7d075fe2c0863e5 +R 82aea8626061f3b7c0b8cf00cdb63138 U drh -Z ebd03db274e88f39387d4aac452cd0be +Z 1ad6961249f560a4ead02c9a1a345bbe diff --git a/manifest.uuid b/manifest.uuid index 3eb60dca2b..dff7e747b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ceff8955020cd1314bf1ab0af7d075fe2c0863e5 \ No newline at end of file +bd9327a9684b99978734ccd561eea1ad864ab13b \ No newline at end of file diff --git a/src/where.c b/src/where.c index 1f198beab4..41b0e7a488 100644 --- a/src/where.c +++ b/src/where.c @@ -44,6 +44,8 @@ typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; +typedef struct WhereVtabPlan WhereVtabPlan; + /* ** Each instance of this object represents a way of evaluating one @@ -54,15 +56,24 @@ typedef struct WhereScan WhereScan; struct WhereLoop { Bitmask prereq; /* Bitmask of other loops that must run first */ Bitmask maskSelf; /* Bitmask identifying table iTab */ - int iTab; /* Index of the table coded by this loop */ + u16 iTab; /* Index of the table coded by this loop */ + u16 nTerm; /* Number of entries in aTerm[] */ u16 iOb, nOb; /* ORDER BY terms satisfied by this strategy */ double rSetup; /* One-time setup cost (ex: create transient index) */ double rRun; /* Cost of running each loop */ double nOut; /* Estimated number of output rows */ u32 wsFlags; /* WHERE_* flags describing the plan */ - u16 nEq; /* Number of equality constraints */ - u16 nTerm; /* Number of entries in aTerm[] */ - Index *pIndex; /* Index used */ + union { + struct { /* Information for internal btree tables */ + int nEq; /* Number of equality constraints */ + Index *pIndex; /* Index used, or NULL */ + } btree; + struct { /* Information for virtualt tables */ + int idxNum; /* Index number */ + int needFree; /* True if sqlite3_free(idxStr) is needed */ + char *idxStr; /* Index identifier string */ + } vtab; + } u; WhereTerm **aTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ }; @@ -314,7 +325,7 @@ struct WhereLoopBuilder { */ #define WHERE_ROWID_EQ 0x00001000 /* rowid=EXPR or rowid IN (...) */ #define WHERE_ROWID_RANGE 0x00002000 /* rowidEXPR */ -#define WHERE_IPK 0x00004000 /* x is the INTEGER PRIMARY KEY */ +#define WHERE_IPK 0x00008000 /* x is the INTEGER PRIMARY KEY */ #define WHERE_COLUMN_EQ 0x00010000 /* x=EXPR or x IN (...) or x IS NULL */ #define WHERE_COLUMN_RANGE 0x00020000 /* xEXPR */ #define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */ @@ -333,6 +344,7 @@ struct WhereLoopBuilder { #define WHERE_OB_UNIQUE 0x00004000 /* Values in ORDER BY columns are ** different for every output row */ #define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */ +#define WHERE_FREEIDXSTR 0x04000000 /* neeed to free WhereLoop.u.idxStr */ #define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */ #define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */ #define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */ @@ -2218,11 +2230,12 @@ static void constructAutomaticIndex( ** responsibility of the caller to eventually release the structure ** by passing the pointer returned by this function to sqlite3_free(). */ -static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){ - Parse *pParse = p->pParse; - WhereClause *pWC = p->pWC; - struct SrcList_item *pSrc = p->pSrc; - ExprList *pOrderBy = p->pOrderBy; +static sqlite3_index_info *allocateIndexInfo( + Parse *pParse, + WhereClause *pWC, + struct SrcList_item *pSrc, + ExprList *pOrderBy +){ int i, j; int nTerm; struct sqlite3_index_constraint *pIdxCons; @@ -2411,7 +2424,7 @@ static void bestVirtualIndex(WhereBestIdx *p){ */ pIdxInfo = *p->ppIdxInfo; if( pIdxInfo==0 ){ - *p->ppIdxInfo = pIdxInfo = allocateIndexInfo(p); + *p->ppIdxInfo = pIdxInfo = allocateIndexInfo(pParse,pWC,pSrc,p->pOrderBy); } if( pIdxInfo==0 ){ return; @@ -5060,10 +5073,22 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ p->iTab, nb, p->maskSelf, nb, p->prereq); sqlite3DebugPrintf(" %8s", pItem->zAlias ? pItem->zAlias : pTab->zName); - if( p->pIndex ){ - sqlite3DebugPrintf(".%-12s %2d", p->pIndex->zName, p->nEq); + if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + if( p->u.btree.pIndex ){ + sqlite3DebugPrintf(".%-12s %2d", + p->u.btree.pIndex->zName, p->u.btree.nEq); + }else{ + sqlite3DebugPrintf("%16s",""); + } }else{ - sqlite3DebugPrintf("%16s",""); + char *z; + if( p->u.vtab.idxStr ){ + z = sqlite3_mprintf("(%d,\"%s\")", p->u.vtab.idxNum,p->u.vtab.idxStr); + }else{ + z = sqlite3_mprintf("(%d)", p->u.vtab.idxNum); + } + sqlite3DebugPrintf(" %-15s", z); + sqlite3_free(z); } sqlite3DebugPrintf(" fg %08x OB %d,%d N %2d", p->wsFlags, p->iOb, p->nOb, p->nTerm); @@ -5072,11 +5097,25 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ } #endif +/* +** Deallocate internal memory used by a WhereLoop object +*/ +static void whereLoopClear(sqlite3 *db, WhereLoop *p){ + sqlite3DbFree(db, p->aTerm); + p->aTerm = 0; + p->nTerm = 0; + if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ + if( p->u.vtab.needFree ) sqlite3_free(p->u.vtab.idxStr); + p->u.vtab.needFree = 0; + p->u.vtab.idxStr = 0; + } +} + /* ** Delete a WhereLoop object */ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ - sqlite3DbFree(db, p->aTerm); + whereLoopClear(db, p); sqlite3DbFree(db, p); } @@ -5149,10 +5188,8 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ && p->rRun>=pTemplate->rRun ){ /* Overwrite an existing WhereLoop with a better one */ - sqlite3DbFree(db, p->aTerm); - p->aTerm = 0; - p->nTerm = 0; pNext = p->pNextLoop; + whereLoopClear(db, p); break; } } @@ -5176,21 +5213,25 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ p->pNextLoop = pNext; *ppPrev = p; p->aTerm = paTerm; - if( p->pIndex && p->pIndex->tnum==0 ) p->pIndex = 0; if( pTemplate->nTerm ){ memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0])); } + if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + if( p->u.btree.pIndex && p->u.btree.pIndex->tnum==0 ) p->u.btree.pIndex = 0; + }else{ + pTemplate->u.vtab.needFree = 0; + } return SQLITE_OK; } /* -** We have so far matched pBuilder->pNew->nEq terms of the index pIndex. +** We have so far matched pBuilder->pNew->u.btree.nEq terms of the index pIndex. ** Try to match one more. ** ** If pProbe->tnum==0, that means pIndex is a fake index used for the ** INTEGER PRIMARY KEY. */ -static void whereLoopAddBtreeIndex( +static int whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ struct SrcList_item *pSrc, /* FROM clause term being analyzed */ Index *pProbe, /* An index on pSrc */ @@ -5203,12 +5244,14 @@ static void whereLoopAddBtreeIndex( WhereScan scan; /* Iterator for WHERE terms */ WhereLoop savedLoop; /* Saved original content of pNew[] */ int iCol; /* Index of the column in the table */ + int rc = SQLITE_OK; /* Return code */ db = pBuilder->db; pNew = pBuilder->pNew; - if( db->mallocFailed ) return; + if( db->mallocFailed ) return SQLITE_NOMEM; - assert( pNew->nEqnColumn ); + assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); + assert( pNew->u.btree.nEqnColumn ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; @@ -5218,14 +5261,14 @@ static void whereLoopAddBtreeIndex( opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE; } - iCol = pProbe->aiColumn[pNew->nEq]; + iCol = pProbe->aiColumn[pNew->u.btree.nEq]; pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, iCol>=0 ? pProbe : 0); savedLoop = *pNew; pNew->rSetup = (double)0; - for(; pTerm!=0; pTerm = whereScanNext(&scan)){ + for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ int nIn = 1; - pNew->nEq = savedLoop.nEq; + pNew->u.btree.nEq = savedLoop.u.btree.nEq; pNew->nTerm = savedLoop.nTerm; pNew->aTerm[pNew->nTerm++] = pTerm; pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~pNew->maskSelf; @@ -5239,12 +5282,12 @@ static void whereLoopAddBtreeIndex( /* "x IN (value, value, ...)" */ nIn = pExpr->x.pList->nExpr; } - pNew->nEq++; - pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul * nIn; + pNew->u.btree.nEq++; + pNew->nOut = (double)pProbe->aiRowEst[pNew->u.btree.nEq] * nInMul * nIn; }else if( pTerm->eOperator & (WO_EQ|WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; - pNew->nEq++; - pNew->nOut = (double)pProbe->aiRowEst[pNew->nEq] * nInMul; + pNew->u.btree.nEq++; + pNew->nOut = (double)pProbe->aiRowEst[pNew->u.btree.nEq] * nInMul; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pNew->nOut = savedLoop.nOut/3; @@ -5253,19 +5296,22 @@ static void whereLoopAddBtreeIndex( pNew->nOut = savedLoop.nOut/3; } pNew->rRun = pNew->nOut + estLog(pProbe->aiRowEst[0])*nIn; - whereLoopInsert(pBuilder->pWInfo, pNew); - if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->nEqnColumn ){ + rc = whereLoopInsert(pBuilder->pWInfo, pNew); + if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 + && pNew->u.btree.nEqnColumn + ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul*nIn); } } *pNew = savedLoop; + return rc; } /* ** Add all WhereLoop objects for the iTab-th table of the join. That ** table is guaranteed to be a b-tree table, not a virtual table. */ -static void whereLoopAddBtree( +static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ int iTab, /* The table to process */ Bitmask mExtra /* Extra prerequesites for using this table */ @@ -5277,6 +5323,7 @@ static void whereLoopAddBtree( struct SrcList_item *pSrc; /* The FROM clause btree term to add */ sqlite3 *db; /* The database connection */ WhereLoop *pNew; /* Template WhereLoop object */ + int rc = SQLITE_OK; /* Return code */ pNew = pBuilder->pNew; db = pBuilder->db; @@ -5311,24 +5358,24 @@ static void whereLoopAddBtree( /* Insert a full table scan */ pNew->iTab = iTab; - pNew->nEq = 0; + pNew->u.btree.nEq = 0; pNew->nTerm = 0; pNew->rSetup = (double)0; pNew->prereq = 0; - pNew->pIndex = 0; + pNew->u.btree.pIndex = 0; pNew->wsFlags = 0; pNew->iOb = pNew->nOb = 0; pNew->rRun = (double)pSrc->pTab->nRowEst; pNew->nOut = (double)pSrc->pTab->nRowEst; - whereLoopInsert(pBuilder->pWInfo, pNew); + rc = whereLoopInsert(pBuilder->pWInfo, pNew); /* Loop over all indices */ - for(; pProbe; pProbe=pProbe->pNext){ + for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext){ WhereTerm **paTerm; pNew->prereq = mExtra; pNew->iTab = iTab; - pNew->nEq = 0; + pNew->u.btree.nEq = 0; pNew->nTerm = 0; if( pProbe->tnum<=0 ){ /* Integer primary key index */ @@ -5345,34 +5392,185 @@ static void whereLoopAddBtree( pNew->wsFlags = m==0 ? WHERE_IDX_ONLY : 0; } paTerm = sqlite3DbRealloc(db, pNew->aTerm, - (pProbe->nColumn+1)*sizeof(pNew->aTerm[0])); - if( paTerm==0 ) break; + (pProbe->nColumn+2)*sizeof(pNew->aTerm[0])); + if( paTerm==0 ){ rc = SQLITE_NOMEM; break; } pNew->aTerm = paTerm; - pNew->pIndex = pProbe; + pNew->u.btree.pIndex = pProbe; - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); + rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); /* If there was an INDEXED BY clause, then only that one index is ** considered. */ if( pSrc->pIndex ) break; } + return rc; } /* ** Add all WhereLoop objects for the iTab-th table of the join. That ** table is guaranteed to be a virtual table. */ -static void whereLoopAddVirtual( +static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ int iTab, /* The table to process */ Bitmask mExtra /* Extra prerequesites for using this table */ ){ + Parse *pParse; /* The parsing context */ + WhereClause *pWC; /* The WHERE clause */ + struct SrcList_item *pSrc; /* The FROM clause term to search */ + Table *pTab; + sqlite3 *db; + sqlite3_index_info *pIdxInfo; + struct sqlite3_index_constraint *pIdxCons; + struct sqlite3_index_constraint_usage *pUsage; + WhereTerm *pTerm; + int i, j; + int iTerm, mxTerm; + int seenIn = 0; /* True if an IN operator is seen */ + int seenVar = 0; /* True if a non-constant constraint is seen */ + int iPhase; /* 0: const w/o IN, 1: const, 2: no IN, 2: IN */ + WhereLoop *pNew; + WhereTerm **paTerm; + int rc = SQLITE_OK; + + pParse = pBuilder->pParse; + db = pParse->db; + pWC = pBuilder->pWC; + pSrc = &pBuilder->pTabList->a[iTab]; + pTab = pSrc->pTab; + pNew = pBuilder->pNew; + pIdxInfo = allocateIndexInfo(pParse,pWC,pSrc,pBuilder->pOrderBy); + if( pIdxInfo==0 ) return SQLITE_NOMEM; + paTerm = sqlite3DbRealloc(db, pNew->aTerm, + pIdxInfo->nConstraint*sizeof(pNew->aTerm[0])); + if( paTerm==0 ) return SQLITE_NOMEM; + pNew->aTerm = paTerm; + pNew->prereq = 0; + pNew->iTab = iTab; + pNew->maskSelf = getMask(pBuilder->pWC->pMaskSet, pSrc->iCursor); + pNew->iOb = 0; + pNew->nOb = 0; + pNew->rSetup = 0; + pNew->wsFlags = WHERE_VIRTUALTABLE; + pNew->nTerm = 0; + pNew->u.vtab.needFree = 0; + pUsage = pIdxInfo->aConstraintUsage; + + for(iPhase=0; iPhase<=2; iPhase++){ + if( !seenIn && (iPhase&1)!=0 ){ + iPhase++; + if( iPhase>3 ) break; + } + if( !seenVar && iPhase>1 ) break; + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pIdxCons++){ + j = pIdxCons->iTermOffset; + pTerm = &pWC->a[j]; + switch( iPhase ){ + case 0: /* Constants without IN operator */ + pIdxCons->usable = 0; + if( (pTerm->eOperator & WO_IN)!=0 ){ + seenIn = 1; + }else if( pTerm->prereqRight!=0 ){ + seenVar = 1; + }else{ + pIdxCons->usable = 1; + } + break; + case 1: /* Constants with IN operators */ + assert( seenIn ); + pIdxCons->usable = (pTerm->prereqRight==0); + break; + case 2: /* Variables without IN */ + assert( seenVar ); + pIdxCons->usable = (pTerm->eOperator & WO_IN)==0; + break; + default: /* Variables with IN */ + assert( seenVar && seenIn ); + pIdxCons->usable = 1; + break; + } + } + memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); + if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr); + pIdxInfo->idxStr = 0; + pIdxInfo->idxNum = 0; + pIdxInfo->needToFreeIdxStr = 0; + pIdxInfo->orderByConsumed = 0; + /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ + pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); + rc = vtabBestIndex(pParse, pTab, pIdxInfo); + if( rc ) goto whereLoopAddVtab_exit; + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + pNew->prereq = 0; + for(i=0; inConstraint; i++) pNew->aTerm[i] = 0; + mxTerm = 0; + for(i=0; inConstraint; i++, pIdxCons++){ + if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){ + j = pIdxCons->iTermOffset; + if( iTerm>=pIdxInfo->nConstraint + || j<0 + || j>=pWC->nTerm + || pNew->aTerm[iTerm]!=0 + ){ + rc = SQLITE_ERROR; + sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName); + goto whereLoopAddVtab_exit; + } + pTerm = &pWC->a[j]; + pNew->prereq |= pTerm->prereqRight; + pNew->aTerm[iTerm] = pTerm; + if( iTerm>mxTerm ) mxTerm = iTerm; + if( (pTerm->eOperator & WO_IN)!=0 ){ + if( pUsage[i].omit==0 ){ + /* Do not attempt to use an IN constraint if the virtual table + ** says that the equivalent EQ constraint cannot be safely omitted. + ** If we do attempt to use such a constraint, some rows might be + ** repeated in the output. */ + break; + } + /* A virtual table that is constrained by an IN clause may not + ** consume the ORDER BY clause because (1) the order of IN terms + ** 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; + } + } + } + if( i>=pIdxInfo->nConstraint ){ + pNew->nTerm = mxTerm+1; + pNew->u.vtab.idxNum = pIdxInfo->idxNum; + pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; + pIdxInfo->needToFreeIdxStr = 0; + pNew->u.vtab.idxStr = pIdxInfo->idxStr; + pNew->iOb = 0; + if( pIdxInfo->orderByConsumed ){ + pNew->nOb = (u16)(pIdxInfo->nOrderBy&0xffff); + }else{ + pNew->nOb = 0; + } + pNew->rSetup = (double)0; + pNew->rRun = pIdxInfo->estimatedCost; + pNew->nOut = (double)25; + whereLoopInsert(pBuilder->pWInfo, pNew); + if( pNew->u.vtab.needFree ){ + sqlite3_free(pNew->u.vtab.idxStr); + pNew->u.vtab.needFree = 0; + } + } + } + +whereLoopAddVtab_exit: + if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr); + sqlite3DbFree(db, pIdxInfo); + return rc; } /* ** Add all WhereLoop objects for all tables */ -static void whereLoopAddAll(WhereLoopBuilder *pBuilder){ +static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ Bitmask mExtra = 0; Bitmask mPrior = 0; int iTab; @@ -5381,24 +5579,26 @@ static void whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereClause *pWC = pBuilder->pWC; sqlite3 *db = pBuilder->db; int nTabList = pBuilder->pWInfo->nLevel; + int rc = SQLITE_OK; /* Loop over the tables in the join, from left to right */ pBuilder->pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); - if( pBuilder->pNew==0 ) return; + if( pBuilder->pNew==0 ) return SQLITE_NOMEM; for(iTab=0, pItem=pTabList->a; iTabpTab) ){ - whereLoopAddVirtual(pBuilder, iTab, mExtra); + rc = whereLoopAddVirtual(pBuilder, iTab, mExtra); }else{ - whereLoopAddBtree(pBuilder, iTab, mExtra); + rc = whereLoopAddBtree(pBuilder, iTab, mExtra); } mPrior |= getMask(pWC->pMaskSet, pItem->iCursor); if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ mExtra = mPrior; } - if( db->mallocFailed ) break; + if( rc || db->mallocFailed ) break; } whereLoopDelete(db, pBuilder->pNew); pBuilder->pNew = 0; + return rc; } /* @@ -5501,7 +5701,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ } /* TEMPORARY */ - if( nFrom==0 ){ sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } +// if( nFrom==0 ){ sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } assert( nFrom>0 ); /* Find the lowest cost path and load it into pWInfo->a[].pWLoop */ @@ -5629,6 +5829,7 @@ WhereInfo *sqlite3WhereBegin( int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */ int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ + int rc; /* Return code */ /* Variable initialization */ @@ -5758,8 +5959,8 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(("*** Optimizer Start ***\n")); - whereLoopAddAll(&sWLB); - if( db->mallocFailed ) goto whereBeginError; + rc = whereLoopAddAll(&sWLB); + if( rc ) goto whereBeginError; /* Display all of the WhereLoop objects if wheretrace is enabled */ #if defined(SQLITE_DEBUG) \ From c718f1c894b0e0b0bd6d44e9a4e1412fa3e7abfa Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 8 May 2013 20:05:58 +0000 Subject: [PATCH 010/144] Fix memory leaks in the NGQP logic for virtual tables. FossilOrigin-Name: 3c2e83a4a2c5e85202162feeb37ef7a3911c05a3 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 13 ++++++++----- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 45446a4e34..cead004f71 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C NGQP\sworking\swith\svirtualt\stables,\sthough\smany\slegacy\stests\sfail\sand\sthere\nare\syet\ssome\smemory\sleaks. -D 2013-05-08T14:14:26.339 +C Fix\smemory\sleaks\sin\sthe\sNGQP\slogic\sfor\svirtual\stables. +D 2013-05-08T20:05:58.332 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 409691bea5b1442e7cfdeca004c3f38208585ca4 +F src/where.c e2e0ff816591684ff74bef65fae747cc57cee335 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ceff8955020cd1314bf1ab0af7d075fe2c0863e5 -R 82aea8626061f3b7c0b8cf00cdb63138 +P bd9327a9684b99978734ccd561eea1ad864ab13b +R 08bf850cd4f323af143e8919e5b89b44 U drh -Z 1ad6961249f560a4ead02c9a1a345bbe +Z 89b960e01fe84155abc15edf55ac2ba0 diff --git a/manifest.uuid b/manifest.uuid index dff7e747b9..6cc7d9d5c8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bd9327a9684b99978734ccd561eea1ad864ab13b \ No newline at end of file +3c2e83a4a2c5e85202162feeb37ef7a3911c05a3 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 41b0e7a488..6d7805dfdd 100644 --- a/src/where.c +++ b/src/where.c @@ -5442,8 +5442,11 @@ static int whereLoopAddVirtual( pIdxInfo = allocateIndexInfo(pParse,pWC,pSrc,pBuilder->pOrderBy); if( pIdxInfo==0 ) return SQLITE_NOMEM; paTerm = sqlite3DbRealloc(db, pNew->aTerm, - pIdxInfo->nConstraint*sizeof(pNew->aTerm[0])); - if( paTerm==0 ) return SQLITE_NOMEM; + (pIdxInfo->nConstraint+1)*sizeof(pNew->aTerm[0])); + if( paTerm==0 ){ + sqlite3DbFree(db, pIdxInfo); + return SQLITE_NOMEM; + } pNew->aTerm = paTerm; pNew->prereq = 0; pNew->iTab = iTab; @@ -5504,7 +5507,7 @@ static int whereLoopAddVirtual( pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pNew->prereq = 0; for(i=0; inConstraint; i++) pNew->aTerm[i] = 0; - mxTerm = 0; + mxTerm = -1; for(i=0; inConstraint; i++, pIdxCons++){ if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){ j = pIdxCons->iTermOffset; @@ -5659,7 +5662,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ if( nTo=mxCost; jj--){ assert(jj>0); } + for(jj=nTo-1; aTo[jj].rCost0); } } pTo = &aTo[jj]; }else{ @@ -5701,7 +5704,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ } /* TEMPORARY */ -// if( nFrom==0 ){ sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } + if( nFrom==0 ){ sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } assert( nFrom>0 ); /* Find the lowest cost path and load it into pWInfo->a[].pWLoop */ From 6b7157bbd5183960c8dd6a6214b33163d9122bb7 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 10 May 2013 02:00:35 +0000 Subject: [PATCH 011/144] Free up bits of wsFlags for reuse. Install the ORDER BY optimization infrastructure for the NGQP. FossilOrigin-Name: 82d50e198025a2fdb8ee733edb8419d388ee5362 --- manifest | 14 ++-- manifest.uuid | 2 +- src/sqliteInt.h | 3 + src/where.c | 190 ++++++++++++++++++++++++++++++++---------------- 4 files changed, 139 insertions(+), 70 deletions(-) diff --git a/manifest b/manifest index cead004f71..70d136a298 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\smemory\sleaks\sin\sthe\sNGQP\slogic\sfor\svirtual\stables. -D 2013-05-08T20:05:58.332 +C Free\sup\sbits\sof\swsFlags\sfor\sreuse.\s\sInstall\sthe\sORDER\sBY\soptimization\ninfrastructure\sfor\sthe\sNGQP. +D 2013-05-10T02:00:35.314 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -194,7 +194,7 @@ F src/shell.c 5d527e5d08f05ec2c43ff194ea44bf62b974f4c9 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h aee09cf5ee7d5e899246affdd8c3cf58f086ade5 +F src/sqliteInt.h b4411cfc1c7803cdf393975d5420b4da0d8dd1c4 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -263,7 +263,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e2e0ff816591684ff74bef65fae747cc57cee335 +F src/where.c 2be67c1a1a018b1de91f08e48baa02db13652e40 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1060,7 +1060,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P bd9327a9684b99978734ccd561eea1ad864ab13b -R 08bf850cd4f323af143e8919e5b89b44 +P 3c2e83a4a2c5e85202162feeb37ef7a3911c05a3 +R fe9c54bd236af22a2f9e27cec8708db5 U drh -Z 89b960e01fe84155abc15edf55ac2ba0 +Z c9a2e102e5146d5a293863d252ad4424 diff --git a/manifest.uuid b/manifest.uuid index 6cc7d9d5c8..5c1c65ebf9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3c2e83a4a2c5e85202162feeb37ef7a3911c05a3 \ No newline at end of file +82d50e198025a2fdb8ee733edb8419d388ee5362 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 86b123749c..08ecfa78d1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2045,6 +2045,7 @@ struct WhereLevel { #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ +#define WHREE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ /* ** The WHERE clause processing routine has two halves. The @@ -2056,6 +2057,8 @@ struct WhereLevel { struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ + ExprList *pOrderBy; /* The ORDER BY clause or NULL */ + ExprList *pDistinct; /* DISTINCT ON values, or NULL */ u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ diff --git a/src/where.c b/src/where.c index 6d7805dfdd..56ca3e75aa 100644 --- a/src/where.c +++ b/src/where.c @@ -50,7 +50,7 @@ typedef struct WhereVtabPlan WhereVtabPlan; /* ** Each instance of this object represents a way of evaluating one ** term of a join. The WhereClause object holds a table of these -** objects using (iTab,prereq,iOb,nOb) as the primary key. Note that the +** objects using (maskSelf,prereq,) as the primary key. Note that the ** same join term might have multiple associated WhereLoop objects. */ struct WhereLoop { @@ -58,19 +58,19 @@ struct WhereLoop { Bitmask maskSelf; /* Bitmask identifying table iTab */ u16 iTab; /* Index of the table coded by this loop */ u16 nTerm; /* Number of entries in aTerm[] */ - u16 iOb, nOb; /* ORDER BY terms satisfied by this strategy */ + u32 wsFlags; /* WHERE_* flags describing the plan */ double rSetup; /* One-time setup cost (ex: create transient index) */ double rRun; /* Cost of running each loop */ double nOut; /* Estimated number of output rows */ - u32 wsFlags; /* WHERE_* flags describing the plan */ union { struct { /* Information for internal btree tables */ int nEq; /* Number of equality constraints */ Index *pIndex; /* Index used, or NULL */ } btree; - struct { /* Information for virtualt tables */ + struct { /* Information for virtual tables */ int idxNum; /* Index number */ - int needFree; /* True if sqlite3_free(idxStr) is needed */ + u8 needFree; /* True if sqlite3_free(idxStr) is needed */ + u8 isOrdered; /* True if satisfies ORDER BY */ char *idxStr; /* Index identifier string */ } vtab; } u; @@ -86,6 +86,8 @@ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ double nRow; /* Estimated number of rows generated by this path */ double rCost; /* Total cost of this path */ + u8 isOrdered; /* True if this path satisfies ORDER BY */ + u8 isOrderedValid; /* True if the isOrdered field is valid */ WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ }; @@ -314,41 +316,34 @@ struct WhereLoopBuilder { ** Value for wsFlags returned by bestIndex() and stored in ** WhereLevel.wsFlags. These flags determine which search ** strategies are appropriate. -** -** The least significant 12 bits is reserved as a mask for WO_ values above. -** The WhereLevel.wsFlags field is usually set to WO_IN|WO_EQ|WO_ISNULL. -** But if the table is the right table of a left join, WhereLevel.wsFlags -** is set to WO_IN|WO_EQ. The WhereLevel.wsFlags field can then be used as -** the "op" parameter to findTerm when we are resolving equality constraints. -** ISNULL constraints will then not be used on the right table of a left -** join. Tickets #2177 and #2189. */ -#define WHERE_ROWID_EQ 0x00001000 /* rowid=EXPR or rowid IN (...) */ -#define WHERE_ROWID_RANGE 0x00002000 /* rowidEXPR */ -#define WHERE_IPK 0x00008000 /* x is the INTEGER PRIMARY KEY */ -#define WHERE_COLUMN_EQ 0x00010000 /* x=EXPR or x IN (...) or x IS NULL */ -#define WHERE_COLUMN_RANGE 0x00020000 /* xEXPR */ -#define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */ -#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */ -#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */ -#define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */ -#define WHERE_IN_ABLE 0x080f1000 /* Able to support an IN operator */ -#define WHERE_TOP_LIMIT 0x00100000 /* xEXPR or x>=EXPR constraint */ -#define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and xEXPR */ +#define WHERE_NULL_OK 0x00000004 /* Ok to use WO_ISNULL */ +#define WHERE_IPK 0x00000008 /* x is the INTEGER PRIMARY KEY */ +#define WHERE_COLUMN_EQ 0x00000010 /* x=EXPR or x IN (...) or x IS NULL */ +#define WHERE_COLUMN_RANGE 0x00000020 /* xEXPR */ +#define WHERE_COLUMN_IN 0x00000040 /* x IN (...) */ +#define WHERE_COLUMN_NULL 0x00000080 /* x IS NULL */ +#define WHERE_INDEXED 0x000000f0 /* Anything that uses an index */ +#define WHERE_NOT_FULLSCAN 0x000200f3 /* Does not do a full table scan */ +#define WHERE_IN_ABLE 0x000100f1 /* Able to support an IN operator */ +#define WHERE_TOP_LIMIT 0x00000100 /* xEXPR or x>=EXPR constraint */ +#define WHERE_BOTH_LIMIT 0x00000300 /* Both x>EXPR and xu.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; - int flags = WHERE_MULTI_OR; double rTotal = 0; double nRow = 0; Bitmask used = 0; @@ -1967,7 +1961,7 @@ static void bestOrClauseIndex(WhereBestIdx *p){ p->cost.used = used; p->cost.plan.nRow = nRow; p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0; - p->cost.plan.wsFlags = flags; + p->cost.plan.wsFlags = WHERE_MULTI_OR; p->cost.plan.u.pTerm = pTerm; } } @@ -2149,7 +2143,7 @@ static void constructAutomaticIndex( if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){ nColumn += pTable->nCol - BMS + 1; } - pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WO_EQ; + pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY; /* Construct the Index object to describe this index */ nByte = sizeof(Index); @@ -3815,7 +3809,7 @@ static void bestBtreeIndex(WhereBestIdx *p){ bestOrClauseIndex(p); bestAutomaticIndex(p); - p->cost.plan.wsFlags |= eqTermMask; + if( eqTermMask & WO_ISNULL ) p->cost.plan.wsFlags |= WHERE_NULL_OK; } /* @@ -4066,6 +4060,7 @@ static int codeAllEqualityTerms( int regBase; /* Base register */ int nReg; /* Number of registers to allocate */ char *zAff; /* Affinity string to return */ + int eqFlags; /* WO_EQ|WO_IN and maybe also WO_ISNULL */ /* This module is only called on query plans that use an index. */ assert( pLevel->plan.wsFlags & WHERE_INDEXED ); @@ -4085,10 +4080,12 @@ static int codeAllEqualityTerms( /* Evaluate the equality constraints */ assert( pIdx->nColumn>=nEq ); + eqFlags = (pLevel->plan.wsFlags&WHERE_NULL_OK) ? (WO_EQ|WO_IN|WO_ISNULL) + : (WO_EQ|WO_IN); for(j=0; jaiColumn[j]; - pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx); + pTerm = findTerm(pWC, iCur, k, notReady, eqFlags, pIdx); if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ @@ -5090,8 +5087,7 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ sqlite3DebugPrintf(" %-15s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" fg %08x OB %d,%d N %2d", - p->wsFlags, p->iOb, p->nOb, p->nTerm); + sqlite3DebugPrintf(" fg %08x N %2d", p->wsFlags, p->nTerm); sqlite3DebugPrintf(" cost %.4g,%.4g,%.4g\n", p->prereq, p->rSetup, p->rRun, p->nOut); } @@ -5172,8 +5168,6 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ if( p->iTab!=pTemplate->iTab ) continue; if( (p->prereq & pTemplate->prereq)==p->prereq - && p->nOb>=pTemplate->nOb - && p->iOb==pTemplate->iOb && p->rSetup<=pTemplate->rSetup && p->rRun<=pTemplate->rRun ){ @@ -5182,8 +5176,6 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ return SQLITE_OK; } if( (p->prereq & pTemplate->prereq)==pTemplate->prereq - && p->nOb<=pTemplate->nOb - && p->iOb==pTemplate->iOb && p->rSetup>=pTemplate->rSetup && p->rRun>=pTemplate->rRun ){ @@ -5364,7 +5356,6 @@ static int whereLoopAddBtree( pNew->prereq = 0; pNew->u.btree.pIndex = 0; pNew->wsFlags = 0; - pNew->iOb = pNew->nOb = 0; pNew->rRun = (double)pSrc->pTab->nRowEst; pNew->nOut = (double)pSrc->pTab->nRowEst; rc = whereLoopInsert(pBuilder->pWInfo, pNew); @@ -5451,8 +5442,6 @@ static int whereLoopAddVirtual( pNew->prereq = 0; pNew->iTab = iTab; pNew->maskSelf = getMask(pBuilder->pWC->pMaskSet, pSrc->iCursor); - pNew->iOb = 0; - pNew->nOb = 0; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; pNew->nTerm = 0; @@ -5547,12 +5536,7 @@ static int whereLoopAddVirtual( pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; - pNew->iOb = 0; - if( pIdxInfo->orderByConsumed ){ - pNew->nOb = (u16)(pIdxInfo->nOrderBy&0xffff); - }else{ - pNew->nOb = 0; - } + pNew->u.vtab.isOrdered = (u8)(pIdxInfo->nOrderBy!=0); pNew->rSetup = (double)0; pNew->rRun = pIdxInfo->estimatedCost; pNew->nOut = (double)25; @@ -5604,6 +5588,29 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ return rc; } +/* +** Examine a WherePath to see if it outputs rows in the requested ORDER BY +** (or GROUP BY) without requiring a separate source operation. Return 1 +** if it does and 0 if it does not and -1 if we cannot tell. +*/ +static int wherePathSatisfiesOrderBy( + WhereInfo *pWInfo, /* The WHERE clause */ + WherePath *pPath, /* The WherePath to check */ + int nLoop, /* Number of entries in pPath->aLoop[] */ + WhereLoop *pLoop /* Add this WhereLoop to the end of pPath->aLoop[] */ +){ + if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ + return nLoop==0 && pLoop->u.vtab.isOrdered; + }else{ + /* TBD: Check to see if pFrom + pWLoop satisfies the ORDER BY. + ** (1) If yes: set isOrderedValid and isOrdered to 1. + ** (2) If no: set isOrderedValid to 1 and isOrdered to 0. + ** (3) unknown: no-op */ + return 0; + } +} + + /* ** Given the list of WhereLoop objects on pWInfo->pLoops, this routine ** attempts to find the lowest cost path that visits each WhereLoop @@ -5620,12 +5627,14 @@ static int wherePathSolver(WhereInfo *pWInfo){ int ii, jj; /* Loop counters */ double rCost; /* Cost of a path */ double mxCost; /* Maximum cost of a set of paths */ + double rSortCost; /* Cost to do a sort */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ WherePath *pFrom; /* An element of aFrom[] that we are working on */ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ + WhereLoop *pNext; /* Next loop */ WhereLoop **pX; /* Used to divy up the pSpace memory */ char *pSpace; /* Temporary memory used by this routine */ @@ -5645,18 +5654,67 @@ static int wherePathSolver(WhereInfo *pWInfo){ pFrom->aLoop = pX; } + /* Seed the search with a single WherePath containing zero WhereLoops */ aFrom[0].nRow = (double)1; nFrom = 1; + + /* Precompute the cost of sorting the final result set, if the caller + ** to sqlite3WhereBegin() was concerned about sorting */ + rSortCost = (double)0; + if( pWInfo->pOrderBy==0 ){ + aFrom[0].isOrderedValid = 1; + }else{ + /* Compute an estimate on the cost to sort the entire result set */ + rSortCost = (double)1; + for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pNext){ + pNext = pWLoop->pNextLoop; + rCost = pWLoop->nOut; + while( pNext && pNext->iTab==pWLoop->iTab ){ + if( pNext->nOutnOut; + pNext = pNext->pNextLoop; + } + rSortCost *= rCost; + } + rSortCost *= estLog(rSortCost); + } + + /* Compute successively longer WherePaths using the previous generation + ** of WherePaths as the basis for the next. Keep track of the mxChoice + ** best paths at each generation */ for(iLoop=0; iLooppLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ Bitmask maskNew; + u8 isOrderedValid = pFrom->isOrderedValid; + u8 isOrdered = pFrom->isOrdered; if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; + /* At this point, pWLoop is a candidate to be the next loop. + ** Compute its cost */ rCost = pWLoop->rSetup + pWLoop->rRun*pFrom->nRow + pFrom->rCost; maskNew = pFrom->maskLoop | pWLoop->maskSelf; - for(jj=0, pTo=aTo; jjmaskLoop!=maskNew; jj++){} + if( !isOrderedValid ){ + switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, pWLoop) ){ + case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ + isOrdered = 1; + isOrderedValid = 1; + break; + case 0: /* No. pFrom+pWLoop will require a separate sort */ + isOrdered = 0; + isOrderedValid = 1; + rCost += rSortCost; + break; + default: /* Cannot tell yet. Try again on the next iteration */ + break; + } + } + /* Check to see if pWLoop should be added to the mxChoice best so far */ + for(jj=0, pTo=aTo; jjmaskLoop==maskNew && pTo->isOrderedValid==isOrderedValid ){ + break; + } + } if( jj>=nTo ){ if( nTo>=mxChoice && rCost>=mxCost ) continue; if( nTorCost<=rCost ) continue; } + /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; pTo->nRow = pFrom->nRow * pWLoop->nOut; pTo->rCost = rCost; + pTo->isOrderedValid = isOrderedValid; + pTo->isOrdered = isOrdered; memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); pTo->aLoop[iLoop] = pWLoop; if( nTo>=mxChoice ){ @@ -5695,8 +5756,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ } #endif - /* Swap the roles of aFrom and aTo in preparation for the next - ** cycle. */ + /* Swap the roles of aFrom and aTo for the next generation */ pFrom = aTo; aTo = aFrom; aFrom = pFrom; @@ -5707,15 +5767,19 @@ static int wherePathSolver(WhereInfo *pWInfo){ if( nFrom==0 ){ sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } assert( nFrom>0 ); - /* Find the lowest cost path and load it into pWInfo->a[].pWLoop */ + /* Find the lowest cost path. pFrom will be left pointing to that path */ pFrom = aFrom; for(ii=1; iirCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; } assert( pWInfo->nLevel==nLoop ); + /* Load the lowest cost path into pWInfo */ for(iLoop=0; iLoopa[iLoop].pWLoop = pFrom->aLoop[iLoop]; } + if( pFrom->isOrdered ){ + pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; + } /* Free temporary memory and return success */ sqlite3DbFree(db, pSpace); @@ -5882,6 +5946,8 @@ WhereInfo *sqlite3WhereBegin( pWInfo->nLevel = nTabList; pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; + pWInfo->pOrderBy = pOrderBy; + pWInfo->pDistinct = pDistinct; pWInfo->iBreak = sqlite3VdbeMakeLabel(v); pWInfo->pWC = sWBI.pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo]; pWInfo->wctrlFlags = wctrlFlags; From b2a90f09b8a7af6d84184d90f3956ea0c884df8f Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 10 May 2013 03:30:49 +0000 Subject: [PATCH 012/144] Factor out common operations into whereLoopAddAll(). Add stubs for missing features. FossilOrigin-Name: 0278e420614e02fb2d8474ed99b0904275882dfe --- manifest | 12 +++++----- manifest.uuid | 2 +- src/where.c | 65 +++++++++++++++++++++++---------------------------- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/manifest b/manifest index 57a0d63001..f81212a36c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sin\sthe\slatest\strunk\schanges. -D 2013-05-10T02:11:40.008 +C Factor\sout\scommon\soperations\sinto\swhereLoopAddAll().\s\sAdd\sstubs\sfor\nmissing\sfeatures. +D 2013-05-10T03:30:49.076 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -264,7 +264,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 4816e3ec624c96b5169f0cc83dbb5cf459ce3fd1 +F src/where.c 31160bacc36e1fa5818caf091d5559d55eae7a5d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1062,7 +1062,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 82d50e198025a2fdb8ee733edb8419d388ee5362 cf5c3642247fdd34d87f0368594cd7b8f081636a -R bed3d93321566d3c8fda15cb3370678a +P 5ed31c8279a4f465b982df5dc20cefc286928b93 +R 6a6b39040b040f90ce4281cc062a3caa U drh -Z 9d7433ee1472cd0008b2ab99b16fa998 +Z ca90367b6425b581381608ce8a76b4fa diff --git a/manifest.uuid b/manifest.uuid index 64be8db9eb..a2c17feaba 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5ed31c8279a4f465b982df5dc20cefc286928b93 \ No newline at end of file +0278e420614e02fb2d8474ed99b0904275882dfe \ No newline at end of file diff --git a/src/where.c b/src/where.c index 26db3b3edf..368081feae 100644 --- a/src/where.c +++ b/src/where.c @@ -5309,7 +5309,6 @@ static int whereLoopAddBtreeIndex( */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - int iTab, /* The table to process */ Bitmask mExtra /* Extra prerequesites for using this table */ ){ Index *pProbe; /* An index we are evaluating */ @@ -5317,14 +5316,11 @@ static int whereLoopAddBtree( tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ struct SrcList_item *pSrc; /* The FROM clause btree term to add */ - sqlite3 *db; /* The database connection */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ pNew = pBuilder->pNew; - db = pBuilder->db; - pSrc = pBuilder->pTabList->a + iTab; - pNew->maskSelf = getMask(pBuilder->pWC->pMaskSet, pSrc->iCursor); + pSrc = pBuilder->pTabList->a + pNew->iTab; if( pSrc->pIndex ){ /* An INDEXED BY clause specifies a particular index to use */ @@ -5353,23 +5349,21 @@ static int whereLoopAddBtree( } /* Insert a full table scan */ - pNew->iTab = iTab; pNew->u.btree.nEq = 0; pNew->nTerm = 0; pNew->rSetup = (double)0; - pNew->prereq = 0; + pNew->prereq = mExtra; pNew->u.btree.pIndex = 0; pNew->wsFlags = 0; pNew->rRun = (double)pSrc->pTab->nRowEst; pNew->nOut = (double)pSrc->pTab->nRowEst; rc = whereLoopInsert(pBuilder->pWInfo, pNew); + /* TBD: Insert automatic index opportunities */ + /* Loop over all indices */ for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext){ - WhereTerm **paTerm; - pNew->prereq = mExtra; - pNew->iTab = iTab; pNew->u.btree.nEq = 0; pNew->nTerm = 0; if( pProbe->tnum<=0 ){ @@ -5386,10 +5380,6 @@ static int whereLoopAddBtree( } pNew->wsFlags = m==0 ? WHERE_IDX_ONLY : 0; } - paTerm = sqlite3DbRealloc(db, pNew->aTerm, - (pProbe->nColumn+2)*sizeof(pNew->aTerm[0])); - if( paTerm==0 ){ rc = SQLITE_NOMEM; break; } - pNew->aTerm = paTerm; pNew->u.btree.pIndex = pProbe; rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); @@ -5407,7 +5397,6 @@ static int whereLoopAddBtree( */ static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - int iTab, /* The table to process */ Bitmask mExtra /* Extra prerequesites for using this table */ ){ Parse *pParse; /* The parsing context */ @@ -5425,27 +5414,17 @@ static int whereLoopAddVirtual( int seenVar = 0; /* True if a non-constant constraint is seen */ int iPhase; /* 0: const w/o IN, 1: const, 2: no IN, 2: IN */ WhereLoop *pNew; - WhereTerm **paTerm; int rc = SQLITE_OK; pParse = pBuilder->pParse; db = pParse->db; pWC = pBuilder->pWC; - pSrc = &pBuilder->pTabList->a[iTab]; - pTab = pSrc->pTab; pNew = pBuilder->pNew; - pIdxInfo = allocateIndexInfo(pParse,pWC,pSrc,pBuilder->pOrderBy); + pSrc = &pBuilder->pTabList->a[pNew->iTab]; + pTab = pSrc->pTab; + pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pBuilder->pOrderBy); if( pIdxInfo==0 ) return SQLITE_NOMEM; - paTerm = sqlite3DbRealloc(db, pNew->aTerm, - (pIdxInfo->nConstraint+1)*sizeof(pNew->aTerm[0])); - if( paTerm==0 ){ - sqlite3DbFree(db, pIdxInfo); - return SQLITE_NOMEM; - } - pNew->aTerm = paTerm; pNew->prereq = 0; - pNew->iTab = iTab; - pNew->maskSelf = getMask(pBuilder->pWC->pMaskSet, pSrc->iCursor); pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; pNew->nTerm = 0; @@ -5571,22 +5550,36 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pBuilder->db; int nTabList = pBuilder->pWInfo->nLevel; int rc = SQLITE_OK; + WhereLoop *pNew; /* Loop over the tables in the join, from left to right */ - pBuilder->pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); - if( pBuilder->pNew==0 ) return SQLITE_NOMEM; + pBuilder->pNew = pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->aTerm = sqlite3DbMallocZero(db, (pWC->nTerm+1)*sizeof(pNew->aTerm[0])); + if( pNew->aTerm==0 ){ + rc = SQLITE_NOMEM; + goto whereLoopAddAll_end; + } for(iTab=0, pItem=pTabList->a; iTabpTab) ){ - rc = whereLoopAddVirtual(pBuilder, iTab, mExtra); - }else{ - rc = whereLoopAddBtree(pBuilder, iTab, mExtra); - } - mPrior |= getMask(pWC->pMaskSet, pItem->iCursor); + pNew->iTab = iTab; + pNew->maskSelf = getMask(pWC->pMaskSet, pItem->iCursor); if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ mExtra = mPrior; } + if( IsVirtual(pItem->pTab) ){ + rc = whereLoopAddVirtual(pBuilder, mExtra); + }else{ + rc = whereLoopAddBtree(pBuilder, mExtra); + } +#if 0 + if( rc==SQLITE_OK ){ + rc = whereLoopAddOr(pBuilder, mExtra); + } +#endif + mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; } +whereLoopAddAll_end: whereLoopDelete(db, pBuilder->pNew); pBuilder->pNew = 0; return rc; From eb04de3224c0f6e5160d8c641bf4dd2c83bb63e8 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 10 May 2013 15:16:30 +0000 Subject: [PATCH 013/144] Update the NGQP so that it can produce plans that include automatic indices. FossilOrigin-Name: 586b55d8d7722de1c0530b3b832bae0511e6d05c --- manifest | 12 ++++----- manifest.uuid | 2 +- src/where.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index f81212a36c..180d5b5b51 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Factor\sout\scommon\soperations\sinto\swhereLoopAddAll().\s\sAdd\sstubs\sfor\nmissing\sfeatures. -D 2013-05-10T03:30:49.076 +C Update\sthe\sNGQP\sso\sthat\sit\scan\sproduce\splans\sthat\sinclude\sautomatic\sindices. +D 2013-05-10T15:16:30.669 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -264,7 +264,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 31160bacc36e1fa5818caf091d5559d55eae7a5d +F src/where.c f96b2602fd2da89873ed5a210608c58bf80d7c0e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1062,7 +1062,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 5ed31c8279a4f465b982df5dc20cefc286928b93 -R 6a6b39040b040f90ce4281cc062a3caa +P 0278e420614e02fb2d8474ed99b0904275882dfe +R 69dec67361636bd352a6f82f3ef9f1cb U drh -Z ca90367b6425b581381608ce8a76b4fa +Z ef95f556fc74affef6b6df28ead69ff3 diff --git a/manifest.uuid b/manifest.uuid index a2c17feaba..0143fae8fc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0278e420614e02fb2d8474ed99b0904275882dfe \ No newline at end of file +586b55d8d7722de1c0530b3b832bae0511e6d05c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 368081feae..40653d7c51 100644 --- a/src/where.c +++ b/src/where.c @@ -289,6 +289,7 @@ struct WhereLoopBuilder { SrcList *pTabList; /* FROM clause */ ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ + int mxTerm; /* Maximum number of aTerm[] entries on pNew */ }; /* @@ -5241,6 +5242,7 @@ static int whereLoopAddBtreeIndex( WhereLoop savedLoop; /* Saved original content of pNew[] */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ + double rLogSize; /* Logarithm of table size */ db = pBuilder->db; pNew = pBuilder->pNew; @@ -5262,10 +5264,12 @@ static int whereLoopAddBtreeIndex( opMask, iCol>=0 ? pProbe : 0); savedLoop = *pNew; pNew->rSetup = (double)0; + rLogSize = estLog(pProbe->aiRowEst[0]); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ int nIn = 1; pNew->u.btree.nEq = savedLoop.u.btree.nEq; pNew->nTerm = savedLoop.nTerm; + if( pNew->nTerm>=pBuilder->mxTerm ) break; /* Repeated column in index */ pNew->aTerm[pNew->nTerm++] = pTerm; pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~pNew->maskSelf; if( pTerm->eOperator & WO_IN ){ @@ -5291,7 +5295,16 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pNew->nOut = savedLoop.nOut/3; } - pNew->rRun = pNew->nOut + estLog(pProbe->aiRowEst[0])*nIn; + pNew->rRun = rLogSize*nIn; /* Cost for nIn binary searches */ + if( pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK) ){ + pNew->rRun += pNew->nOut; /* Unit step cost to reach each row */ + }else{ + /* Each row involves a step of the index, then a binary search of + ** the main table */ + pNew->rRun += pNew->nOut*(1 + rLogSize); + } + /* TBD: Adjust nOut and rRun for STAT3 range values */ + /* TBD: Adjust nOut for additional constraints */ rc = whereLoopInsert(pBuilder->pWInfo, pNew); if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn @@ -5318,6 +5331,8 @@ static int whereLoopAddBtree( struct SrcList_item *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ + double rSize; /* number of rows in the table */ + double rLogSize; /* Logarithm of the number of rows in the table */ pNew = pBuilder->pNew; pSrc = pBuilder->pTabList->a + pNew->iTab; @@ -5347,6 +5362,33 @@ static int whereLoopAddBtree( } pProbe = &sPk; } + rSize = (double)pSrc->pTab->nRowEst; + rLogSize = estLog(rSize); + + /* Automatic indexes */ + if( (pBuilder->pParse->db->flags & SQLITE_AutoIndex)!=0 + && !pSrc->viaCoroutine + && !pSrc->notIndexed + && !pSrc->isCorrelated + ){ + /* Generate auto-index WhereLoops */ + WhereClause *pWC = pBuilder->pWC; + WhereTerm *pTerm; + WhereTerm *pWCEnd = pWC->a + pWC->nTerm; + for(pTerm=pWC->a; rc==SQLITE_OK && pTermu.btree.nEq = 1; + pNew->nTerm = 1; + pNew->aTerm[0] = pTerm; + pNew->rSetup = 2*rLogSize*pSrc->pTab->nRowEst; + pNew->nOut = (double)10; + pNew->rRun = rLogSize + pNew->nOut; + pNew->wsFlags = WHERE_TEMP_INDEX; + pNew->prereq = mExtra | pTerm->prereqRight; + rc = whereLoopInsert(pBuilder->pWInfo, pNew); + } + } + } /* Insert a full table scan */ pNew->u.btree.nEq = 0; @@ -5355,12 +5397,11 @@ static int whereLoopAddBtree( pNew->prereq = mExtra; pNew->u.btree.pIndex = 0; pNew->wsFlags = 0; - pNew->rRun = (double)pSrc->pTab->nRowEst; - pNew->nOut = (double)pSrc->pTab->nRowEst; + pNew->nOut = rSize; + pNew->rRun = rSize + rLogSize; + /* TBD: Reduce nOut using constraints */ rc = whereLoopInsert(pBuilder->pWInfo, pNew); - /* TBD: Insert automatic index opportunities */ - /* Loop over all indices */ for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext){ @@ -5478,6 +5519,7 @@ static int whereLoopAddVirtual( if( rc ) goto whereLoopAddVtab_exit; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pNew->prereq = 0; + assert( pIdxInfo->nConstraint<=pBuilder->mxTerm ); for(i=0; inConstraint; i++) pNew->aTerm[i] = 0; mxTerm = -1; for(i=0; inConstraint; i++, pIdxCons++){ @@ -5555,7 +5597,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ /* Loop over the tables in the join, from left to right */ pBuilder->pNew = pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); if( pNew==0 ) return SQLITE_NOMEM; - pNew->aTerm = sqlite3DbMallocZero(db, (pWC->nTerm+1)*sizeof(pNew->aTerm[0])); + pBuilder->mxTerm = pWC->nTerm+1; + while( pWC->pOuter ){ + pWC = pWC->pOuter; + pBuilder->mxTerm += pWC->nTerm; + } + pWC = pBuilder->pWC; + pNew->aTerm = sqlite3DbMallocZero(db,pBuilder->mxTerm*sizeof(pNew->aTerm[0])); if( pNew->aTerm==0 ){ rc = SQLITE_NOMEM; goto whereLoopAddAll_end; @@ -6331,6 +6379,17 @@ WhereInfo *sqlite3WhereBegin( pWInfo->a[0].plan.wsFlags &= ~WHERE_IDX_ONLY; } +#if 0 + /* Scaffolding: Check the new query plan against the old. Report any + ** discrepencies */ + for(ii=0; iia[ii].iFrom!=pWInfo->a[ii].pWLoop->iTab ){ + sqlite3DebugPrintf("(QP-Mismatch)"); + break; + } + } +#endif + /* Open all tables in the pTabList and any indices selected for ** searching those tables. */ From cf8fa7a65b5562d92c19cb4267cbd4ed9989a2b6 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 10 May 2013 20:26:22 +0000 Subject: [PATCH 014/144] Now generating OR-clause plans. FossilOrigin-Name: e17003fcfec0c0b524b1b9ff8e15e7ee83efa571 --- manifest | 12 ++--- manifest.uuid | 2 +- src/where.c | 121 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 116 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 180d5b5b51..5d695c8a7f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\sNGQP\sso\sthat\sit\scan\sproduce\splans\sthat\sinclude\sautomatic\sindices. -D 2013-05-10T15:16:30.669 +C Now\sgenerating\sOR-clause\splans. +D 2013-05-10T20:26:22.071 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -264,7 +264,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c f96b2602fd2da89873ed5a210608c58bf80d7c0e +F src/where.c 374f50ced988b23addabd3c351f1c18d8652d394 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1062,7 +1062,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 0278e420614e02fb2d8474ed99b0904275882dfe -R 69dec67361636bd352a6f82f3ef9f1cb +P 586b55d8d7722de1c0530b3b832bae0511e6d05c +R a9f14f7930497f93900a124a55885f20 U drh -Z ef95f556fc74affef6b6df28ead69ff3 +Z 9615c6567bc86000a51d8e76292d6ef0 diff --git a/manifest.uuid b/manifest.uuid index 0143fae8fc..250be95162 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -586b55d8d7722de1c0530b3b832bae0511e6d05c \ No newline at end of file +e17003fcfec0c0b524b1b9ff8e15e7ee83efa571 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 40653d7c51..fdadc3e738 100644 --- a/src/where.c +++ b/src/where.c @@ -289,6 +289,7 @@ struct WhereLoopBuilder { SrcList *pTabList; /* FROM clause */ ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ + WhereLoop *pBest; /* If non-NULL, store single best loop here */ int mxTerm; /* Maximum number of aTerm[] entries on pNew */ }; @@ -5162,10 +5163,27 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** fewer dependencies than the template. Otherwise a new WhereLoop is ** added based no the template. */ -static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ +static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p, *pNext = 0, *pToFree = 0; WhereTerm **paTerm = 0; - sqlite3 *db = pWInfo->pParse->db; + sqlite3 *db = pBuilder->db; + WhereInfo *pWInfo = pBuilder->pWInfo; + + if( (p = pBuilder->pBest)!=0 ){ + if( p->maskSelf!=0 ){ + if( p->rRun+p->rSetup < pTemplate->rRun+pTemplate->rSetup ){ + return SQLITE_OK; + } + if( p->rRun+p->rSetup == pTemplate->rRun+pTemplate->rSetup + && p->prereq <= pTemplate->prereq ){ + return SQLITE_OK; + } + } + *p = *pTemplate; + p->aTerm = 0; + p->u.vtab.needFree = 0; + return SQLITE_OK; + } /* Search for an existing WhereLoop to overwrite, or which takes ** priority over pTemplate. @@ -5210,11 +5228,13 @@ static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){ p->pNextLoop = pNext; *ppPrev = p; p->aTerm = paTerm; - if( pTemplate->nTerm ){ - memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0])); + if( p->nTerm ){ + memcpy(p->aTerm, pTemplate->aTerm, p->nTerm*sizeof(p->aTerm[0])); } if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ - if( p->u.btree.pIndex && p->u.btree.pIndex->tnum==0 ) p->u.btree.pIndex = 0; + if( p->u.btree.pIndex && p->u.btree.pIndex->tnum==0 ){ + p->u.btree.pIndex = 0; + } }else{ pTemplate->u.vtab.needFree = 0; } @@ -5305,7 +5325,7 @@ static int whereLoopAddBtreeIndex( } /* TBD: Adjust nOut and rRun for STAT3 range values */ /* TBD: Adjust nOut for additional constraints */ - rc = whereLoopInsert(pBuilder->pWInfo, pNew); + rc = whereLoopInsert(pBuilder, pNew); if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn ){ @@ -5366,7 +5386,8 @@ static int whereLoopAddBtree( rLogSize = estLog(rSize); /* Automatic indexes */ - if( (pBuilder->pParse->db->flags & SQLITE_AutoIndex)!=0 + if( !pBuilder->pBest + && (pBuilder->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->viaCoroutine && !pSrc->notIndexed && !pSrc->isCorrelated @@ -5385,7 +5406,7 @@ static int whereLoopAddBtree( pNew->rRun = rLogSize + pNew->nOut; pNew->wsFlags = WHERE_TEMP_INDEX; pNew->prereq = mExtra | pTerm->prereqRight; - rc = whereLoopInsert(pBuilder->pWInfo, pNew); + rc = whereLoopInsert(pBuilder, pNew); } } } @@ -5400,7 +5421,7 @@ static int whereLoopAddBtree( pNew->nOut = rSize; pNew->rRun = rSize + rLogSize; /* TBD: Reduce nOut using constraints */ - rc = whereLoopInsert(pBuilder->pWInfo, pNew); + rc = whereLoopInsert(pBuilder, pNew); /* Loop over all indices */ @@ -5565,7 +5586,7 @@ static int whereLoopAddVirtual( pNew->rSetup = (double)0; pNew->rRun = pIdxInfo->estimatedCost; pNew->nOut = (double)25; - whereLoopInsert(pBuilder->pWInfo, pNew); + whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); pNew->u.vtab.needFree = 0; @@ -5579,6 +5600,84 @@ whereLoopAddVtab_exit: return rc; } +/* +** Add WhereLoop entries to handle OR terms. This works for either +** btrees or virtual tables. +*/ +static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ + WhereClause *pWC; + WhereLoop *pNew; + WhereTerm *pTerm, *pWCEnd; + int rc = SQLITE_OK; + int iCur; + WhereClause tempWC; + WhereLoopBuilder sSubBuild; + WhereLoop sBest; + struct SrcList_item *pItem; + + + pWC = pBuilder->pWC; + if( pWC->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; + pWCEnd = pWC->a + pWC->nTerm; + pNew = pBuilder->pNew; + pItem = pBuilder->pTabList->a + pNew->iTab; + iCur = pItem->iCursor; + sSubBuild = *pBuilder; + sSubBuild.pOrderBy = 0; + sSubBuild.pBest = &sBest; + tempWC.pParse = pWC->pParse; + tempWC.pMaskSet = pWC->pMaskSet; + tempWC.pOuter = pWC; + tempWC.op = TK_AND; + tempWC.wctrlFlags = 0; + tempWC.nTerm = 1; + + for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 + && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 + ){ + WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; + WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; + WhereTerm *pOrTerm; + double rTotal = 0; + double nRow = 0; + Bitmask prereq = mExtra; + + + for(pOrTerm=pOrWC->a; pOrTermeOperator& WO_AND)!=0 ){ + sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; + }else if( pOrTerm->leftCursor==iCur ){ + tempWC.a = pOrTerm; + sSubBuild.pWC = &tempWC; + }else{ + continue; + } + sBest.maskSelf = 0; + if( IsVirtual(pItem->pTab) ){ + rc = whereLoopAddVirtual(&sSubBuild, mExtra); + }else{ + rc = whereLoopAddBtree(&sSubBuild, mExtra); + } + if( sBest.maskSelf==0 ) break; + assert( sBest.rSetup==(double)0 ); + rTotal += sBest.rRun; + nRow += sBest.nOut; + prereq |= sBest.prereq; + } + pNew->nTerm = 1; + pNew->aTerm[0] = pTerm; + pNew->wsFlags = WHERE_MULTI_OR; + pNew->rSetup = (double)0; + pNew->rRun = rTotal; + pNew->nOut = nRow; + pNew->prereq = prereq; + rc = whereLoopInsert(pBuilder, pNew); + } + } + return rc; +} + /* ** Add all WhereLoop objects for all tables */ @@ -5619,11 +5718,9 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ }else{ rc = whereLoopAddBtree(pBuilder, mExtra); } -#if 0 if( rc==SQLITE_OK ){ rc = whereLoopAddOr(pBuilder, mExtra); } -#endif mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; } From 0823c89c9bc1190d479df006137fbbaa6c08bf00 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 11 May 2013 00:06:23 +0000 Subject: [PATCH 015/144] Minor fixes to the OR-clause processing in the NGQP. FossilOrigin-Name: d6946f33c7851aa7efb04b93ac2ae1ac50c26eec --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 17 ++++++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 5d695c8a7f..53d49f8c0c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Now\sgenerating\sOR-clause\splans. -D 2013-05-10T20:26:22.071 +C Minor\sfixes\sto\sthe\sOR-clause\sprocessing\sin\sthe\sNGQP. +D 2013-05-11T00:06:23.252 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -264,7 +264,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 374f50ced988b23addabd3c351f1c18d8652d394 +F src/where.c 049e7011b90717768eed37cdbe912d85f66a395b F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1062,7 +1062,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 586b55d8d7722de1c0530b3b832bae0511e6d05c -R a9f14f7930497f93900a124a55885f20 +P e17003fcfec0c0b524b1b9ff8e15e7ee83efa571 +R eb646fd2ea7876f6a2dea69031e80ca3 U drh -Z 9615c6567bc86000a51d8e76292d6ef0 +Z cf78dc58c7e86082569e8dd0f46801e5 diff --git a/manifest.uuid b/manifest.uuid index 250be95162..be800b411f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e17003fcfec0c0b524b1b9ff8e15e7ee83efa571 \ No newline at end of file +d6946f33c7851aa7efb04b93ac2ae1ac50c26eec \ No newline at end of file diff --git a/src/where.c b/src/where.c index fdadc3e738..d0a3fce772 100644 --- a/src/where.c +++ b/src/where.c @@ -5337,8 +5337,9 @@ static int whereLoopAddBtreeIndex( } /* -** Add all WhereLoop objects for the iTab-th table of the join. That -** table is guaranteed to be a b-tree table, not a virtual table. +** Add all WhereLoop objects a single table of the join were the table +** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be +** a b-tree table, not a virtual table. */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ @@ -5356,6 +5357,7 @@ static int whereLoopAddBtree( pNew = pBuilder->pNew; pSrc = pBuilder->pTabList->a + pNew->iTab; + assert( !IsVirtual(pSrc->pTab) ); if( pSrc->pIndex ){ /* An INDEXED BY clause specifies a particular index to use */ @@ -5454,8 +5456,8 @@ static int whereLoopAddBtree( } /* -** Add all WhereLoop objects for the iTab-th table of the join. That -** table is guaranteed to be a virtual table. +** Add all WhereLoop objects for a table of the join identified by +** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. */ static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ @@ -5484,6 +5486,7 @@ static int whereLoopAddVirtual( pNew = pBuilder->pNew; pSrc = &pBuilder->pTabList->a[pNew->iTab]; pTab = pSrc->pTab; + assert( IsVirtual(pTab) ); pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pBuilder->pOrderBy); if( pIdxInfo==0 ) return SQLITE_NOMEM; pNew->prereq = 0; @@ -5493,7 +5496,7 @@ static int whereLoopAddVirtual( pNew->u.vtab.needFree = 0; pUsage = pIdxInfo->aConstraintUsage; - for(iPhase=0; iPhase<=2; iPhase++){ + for(iPhase=0; iPhase<=3; iPhase++){ if( !seenIn && (iPhase&1)!=0 ){ iPhase++; if( iPhase>3 ) break; @@ -5540,11 +5543,11 @@ static int whereLoopAddVirtual( if( rc ) goto whereLoopAddVtab_exit; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pNew->prereq = 0; - assert( pIdxInfo->nConstraint<=pBuilder->mxTerm ); - for(i=0; inConstraint; i++) pNew->aTerm[i] = 0; mxTerm = -1; + for(i=0; imxTerm; i++) pNew->aTerm[i] = 0; for(i=0; inConstraint; i++, pIdxCons++){ if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){ + if( iTerm>=pBuilder->mxTerm ) break; j = pIdxCons->iTermOffset; if( iTerm>=pIdxInfo->nConstraint || j<0 From 319f677d57a72e49c0618753e1a588d6f5840cf8 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 14 May 2013 15:31:07 +0000 Subject: [PATCH 016/144] First attempt to get ORDER BY optimization working in NGQP. FossilOrigin-Name: 9fe20292558bb9422de91e35648cb834cbf3b306 --- manifest | 14 ++--- manifest.uuid | 2 +- src/sqliteInt.h | 2 +- src/where.c | 160 +++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 153 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 53d49f8c0c..316d75d659 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sfixes\sto\sthe\sOR-clause\sprocessing\sin\sthe\sNGQP. -D 2013-05-11T00:06:23.252 +C First\sattempt\sto\sget\sORDER\sBY\soptimization\sworking\sin\sNGQP. +D 2013-05-14T15:31:07.121 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -195,7 +195,7 @@ F src/shell.c 2109d54f67c815a100abd7dc6a6e25eddb3b97eb F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h fab5580c75a16dced398bdd249c0409c9441b466 +F src/sqliteInt.h b9b6a2e97254fb50b6977ec55ad0f4e4ce0510d2 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -264,7 +264,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 049e7011b90717768eed37cdbe912d85f66a395b +F src/where.c 51d935c6593748ed004006ee0f2147a860d56e90 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1062,7 +1062,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P e17003fcfec0c0b524b1b9ff8e15e7ee83efa571 -R eb646fd2ea7876f6a2dea69031e80ca3 +P d6946f33c7851aa7efb04b93ac2ae1ac50c26eec +R fe984d1689a56a08a31662e67855ab37 U drh -Z cf78dc58c7e86082569e8dd0f46801e5 +Z 13c634b8e2044390ac483fb2d5137194 diff --git a/manifest.uuid b/manifest.uuid index be800b411f..7326bbb499 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d6946f33c7851aa7efb04b93ac2ae1ac50c26eec \ No newline at end of file +9fe20292558bb9422de91e35648cb834cbf3b306 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 45ae796c44..3ba0a3597b 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2045,7 +2045,7 @@ struct WhereLevel { #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ -#define WHREE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ +#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ /* ** The WHERE clause processing routine has two halves. The diff --git a/src/where.c b/src/where.c index d0a3fce772..2eff05ab39 100644 --- a/src/where.c +++ b/src/where.c @@ -84,6 +84,7 @@ struct WhereLoop { */ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ + Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ double nRow; /* Estimated number of rows generated by this path */ double rCost; /* Total cost of this path */ u8 isOrdered; /* True if this path satisfies ORDER BY */ @@ -5078,8 +5079,13 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ if( p->u.btree.pIndex ){ - sqlite3DebugPrintf(".%-12s %2d", - p->u.btree.pIndex->zName, p->u.btree.nEq); + const char *zName = p->u.btree.pIndex->zName; + if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ + int i = sqlite3Strlen30(zName) - 1; + while( zName[i]!='_' ) i--; + zName += i; + } + sqlite3DebugPrintf(".%-12s %2d", zName, p->u.btree.nEq); }else{ sqlite3DebugPrintf("%16s",""); } @@ -5734,25 +5740,139 @@ whereLoopAddAll_end: } /* -** Examine a WherePath to see if it outputs rows in the requested ORDER BY -** (or GROUP BY) without requiring a separate source operation. Return 1 -** if it does and 0 if it does not and -1 if we cannot tell. +** Examine a WherePath (with the addition of the extra WhereLoop of the 4th +** parameters) to see if it outputs rows in the requested ORDER BY +** (or GROUP BY) without requiring a separate source operation. Return: +** +** 0: ORDER BY is not satisfied. Sorting required +** 1: ORDER BY is satisfied. Omit sorting +** -1: Unknown at this time +** */ static int wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ WherePath *pPath, /* The WherePath to check */ int nLoop, /* Number of entries in pPath->aLoop[] */ - WhereLoop *pLoop /* Add this WhereLoop to the end of pPath->aLoop[] */ + WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ + Bitmask *pRevMask /* Mask of WhereLoops to run in reverse order */ ){ - if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ - return nLoop==0 && pLoop->u.vtab.isOrdered; - }else{ - /* TBD: Check to see if pFrom + pWLoop satisfies the ORDER BY. - ** (1) If yes: set isOrderedValid and isOrdered to 1. - ** (2) If no: set isOrderedValid to 1 and isOrdered to 0. - ** (3) unknown: no-op */ - return 0; + u8 revSet; + u8 rev; + u8 isUnique; + u8 requireUnique = 0; + u16 nColumn; + u16 nOrderBy; + int i, j; + int nUsed = 0; + int iCur; + int iColumn; + WhereLoop *pLoop; + ExprList *pOrderBy = pWInfo->pOrderBy; + Expr *pOBExpr; + CollSeq *pColl; + Index *pIndex; + sqlite3 *db = pWInfo->pParse->db; + Bitmask revMask = 0; + + /* + ** We say the WhereLoop is "one-row" if all of the following are true: + ** (a) All index columns match with WHERE_COLUMN_EQ. + ** (b) The index is unique + ** + ** General rules: (not an algorithm!) + ** + ** (1) If the current WhereLoop is one-row, then match over any and all + ** ORDER BY terms for the current WhereLoop and proceed to the next + ** WhereLoop. + ** + ** (2) If the current WhereLoop is not one-row, then all subsequent + ** WhereLoops must be one-row. + ** + ** (3) Optionally match any ORDER BY terms against the first nEq columns + ** of the index. + ** + ** (4) Index columns past nEq must match ORDER BY terms one-for-one. + */ + + assert( pOrderBy!=0 ); + + /* Sortability of virtual tables is determined by the xBestIndex method + ** of the virtual table itself */ + if( pLast->wsFlags & WHERE_VIRTUALTABLE ){ + assert( nLoop==0 ); + return pLast->u.vtab.isOrdered; } + + /* Sorting is always required if any term of the ORDER BY is not a + ** column reference */ + nOrderBy = pOrderBy->nExpr; + for(i=0; ia[nUsed].pExpr); + if( pOBExpr->op!=TK_COLUMN ) return 0; + } + + for(i=0; i<=nLoop && nUsedaLoop[i] : pLast; + assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); + isUnique = 1; + if( pLoop->wsFlags & WHERE_IPK ){ + if( (pLoop->wsFlags & WHERE_COLUMN_EQ)!=0 ) isUnique = 0; + pIndex = 0; + nColumn = 1; + }else if( pLoop->u.btree.pIndex==0 ){ + return 0; + }else{ + pIndex = pLoop->u.btree.pIndex; + nColumn = pIndex->nColumn; + if( pIndex->onError==OE_None ){ + isUnique = 0; + }else if( (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_RANGE + |WHERE_COLUMN_NULL))!=0 ){ + isUnique = 0; + }else if( pLoop->u.btree.nEq < pIndex->nColumn ){ + isUnique = 0; + } + } + if( !isUnique && requireUnique ) return 0; + requireUnique = !isUnique; + iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; + j = 0; + revSet = rev = 0; + for(j=0; ja[nUsed].pExpr); + assert( pOBExpr->op==TK_COLUMN ); + if( pOBExpr->iTable!=iCur ) break; + if( pIndex==0 ){ + if( pOBExpr->iColumn<0 && j==0 ){ + isUnique = 1; + rev = pOrderBy->a[nUsed].sortOrder; + }else if( isUnique ){ + continue; + }else{ + return 0; + } + } + if( isUnique ) continue; + iColumn = pIndex->aiColumn[j]; + if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; + if( pOBExpr->iColumn!=iColumn ) return 0; + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[nUsed].pExpr); + if( !pColl ) pColl = db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) return 0; + if( revSet ){ + if( pIndex->aSortOrder[j]!=rev ) return 0; + }else{ + rev = pIndex->aSortOrder[j]; + revSet = 1; + } + } + if( rev ) revMask |= ((Bitmask)1)<pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ Bitmask maskNew; + Bitmask revMask = 0; u8 isOrderedValid = pFrom->isOrderedValid; u8 isOrdered = pFrom->isOrdered; if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; @@ -5840,7 +5961,8 @@ static int wherePathSolver(WhereInfo *pWInfo){ rCost = pWLoop->rSetup + pWLoop->rRun*pFrom->nRow + pFrom->rCost; maskNew = pFrom->maskLoop | pWLoop->maskSelf; if( !isOrderedValid ){ - switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, pWLoop) ){ + switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, + pWLoop, &revMask) ){ case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ isOrdered = 1; isOrderedValid = 1; @@ -5873,6 +5995,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ } /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; + pTo->revLoop = revMask; pTo->nRow = pFrom->nRow * pWLoop->nOut; pTo->rCost = rCost; pTo->isOrderedValid = isOrderedValid; @@ -6193,7 +6316,12 @@ WhereInfo *sqlite3WhereBegin( && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) if( sqlite3WhereTrace ){ int ii; - sqlite3DebugPrintf("------------ Solution ----------------\n"); + sqlite3DebugPrintf("------------ Solution -------------"); + if( pWInfo->nOBSat ){ + sqlite3DebugPrintf(" ORDER BY omitted\n"); + }else{ + sqlite3DebugPrintf("\n"); + } for(ii=0; iia[ii].pWLoop, pTabList); } From 23f98daabb42f2f1def180b9bd2aa81c2f96b608 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 21 May 2013 15:52:07 +0000 Subject: [PATCH 017/144] Work toward improving the NGQP's ability to optimize out ORDER BY clauses. FossilOrigin-Name: 67367f1e1f0c3eb6be65eea9873910aa62b49884 --- manifest | 14 +++---- manifest.uuid | 2 +- src/sqliteInt.h | 4 +- src/where.c | 101 ++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index 325be9d757..ac6a9e67b4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sin\sall\strunk\schanges\sup\sthrough\sthe\s3.7.17\srelease. -D 2013-05-20T15:14:42.009 +C Work\stoward\simproving\sthe\sNGQP's\sability\sto\soptimize\sout\sORDER\sBY\sclauses. +D 2013-05-21T15:52:07.219 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -196,7 +196,7 @@ F src/shell.c 2109d54f67c815a100abd7dc6a6e25eddb3b97eb F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h b9b6a2e97254fb50b6977ec55ad0f4e4ce0510d2 +F src/sqliteInt.h 3b89d4517d984363a96f6f7b348440e01f13ced3 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -265,7 +265,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 51d935c6593748ed004006ee0f2147a860d56e90 +F src/where.c a01d93b37fbce377326849fe810dbcd2334d40c6 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1065,7 +1065,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 9fe20292558bb9422de91e35648cb834cbf3b306 118a3b35693b134d56ebd780123b7fd6f1497668 -R b3fec2668cd66935dfd81d00e243b60d +P 14ab6675e5eab3761256a06dad23d2b11220788a +R fc1fe5e0f9d1ee7dd6bc32ff7b604dd6 U drh -Z e02385c0316003dbdd17c2ecf0ba1968 +Z 0d777b81f154f68ed82e3cd424f83c9e diff --git a/manifest.uuid b/manifest.uuid index 52fb631158..75cf59ccb0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -14ab6675e5eab3761256a06dad23d2b11220788a \ No newline at end of file +67367f1e1f0c3eb6be65eea9873910aa62b49884 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3ba0a3597b..176413c946 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1919,8 +1919,8 @@ typedef u64 Bitmask; ** contains more than 63 columns and the 64-th or later column is used. */ struct SrcList { - i16 nSrc; /* Number of tables or subqueries in the FROM clause */ - i16 nAlloc; /* Number of entries allocated in a[] below */ + u8 nSrc; /* Number of tables or subqueries in the FROM clause */ + u8 nAlloc; /* Number of entries allocated in a[] below */ struct SrcList_item { Schema *pSchema; /* Schema to which this item is fixed */ char *zDatabase; /* Name of database holding this table */ diff --git a/src/where.c b/src/where.c index 2eff05ab39..0f61f6ed24 100644 --- a/src/where.c +++ b/src/where.c @@ -56,7 +56,8 @@ typedef struct WhereVtabPlan WhereVtabPlan; struct WhereLoop { Bitmask prereq; /* Bitmask of other loops that must run first */ Bitmask maskSelf; /* Bitmask identifying table iTab */ - u16 iTab; /* Index of the table coded by this loop */ + u8 iTab; /* Position in FROM clause of table coded by this loop */ + u8 iSortIdx; /* Sorting index number. 0==None */ u16 nTerm; /* Number of entries in aTerm[] */ u32 wsFlags; /* WHERE_* flags describing the plan */ double rSetup; /* One-time setup cost (ex: create transient index) */ @@ -1987,6 +1988,7 @@ static int termCanDriveIndex( if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & WO_EQ)==0 ) return 0; if( (pTerm->prereqRight & notReady)!=0 ) return 0; + if( pTerm->u.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; return 1; @@ -5168,6 +5170,21 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** and no insert will occur if an existing WhereLoop is faster and has ** fewer dependencies than the template. Otherwise a new WhereLoop is ** added based no the template. +** +** If pBuilder->pBest is not NULL then we only care about the very +** best template and that template should be stored in pBuilder->pBest. +** If pBuilder->pBest is NULL then a list of the best templates are stored +** in pBuilder->pWInfo->pLoops. +** +** When accumulating multiple loops (when pBuilder->pBest is NULL) we +** still might overwrite similar loops with the new template if the +** 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 */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p, *pNext = 0, *pToFree = 0; @@ -5175,6 +5192,11 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ sqlite3 *db = pBuilder->db; WhereInfo *pWInfo = pBuilder->pWInfo; + /* If pBuilder->pBest is defined, then only keep track of the single + ** best WhereLoop. pBuilder->pBest->maskSelf==0 indicates that no + ** prior WhereLoops have been evaluated and that the current pTemplate + ** is therefore the first and hence the best and should be retained. + */ if( (p = pBuilder->pBest)!=0 ){ if( p->maskSelf!=0 ){ if( p->rRun+p->rSetup < pTemplate->rRun+pTemplate->rSetup ){ @@ -5195,7 +5217,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** priority over pTemplate. */ for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ - if( p->iTab!=pTemplate->iTab ) continue; + if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ) continue; if( (p->prereq & pTemplate->prereq)==p->prereq && p->rSetup<=pTemplate->rSetup && p->rRun<=pTemplate->rRun @@ -5238,7 +5260,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ memcpy(p->aTerm, pTemplate->aTerm, p->nTerm*sizeof(p->aTerm[0])); } if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ - if( p->u.btree.pIndex && p->u.btree.pIndex->tnum==0 ){ + if( p->u.btree.pIndex && p->u.btree.pIndex && p->u.btree.pIndex->tnum==0 ){ p->u.btree.pIndex = 0; } }else{ @@ -5342,6 +5364,36 @@ static int whereLoopAddBtreeIndex( return rc; } +/* +** Return True if it is possible that pIndex might be useful in +** implementing the ORDER BY clause in pBuilder. +** +** Return False if pBuilder does not contain an ORDER BY clause or +** if there is no way for pIndex to be useful in implementing that +** ORDER BY clause. +*/ +static int indexMightHelpWithOrderBy( + WhereLoopBuilder *pBuilder, + Index *pIndex, + int iCursor +){ + ExprList *pOB; + int iCol; + int ii; + + if( (pOB = pBuilder->pOrderBy)==0 ) return 0; + iCol = pIndex->aiColumn[0]; + for(ii=0; iinExpr; ii++){ + Expr *pExpr = pOB->a[ii].pExpr; + if( pExpr->op!=TK_COLUMN ) return 0; + if( pExpr->iTable==iCursor ){ + if( pExpr->iColumn==iCol ) return 1; + return 0; + } + } + return 0; +} + /* ** Add all WhereLoop objects a single table of the join were the table ** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be @@ -5358,9 +5410,11 @@ static int whereLoopAddBtree( struct SrcList_item *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ + int iSortIdx = 0; /* Index number */ + int b; /* A boolean value */ double rSize; /* number of rows in the table */ double rLogSize; /* Logarithm of the number of rows in the table */ - + pNew = pBuilder->pNew; pSrc = pBuilder->pTabList->a + pNew->iTab; assert( !IsVirtual(pSrc->pTab) ); @@ -5419,26 +5473,25 @@ static int whereLoopAddBtree( } } - /* Insert a full table scan */ - pNew->u.btree.nEq = 0; - pNew->nTerm = 0; - pNew->rSetup = (double)0; - pNew->prereq = mExtra; - pNew->u.btree.pIndex = 0; - pNew->wsFlags = 0; - pNew->nOut = rSize; - pNew->rRun = rSize + rLogSize; - /* TBD: Reduce nOut using constraints */ - rc = whereLoopInsert(pBuilder, pNew); - /* Loop over all indices */ - for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext){ + for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ pNew->u.btree.nEq = 0; pNew->nTerm = 0; + pNew->iSortIdx = 0; + pNew->rSetup = (double)0; + pNew->prereq = mExtra; + pNew->u.btree.pIndex = pProbe; + b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); if( pProbe->tnum<=0 ){ /* Integer primary key index */ pNew->wsFlags = WHERE_IPK; + + /* Full table scan */ + pNew->nOut = rSize; + pNew->rRun = (rSize + rLogSize)*(3+b); /* 4x penalty for a full-scan */ + rc = whereLoopInsert(pBuilder, pNew); + if( rc ) break; }else{ Bitmask m = pSrc->colUsed; int j; @@ -5448,10 +5501,17 @@ static int whereLoopAddBtree( m &= ~(((Bitmask)1)<wsFlags = m==0 ? WHERE_IDX_ONLY : 0; - } - pNew->u.btree.pIndex = pProbe; + pNew->wsFlags = (m==0) ? WHERE_IDX_ONLY : 0; + /* Full scan via index */ + if( m==0 || b ){ + pNew->iSortIdx = b ? iSortIdx : 0; + pNew->nOut = rSize; + pNew->rRun = (m==0) ? (rSize + rLogSize)*(1+b) : (rSize*rLogSize); + rc = whereLoopInsert(pBuilder, pNew); + if( rc ) break; + } + } rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); /* If there was an INDEXED BY clause, then only that one index is @@ -5681,6 +5741,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew->rRun = rTotal; pNew->nOut = nRow; pNew->prereq = prereq; + memset(&pNew->u, 0, sizeof(pNew->u)); rc = whereLoopInsert(pBuilder, pNew); } } From d15cb17174cc9c7649dc018701ab5a055ac74a6a Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 21 May 2013 19:23:10 +0000 Subject: [PATCH 018/144] Enhanced "wheretrace" output in the NGQP solver routine. FossilOrigin-Name: 04dfb85a2a7025d4b5056b73fa8477691323919f --- manifest | 14 +++--- manifest.uuid | 2 +- src/where.c | 104 ++++++++++++++++++++++++++++++++++---------- test/boundary3.test | 1 + 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index ac6a9e67b4..785a029e3c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Work\stoward\simproving\sthe\sNGQP's\sability\sto\soptimize\sout\sORDER\sBY\sclauses. -D 2013-05-21T15:52:07.219 +C Enhanced\s"wheretrace"\soutput\sin\sthe\sNGQP\ssolver\sroutine. +D 2013-05-21T19:23:10.944 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -265,7 +265,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c a01d93b37fbce377326849fe810dbcd2334d40c6 +F src/where.c 759c34becf7a414b4bebddd30ad65109eb4510fc F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -324,7 +324,7 @@ F test/boundary1.test 66d7f4706ccdb42d58eafdb081de07b0eb42d77b F test/boundary2.tcl e34ef4e930cf1083150d4d2c603e146bd3b76bcb F test/boundary2.test 9ae758d7dab7e882c8b6cc4a6a10278385bff8fa F test/boundary3.tcl 8901d6a503d0bf64251dd81cc74e5ad3add4b119 -F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45 +F test/boundary3.test 04c269017471f1562da2dd6310359f16073a2a65 F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983 F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b F test/btreefault.test f52c593513bda80a506c848325c73c840590884d @@ -1065,7 +1065,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 14ab6675e5eab3761256a06dad23d2b11220788a -R fc1fe5e0f9d1ee7dd6bc32ff7b604dd6 +P 67367f1e1f0c3eb6be65eea9873910aa62b49884 +R 26b15d08d00e63218ca6971b3d46c9f6 U drh -Z 0d777b81f154f68ed82e3cd424f83c9e +Z 6ae4459022aa081e691ba708466a0da1 diff --git a/manifest.uuid b/manifest.uuid index 75cf59ccb0..d686a351db 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -67367f1e1f0c3eb6be65eea9873910aa62b49884 \ No newline at end of file +04dfb85a2a7025d4b5056b73fa8477691323919f \ No newline at end of file diff --git a/src/where.c b/src/where.c index 0f61f6ed24..a5a01ce071 100644 --- a/src/where.c +++ b/src/where.c @@ -28,6 +28,7 @@ #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) # define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X +# define WHERETRACE_ENABLED 1 #else # define WHERETRACE(X) #endif @@ -56,6 +57,9 @@ typedef struct WhereVtabPlan WhereVtabPlan; struct WhereLoop { Bitmask prereq; /* Bitmask of other loops that must run first */ Bitmask maskSelf; /* Bitmask identifying table iTab */ +#ifdef SQLITE_DEBUG + char cId; /* Symbolic ID of this loop for debugging use */ +#endif u8 iTab; /* Position in FROM clause of table coded by this loop */ u8 iSortIdx; /* Sorting index number. 0==None */ u16 nTerm; /* Number of entries in aTerm[] */ @@ -1835,7 +1839,7 @@ static double estLog(double N){ ** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines ** are no-ops. */ -#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_DEBUG) +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED) static void TRACE_IDX_INPUTS(sqlite3_index_info *p){ int i; if( !sqlite3WhereTrace ) return; @@ -5066,8 +5070,7 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */ #endif /* SQLITE_TEST */ -#if defined(SQLITE_DEBUG) \ - && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) +#ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes */ @@ -5075,7 +5078,7 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ int nb = 2*((pTabList->nSrc+15)/16); struct SrcList_item *pItem = pTabList->a + p->iTab; Table *pTab = pItem->pTab; - sqlite3DebugPrintf("%2d.%0*llx.%0*llx", + sqlite3DebugPrintf("%c %2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq); sqlite3DebugPrintf(" %8s", pItem->zAlias ? pItem->zAlias : pTab->zName); @@ -5102,7 +5105,7 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ sqlite3_free(z); } sqlite3DebugPrintf(" fg %08x N %2d", p->wsFlags, p->nTerm); - sqlite3DebugPrintf(" cost %.4g,%.4g,%.4g\n", + sqlite3DebugPrintf(" cost %.2g,%.2g,%.2g\n", p->prereq, p->rSetup, p->rRun, p->nOut); } #endif @@ -5877,7 +5880,8 @@ static int wherePathSatisfiesOrderBy( assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); isUnique = 1; if( pLoop->wsFlags & WHERE_IPK ){ - if( (pLoop->wsFlags & WHERE_COLUMN_EQ)!=0 ) isUnique = 0; + if( (pLoop->wsFlags & WHERE_COLUMN_IN)!=0 ) isUnique = 0; + if( pLoop->u.btree.nEq!=1 ) isUnique = 0; pIndex = 0; nColumn = 1; }else if( pLoop->u.btree.pIndex==0 ){ @@ -5936,6 +5940,18 @@ static int wherePathSatisfiesOrderBy( return -1; } +#ifdef WHERETRACE_ENABLED +/* For debugging use only: */ +static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ + static char zName[65]; + int i; + for(i=0; iaLoop[i]->cId; } + if( pLast ) zName[i++] = pLast->cId; + zName[i] = 0; + return zName; +} +#endif + /* ** Given the list of WhereLoop objects on pWInfo->pLoops, this routine @@ -6044,15 +6060,59 @@ static int wherePathSolver(WhereInfo *pWInfo){ } } if( jj>=nTo ){ - if( nTo>=mxChoice && rCost>=mxCost ) continue; + if( nTo>=mxChoice && rCost>=mxCost ){ +#ifdef WHERETRACE_ENABLE + if( sqlite3WhereTrace>=3 ){ + sqlite3DebugPrintf("Skip %s cost=%-7.2g order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + } +#endif + continue; + } + /* Add a new Path to the aTo[] set */ if( nTo0); } } pTo = &aTo[jj]; +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace>=3 ){ + sqlite3DebugPrintf("New %s cost=%-7.2g order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + } +#endif }else{ - if( pTo->rCost<=rCost ) continue; + if( pTo->rCost<=rCost ){ +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace>=3 ){ + sqlite3DebugPrintf( + "Skip %s cost=%-7.2g order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + sqlite3DebugPrintf(" vs %s cost=%-7.2g order=%c\n", + wherePathName(pTo, iLoop+1, 0), pTo->rCost, + pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + } +#endif + continue; + } + /* A new and better score for a previously created equivalent path */ +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace>=3 ){ + sqlite3DebugPrintf( + "Update %s cost=%-7.2g order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, + isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + sqlite3DebugPrintf(" was %s cost=%-7.2g order=%c\n", + wherePathName(pTo, iLoop+1, 0), pTo->rCost, + pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + } +#endif } /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; @@ -6072,15 +6132,13 @@ static int wherePathSolver(WhereInfo *pWInfo){ } } -#if 0 - if( sqlite3WhereTrace ){ - sqlite3DebugPrintf("---- round %d ---- nTo=%d\n", iLoop, nTo); - for(ii=0; iipTabList); - } +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace>=2 ){ + sqlite3DebugPrintf("---- round %d ----\n", iLoop); + for(ii=0, pTo=aTo; iirCost, pTo->nRow, + pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } } #endif @@ -6361,11 +6419,14 @@ WhereInfo *sqlite3WhereBegin( if( rc ) goto whereBeginError; /* Display all of the WhereLoop objects if wheretrace is enabled */ -#if defined(SQLITE_DEBUG) \ - && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) +#ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ WhereLoop *p; + int i = 0; + static char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" + "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; for(p=pWInfo->pLoops; p; p=p->pNextLoop){ + p->cId = zLabel[(i++)%sizeof(zLabel)]; whereLoopPrint(p, pTabList); } } @@ -6373,8 +6434,7 @@ WhereInfo *sqlite3WhereBegin( wherePathSolver(pWInfo); if( db->mallocFailed ) goto whereBeginError; -#if defined(SQLITE_DEBUG) \ - && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) +#ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ int ii; sqlite3DebugPrintf("------------ Solution -------------"); @@ -6668,7 +6728,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->a[0].plan.wsFlags &= ~WHERE_IDX_ONLY; } -#if 0 +#if 1 /* Scaffolding: Check the new query plan against the old. Report any ** discrepencies */ for(ii=0; ii Date: Wed, 22 May 2013 02:06:59 +0000 Subject: [PATCH 019/144] Improvements to ORDER BY handling in the NGQP. Fix an "exit" mistakenly left in a test script during the previous check-in. FossilOrigin-Name: 12c709b4369c7d94d7fb743d0d0da7a9350a3d16 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 27 ++++++++++++++++++++------- test/boundary3.test | 1 - 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 785a029e3c..a0719128fb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhanced\s"wheretrace"\soutput\sin\sthe\sNGQP\ssolver\sroutine. -D 2013-05-21T19:23:10.944 +C Improvements\sto\sORDER\sBY\shandling\sin\sthe\sNGQP.\s\sFix\san\s"exit"\smistakenly\nleft\sin\sa\stest\sscript\sduring\sthe\sprevious\scheck-in. +D 2013-05-22T02:06:59.780 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -265,7 +265,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 759c34becf7a414b4bebddd30ad65109eb4510fc +F src/where.c b695db3fe80456a57461c43f1fa1596a38fb4652 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -324,7 +324,7 @@ F test/boundary1.test 66d7f4706ccdb42d58eafdb081de07b0eb42d77b F test/boundary2.tcl e34ef4e930cf1083150d4d2c603e146bd3b76bcb F test/boundary2.test 9ae758d7dab7e882c8b6cc4a6a10278385bff8fa F test/boundary3.tcl 8901d6a503d0bf64251dd81cc74e5ad3add4b119 -F test/boundary3.test 04c269017471f1562da2dd6310359f16073a2a65 +F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45 F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983 F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b F test/btreefault.test f52c593513bda80a506c848325c73c840590884d @@ -1065,7 +1065,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 67367f1e1f0c3eb6be65eea9873910aa62b49884 -R 26b15d08d00e63218ca6971b3d46c9f6 +P 04dfb85a2a7025d4b5056b73fa8477691323919f +R b7bf12d6215811537a2285f41fc9e19a U drh -Z 6ae4459022aa081e691ba708466a0da1 +Z 6465b78fdb5633463ec5d8b46a4226e0 diff --git a/manifest.uuid b/manifest.uuid index d686a351db..d7f05dad96 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -04dfb85a2a7025d4b5056b73fa8477691323919f \ No newline at end of file +12c709b4369c7d94d7fb743d0d0da7a9350a3d16 \ No newline at end of file diff --git a/src/where.c b/src/where.c index a5a01ce071..ca9f9938b6 100644 --- a/src/where.c +++ b/src/where.c @@ -5961,7 +5961,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation ** error occurs. */ -static int wherePathSolver(WhereInfo *pWInfo){ +static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ const int mxChoice = 10; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ sqlite3 *db; /* The database connection */ @@ -5976,7 +5976,6 @@ static int wherePathSolver(WhereInfo *pWInfo){ WherePath *pFrom; /* An element of aFrom[] that we are working on */ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ - WhereLoop *pNext; /* Next loop */ WhereLoop **pX; /* Used to divy up the pSpace memory */ char *pSpace; /* Temporary memory used by this routine */ @@ -6003,10 +6002,11 @@ static int wherePathSolver(WhereInfo *pWInfo){ /* Precompute the cost of sorting the final result set, if the caller ** to sqlite3WhereBegin() was concerned about sorting */ rSortCost = (double)0; - if( pWInfo->pOrderBy==0 ){ + if( pWInfo->pOrderBy==0 || nRowEst<0.0 ){ aFrom[0].isOrderedValid = 1; }else{ /* Compute an estimate on the cost to sort the entire result set */ +#if 0 rSortCost = (double)1; for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pNext){ pNext = pWLoop->pNextLoop; @@ -6018,6 +6018,14 @@ static int wherePathSolver(WhereInfo *pWInfo){ rSortCost *= rCost; } rSortCost *= estLog(rSortCost); +#else + rSortCost = nRowEst*estLog(nRowEst); +#endif +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace>=2 ){ + sqlite3DebugPrintf("--solver sort cost=%-7.2g\n", rSortCost); + } +#endif } /* Compute successively longer WherePaths using the previous generation @@ -6134,10 +6142,10 @@ static int wherePathSolver(WhereInfo *pWInfo){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace>=2 ){ - sqlite3DebugPrintf("---- round %d ----\n", iLoop); + sqlite3DebugPrintf("---- after round %d ----\n", iLoop); for(ii=0, pTo=aTo; iirCost, pTo->nRow, + sqlite3DebugPrintf(" %s cost=%-7.2g nrow=%-7.2g order=%c\n", + wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } } @@ -6167,6 +6175,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ if( pFrom->isOrdered ){ pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; } + pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ sqlite3DbFree(db, pSpace); @@ -6432,8 +6441,12 @@ WhereInfo *sqlite3WhereBegin( } #endif - wherePathSolver(pWInfo); + wherePathSolver(pWInfo, -1); if( db->mallocFailed ) goto whereBeginError; + if( pWInfo->pOrderBy ){ + wherePathSolver(pWInfo, pWInfo->nRowOut); + if( db->mallocFailed ) goto whereBeginError; + } #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ int ii; diff --git a/test/boundary3.test b/test/boundary3.test index e1331111f9..dbe9abfa0a 100644 --- a/test/boundary3.test +++ b/test/boundary3.test @@ -123,7 +123,6 @@ do_test boundary3-2.1.3 { SELECT t1.rowid, x FROM t1 JOIN t2 ON t2.r=t1.rowid WHERE t2.a=17 } } {72057594037927935 00ffffffffffffff} -exit do_test boundary3-2.1.gt.1 { db eval { SELECT t2.a FROM t1 JOIN t2 USING(a) From 0f133a483278d8bae17f917b7962c3ad1ccefe80 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 22 May 2013 17:01:17 +0000 Subject: [PATCH 020/144] Allow the rowid at the end of an index to be used in a constraint on that index. FossilOrigin-Name: 9bf0524df7ca2e7fcd92b2878a8457264b3c7f6e --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 22 +++++++++++++++------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index a0719128fb..3b53419b6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\sORDER\sBY\shandling\sin\sthe\sNGQP.\s\sFix\san\s"exit"\smistakenly\nleft\sin\sa\stest\sscript\sduring\sthe\sprevious\scheck-in. -D 2013-05-22T02:06:59.780 +C Allow\sthe\srowid\sat\sthe\send\sof\san\sindex\sto\sbe\sused\sin\sa\sconstraint\son\sthat\sindex. +D 2013-05-22T17:01:17.424 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -265,7 +265,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c b695db3fe80456a57461c43f1fa1596a38fb4652 +F src/where.c 3ca12d203c0cca5bc36f0cd408a97ed5a9357047 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1065,7 +1065,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 04dfb85a2a7025d4b5056b73fa8477691323919f -R b7bf12d6215811537a2285f41fc9e19a +P 12c709b4369c7d94d7fb743d0d0da7a9350a3d16 +R 7322735243734361422a3e6e35778930 U drh -Z 6465b78fdb5633463ec5d8b46a4226e0 +Z fd0ab2669226a74d38406e095d929629 diff --git a/manifest.uuid b/manifest.uuid index d7f05dad96..98ddda464c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -12c709b4369c7d94d7fb743d0d0da7a9350a3d16 \ No newline at end of file +9bf0524df7ca2e7fcd92b2878a8457264b3c7f6e \ No newline at end of file diff --git a/src/where.c b/src/where.c index ca9f9938b6..e28fe4d62c 100644 --- a/src/where.c +++ b/src/where.c @@ -5104,7 +5104,7 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ sqlite3DebugPrintf(" %-15s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" fg %08x N %2d", p->wsFlags, p->nTerm); + sqlite3DebugPrintf(" fg %08x N %d", p->wsFlags, p->nTerm); sqlite3DebugPrintf(" cost %.2g,%.2g,%.2g\n", p->prereq, p->rSetup, p->rRun, p->nOut); } @@ -5293,6 +5293,7 @@ static int whereLoopAddBtreeIndex( WhereLoop savedLoop; /* Saved original content of pNew[] */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ + tRowcnt iRowEst; /* Estimated index selectivity */ double rLogSize; /* Logarithm of table size */ db = pBuilder->db; @@ -5300,7 +5301,7 @@ static int whereLoopAddBtreeIndex( if( db->mallocFailed ) return SQLITE_NOMEM; assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); - assert( pNew->u.btree.nEqnColumn ); + assert( pNew->u.btree.nEq<=pProbe->nColumn ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; @@ -5310,9 +5311,15 @@ static int whereLoopAddBtreeIndex( opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE; } - iCol = pProbe->aiColumn[pNew->u.btree.nEq]; + if( pNew->u.btree.nEq < pProbe->nColumn ){ + iCol = pProbe->aiColumn[pNew->u.btree.nEq]; + iRowEst = pProbe->aiRowEst[pNew->u.btree.nEq+1]; + }else{ + iCol = -1; + iRowEst = 1; + } pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, - opMask, iCol>=0 ? pProbe : 0); + opMask, pProbe); savedLoop = *pNew; pNew->rSetup = (double)0; rLogSize = estLog(pProbe->aiRowEst[0]); @@ -5334,11 +5341,11 @@ static int whereLoopAddBtreeIndex( nIn = pExpr->x.pList->nExpr; } pNew->u.btree.nEq++; - pNew->nOut = (double)pProbe->aiRowEst[pNew->u.btree.nEq] * nInMul * nIn; + pNew->nOut = (double)iRowEst * nInMul * nIn; }else if( pTerm->eOperator & (WO_EQ|WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; pNew->u.btree.nEq++; - pNew->nOut = (double)pProbe->aiRowEst[pNew->u.btree.nEq] * nInMul; + pNew->nOut = (double)iRowEst * nInMul; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pNew->nOut = savedLoop.nOut/3; @@ -5358,7 +5365,8 @@ static int whereLoopAddBtreeIndex( /* TBD: Adjust nOut for additional constraints */ rc = whereLoopInsert(pBuilder, pNew); if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 - && pNew->u.btree.nEqnColumn + && pNew->u.btree.nEq<=pProbe->nColumn + && pProbe->zName!=0 ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul*nIn); } From ef8663765575762847a9a9f44b6f82817e87b793 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 22 May 2013 20:49:02 +0000 Subject: [PATCH 021/144] Use the NGQP plan for EXPLAIN QUERY PLAN output. This change causes 207 errors in veryquick.test, many of which are benign. FossilOrigin-Name: f783e8e6b10de44029c7c5f57e4648a4a677ca1b --- manifest | 14 ++++++------- manifest.uuid | 2 +- src/where.c | 52 +++++++++++++++++++++++++++---------------------- test/tester.tcl | 25 +++++++++++++++++++++--- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/manifest b/manifest index 3b53419b6d..f6c1ed6e1d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\sthe\srowid\sat\sthe\send\sof\san\sindex\sto\sbe\sused\sin\sa\sconstraint\son\sthat\sindex. -D 2013-05-22T17:01:17.424 +C Use\sthe\sNGQP\splan\sfor\sEXPLAIN\sQUERY\sPLAN\soutput.\s\sThis\schange\scauses\s207\nerrors\sin\sveryquick.test,\smany\sof\swhich\sare\sbenign. +D 2013-05-22T20:49:02.170 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -265,7 +265,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 3ca12d203c0cca5bc36f0cd408a97ed5a9357047 +F src/where.c 627bf1af3ab30e1efcc7ac362b15e7e945e9250d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -779,7 +779,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d -F test/tester.tcl 3b08771e6d601612fe62d13787db0e50aac4cf7b +F test/tester.tcl 693700993b7e0a5b7b2171b291a54cdbad1d86ff F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1065,7 +1065,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 12c709b4369c7d94d7fb743d0d0da7a9350a3d16 -R 7322735243734361422a3e6e35778930 +P 9bf0524df7ca2e7fcd92b2878a8457264b3c7f6e +R 97f27b7ea9f3efcce127b9443ade87ed U drh -Z fd0ab2669226a74d38406e095d929629 +Z 96c17883fc9fb8d90fa5ada1b6415a79 diff --git a/manifest.uuid b/manifest.uuid index 98ddda464c..0de3a8524f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9bf0524df7ca2e7fcd92b2878a8457264b3c7f6e \ No newline at end of file +f783e8e6b10de44029c7c5f57e4648a4a677ca1b \ No newline at end of file diff --git a/src/where.c b/src/where.c index e28fe4d62c..fa38b57383 100644 --- a/src/where.c +++ b/src/where.c @@ -4168,16 +4168,16 @@ static void explainAppendTerm( ** It is the responsibility of the caller to free the buffer when it is ** no longer required. */ -static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){ - WherePlan *pPlan = &pLevel->plan; - Index *pIndex = pPlan->u.pIdx; - int nEq = pPlan->nEq; +static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ + Index *pIndex = pLoop->u.btree.pIndex; + int nEq = pLoop->u.btree.nEq; int i, j; Column *aCol = pTab->aCol; int *aiColumn = pIndex->aiColumn; StrAccum txt; - if( nEq==0 && (pPlan->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ + if( pIndex==0 ) return 0; + if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ return 0; } sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH); @@ -4188,11 +4188,11 @@ static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){ } j = i; - if( pPlan->wsFlags&WHERE_BTM_LIMIT ){ + if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(&txt, i++, z, ">"); } - if( pPlan->wsFlags&WHERE_TOP_LIMIT ){ + if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(&txt, i, z, "<"); } @@ -4215,7 +4215,6 @@ static void explainOneScan( u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ if( pParse->explain==2 ){ - u32 flags = pLevel->plan.wsFlags; struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ @@ -4223,12 +4222,16 @@ static void explainOneScan( sqlite3_int64 nRow; /* Expected number of rows visited by scan */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ + WhereLoop *pLoop; /* The controlling WhereLoop object */ + u32 flags; /* Flags that describe this loop */ + pLoop = pLevel->pWLoop; + flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return; - isSearch = (pLevel->plan.nEq>0) - || (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 - || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); + isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 + || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) + || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN"); if( pItem->pSelect ){ @@ -4240,20 +4243,22 @@ static void explainOneScan( if( pItem->zAlias ){ zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); } - if( (flags & WHERE_INDEXED)!=0 ){ - char *zWhere = explainIndexRange(db, pLevel, pItem->pTab); + if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 + && pLoop->u.btree.pIndex!=0 + ){ + char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg, ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""), ((flags & WHERE_IDX_ONLY)?"COVERING ":""), ((flags & WHERE_TEMP_INDEX)?"":" "), - ((flags & WHERE_TEMP_INDEX)?"": pLevel->plan.u.pIdx->zName), + ((flags & WHERE_TEMP_INDEX)?"": pLoop->u.btree.pIndex->zName), zWhere ); sqlite3DbFree(db, zWhere); - }else if( flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){ + }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_INDEXED)!=0 ){ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); - if( flags&WHERE_ROWID_EQ ){ + if( flags&WHERE_COLUMN_EQ ){ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowidplan.u.pVtabIdx; zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg, - pVtabIdx->idxNum, pVtabIdx->idxStr); + pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif if( wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ){ testcase( wctrlFlags & WHERE_ORDERBY_MIN ); nRow = 1; }else{ - nRow = (sqlite3_int64)pLevel->plan.nRow; + nRow = (sqlite3_int64)pLoop->nOut; } zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); @@ -5263,7 +5267,8 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ memcpy(p->aTerm, pTemplate->aTerm, p->nTerm*sizeof(p->aTerm[0])); } if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ - if( p->u.btree.pIndex && p->u.btree.pIndex && p->u.btree.pIndex->tnum==0 ){ + Index *pIndex = p->u.btree.pIndex; + if( pIndex && pIndex->tnum==0 ){ p->u.btree.pIndex = 0; } }else{ @@ -5310,6 +5315,7 @@ static int whereLoopAddBtreeIndex( }else{ opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE; } + if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); if( pNew->u.btree.nEq < pProbe->nColumn ){ iCol = pProbe->aiColumn[pNew->u.btree.nEq]; @@ -5472,6 +5478,7 @@ static int whereLoopAddBtree( for(pTerm=pWC->a; rc==SQLITE_OK && pTermu.btree.nEq = 1; + pNew->u.btree.pIndex = 0; pNew->nTerm = 1; pNew->aTerm[0] = pTerm; pNew->rSetup = 2*rLogSize*pSrc->pTab->nRowEst; @@ -5515,7 +5522,7 @@ static int whereLoopAddBtree( pNew->wsFlags = (m==0) ? WHERE_IDX_ONLY : 0; /* Full scan via index */ - if( m==0 || b ){ + if( (m==0 || b) && pProbe->bUnordered==0 ){ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; pNew->rRun = (m==0) ? (rSize + rLogSize)*(1+b) : (rSize*rLogSize); @@ -5892,10 +5899,9 @@ static int wherePathSatisfiesOrderBy( if( pLoop->u.btree.nEq!=1 ) isUnique = 0; pIndex = 0; nColumn = 1; - }else if( pLoop->u.btree.pIndex==0 ){ + }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ - pIndex = pLoop->u.btree.pIndex; nColumn = pIndex->nColumn; if( pIndex->onError==OE_None ){ isUnique = 0; diff --git a/test/tester.tcl b/test/tester.tcl index 761a36e355..cad9807ed7 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -793,9 +793,28 @@ proc finalize_testing {} { set nTest [incr_ntest] set nErr [set_test_counter errors] - puts "$nErr errors out of $nTest tests" - if {$nErr>0} { - puts "Failures on these tests: [set_test_counter fail_list]" + set nKnown 0 + if {[file readable known-problems.txt]} { + set fd [open known-problems.txt] + set content [read $fd] + close $fd + foreach x $content {set known_error($x) 1} + foreach x [set_test_counter fail_list] { + if {[info exists known_error($x)]} {incr nKnown} + } + } + if {$nKnown>0} { + puts "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\ + out of $nTest tests" + } else { + puts "$nErr errors out of $nTest tests" + } + if {$nErr>$nKnown} { + puts -nonewline "Failures on these tests:" + foreach x [set_test_counter fail_list] { + if {![info exists known_error($x)]} {puts -nonewline " $x"} + } + puts "" } foreach warning [set_test_counter warn_list] { puts "Warning: $warning" From 34e258c942f033d623bb559a0d7dbcd64246d30e Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 23 May 2013 01:40:53 +0000 Subject: [PATCH 022/144] Cause the mmap_size PRAGMA to immediately change the mmap space if the database connection is already active. In particular, reducing mmap_size will immediately free up process address space. FossilOrigin-Name: 761177927cb51e4f5e66061ca39cf37edbe8346b --- manifest | 18 ++++----- manifest.uuid | 2 +- src/os_unix.c | 10 +++-- src/os_win.c | 16 ++++++-- test/mmap3.test | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 test/mmap3.test diff --git a/manifest b/manifest index 5b3b90661c..3429dbcc89 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Version\s3.7.17 -D 2013-05-20T00:56:22.515 +C Cause\sthe\smmap_size\sPRAGMA\sto\simmediately\schange\sthe\smmap\sspace\sif\sthe\ndatabase\sconnection\sis\salready\sactive.\s\sIn\sparticular,\sreducing\smmap_size\nwill\simmediately\sfree\sup\sprocess\saddress\sspace. +D 2013-05-23T01:40:53.974 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -177,8 +177,8 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c 75ce49309b8352c7173ce1ef6fc9e8d1f6daab10 -F src/os_win.c 32b8adca3e989565713ff74098b3cb2cb25d6e59 +F src/os_unix.c 42c9b8b7c61c9fa3561258f523be5749e52ed0e0 +F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b F src/pager.c 49e23f9898113ddfe90942bdf1c1ef57955d0921 F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 F src/parse.y 9708365594eea519cdc8504dee425c0a41c79502 @@ -651,6 +651,7 @@ F test/misc7.test dd82ec9250b89178b96cd28b2aca70639d21e5b3 F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054 F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 +F test/mmap3.test 01728252af6f9bcf708169d7b794b7597c69ac44 F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 @@ -1065,10 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7a9aa21c3506a10ab9465540e81071b39bca447d -R c103e20e6479251bb5b95c9b2e375810 -T +bgcolor * #d0c0ff -T +sym-release * -T +sym-version-3.7.17 * +P 118a3b35693b134d56ebd780123b7fd6f1497668 +R 743f49e6500daee258364b50095b5869 U drh -Z 416a23d38a1b2c089b32c7a6efcbc3bc +Z 8b8fce9c808b567d366ba2a76c063d60 diff --git a/manifest.uuid b/manifest.uuid index 8bfbf98bd7..4ef49c9f54 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -118a3b35693b134d56ebd780123b7fd6f1497668 \ No newline at end of file +761177927cb51e4f5e66061ca39cf37edbe8346b \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index abc23a452e..242c2a3c3b 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3775,15 +3775,19 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; + int rc = SQLITE_OK; if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } *(i64*)pArg = pFile->mmapSizeMax; - if( newLimit>=0 ){ + if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; - if( newLimitmmapSize ) pFile->mmapSize = newLimit; + if( pFile->mmapSize>0 ){ + unixUnmapfile(pFile); + rc = unixMapfile(pFile, -1); + } } - return SQLITE_OK; + return rc; } #ifdef SQLITE_DEBUG /* The pager calls this method to signal that it has done diff --git a/src/os_win.c b/src/os_win.c index aeb08814b3..07b74cbe22 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -2816,6 +2816,9 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ /* Forward declaration */ static int getTempname(int nBuf, char *zBuf); +#if SQLITE_MAX_MMAP_SIZE>0 +static int winMapfile(winFile*, sqlite3_int64); +#endif /* ** Control and query of the open file handle. @@ -2899,13 +2902,20 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; + int rc = SQLITE_OK; if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } *(i64*)pArg = pFile->mmapSizeMax; - if( newLimit>=0 ) pFile->mmapSizeMax = newLimit; - OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); - return SQLITE_OK; + if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ + pFile->mmapSizeMax = newLimit; + if( pFile->mmapSize>0 ){ + (void)winUnmapfile(pFile); + rc = winMapfile(pFile, -1); + } + } + OSTRACE(("FCNTL file=%p, rc=%d\n", pFile->h, rc)); + return rc; } #endif } diff --git a/test/mmap3.test b/test/mmap3.test new file mode 100644 index 0000000000..d2b347eb3e --- /dev/null +++ b/test/mmap3.test @@ -0,0 +1,98 @@ +# 2013-05-23 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable !mmap { + finish_test + return +} +source $testdir/lock_common.tcl +set testprefix mmap3 + +do_test mmap3-1.0 { + load_static_extension db wholenumber + db eval { + PRAGMA mmap_size=100000; + CREATE TABLE t1(x, y); + CREATE VIRTUAL TABLE nums USING wholenumber; + INSERT INTO t1 SELECT value, randomblob(value) FROM nums + WHERE value BETWEEN 1 and 1000; + SELECT sum(x), sum(length(y)) from t1; + PRAGMA mmap_size; + } +} {100000 500500 500500 100000} +do_test mmap3-1.2 { + db eval { + PRAGMA mmap_size=50000; + CREATE TABLE t2(a,b); + SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1; + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {50000 nums t1 t2 ok 50000} +do_test mmap3-1.3 { + db eval { + PRAGMA mmap_size=250000; + DROP TABLE t2; + SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1; + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {250000 nums t1 ok 250000} +do_test mmap3-1.4 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + db eval {PRAGMA mmap_size=150000} + } + db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {ok 250000} +do_test mmap3-1.5 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + db eval {PRAGMA mmap_size=0} + } + db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {ok 250000} +do_test mmap3-1.6 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + set x [db one {PRAGMA mmap_size}] + } + set x [concat $x [db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + }]] +} {250000 ok 250000} +do_test mmap3-1.7 { + db eval { + PRAGMA mmap_size(0); + CREATE TABLE t3(a,b,c); + SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1; + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {0 nums t1 t3 ok 0} +do_test mmap3-1.8 { + db eval {SELECT x FROM t1 WHERE +x BETWEEN 10 AND 15} { + db eval {PRAGMA mmap_size=75000} + } + db eval { + PRAGMA quick_check; + PRAGMA mmap_size; + } +} {ok 75000} + +finish_test From 3719f5f600db954c2e84e47ba8d7d5658be54bbd Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 23 May 2013 10:13:18 +0000 Subject: [PATCH 023/144] Avoid unnecessary calls to FCNTL_SIZE_HINT. Return an error to the user if the file-control invoked by "PRAGMA mmap_size" returns a value other than SQLITE_OK or SQLITE_NOTFOUND. FossilOrigin-Name: 40cfde8b4a59a09e52e62f9f029f8d3b32eb15fa --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/pager.c | 3 ++- src/pragma.c | 8 ++++++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 3429dbcc89..7448a36d33 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Cause\sthe\smmap_size\sPRAGMA\sto\simmediately\schange\sthe\smmap\sspace\sif\sthe\ndatabase\sconnection\sis\salready\sactive.\s\sIn\sparticular,\sreducing\smmap_size\nwill\simmediately\sfree\sup\sprocess\saddress\sspace. -D 2013-05-23T01:40:53.974 +C Avoid\sunnecessary\scalls\sto\sFCNTL_SIZE_HINT.\sReturn\san\serror\sto\sthe\suser\sif\sthe\sfile-control\sinvoked\sby\s"PRAGMA\smmap_size"\sreturns\sa\svalue\sother\sthan\sSQLITE_OK\sor\sSQLITE_NOTFOUND. +D 2013-05-23T10:13:18.105 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -179,13 +179,13 @@ F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_unix.c 42c9b8b7c61c9fa3561258f523be5749e52ed0e0 F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b -F src/pager.c 49e23f9898113ddfe90942bdf1c1ef57955d0921 +F src/pager.c 3709c5c9e2eb566fffba6348508b7212c4d06ca3 F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 F src/parse.y 9708365594eea519cdc8504dee425c0a41c79502 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9 -F src/pragma.c 8779308bc1ea1901c4bc94dfe9a83d436f73f52c +F src/pragma.c 8bf4bfaef7975abff45e55230ed1033b5f208d11 F src/prepare.c 743e484233c51109666d402f470523553b41797c F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 118a3b35693b134d56ebd780123b7fd6f1497668 -R 743f49e6500daee258364b50095b5869 -U drh -Z 8b8fce9c808b567d366ba2a76c063d60 +P 761177927cb51e4f5e66061ca39cf37edbe8346b +R f79c1bfda6a2029cdca9b19f9c8cc1f9 +U dan +Z 2a86c7dc006c06bc92b2aaaf78345975 diff --git a/manifest.uuid b/manifest.uuid index 4ef49c9f54..1a55505521 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -761177927cb51e4f5e66061ca39cf37edbe8346b \ No newline at end of file +40cfde8b4a59a09e52e62f9f029f8d3b32eb15fa \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 1c6a84fea4..443f5fb740 100644 --- a/src/pager.c +++ b/src/pager.c @@ -4214,7 +4214,8 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ */ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); if( rc==SQLITE_OK - && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize + && pPager->dbHintSizedbSize + && (pList->pDirty || pList->pgno>pPager->dbHintSize) ){ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); diff --git a/src/pragma.c b/src/pragma.c index 3056a7d8e2..cde5fd1c77 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -774,11 +774,15 @@ void sqlite3Pragma( } } sz = -1; - if( sqlite3_file_control(db,zDb,SQLITE_FCNTL_MMAP_SIZE,&sz)==SQLITE_OK ){ + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_MMAP_SIZE, &sz); #if SQLITE_MAX_MMAP_SIZE==0 - sz = 0; + sz = 0; #endif + if( rc==SQLITE_OK ){ returnSingleInt(pParse, "mmap_size", sz); + }else if( rc!=SQLITE_NOTFOUND ){ + pParse->nErr++; + pParse->rc = rc; } }else From 7a7083cf706fb60c33d93081cd5c9491c03ee64e Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 23 May 2013 10:15:46 +0000 Subject: [PATCH 024/144] Have the "make fulltest" command run the "mmap" permutation test. FossilOrigin-Name: 82ad373f85aa0a87d24c6dbb2ea7dca8c5aff56a --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/all.test | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 7448a36d33..222af90348 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\sunnecessary\scalls\sto\sFCNTL_SIZE_HINT.\sReturn\san\serror\sto\sthe\suser\sif\sthe\sfile-control\sinvoked\sby\s"PRAGMA\smmap_size"\sreturns\sa\svalue\sother\sthan\sSQLITE_OK\sor\sSQLITE_NOTFOUND. -D 2013-05-23T10:13:18.105 +C Have\sthe\s"make\sfulltest"\scommand\srun\sthe\s"mmap"\spermutation\stest. +D 2013-05-23T10:15:46.215 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -270,7 +270,7 @@ F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 -F test/all.test 52fc8dee494092031a556911d404ca30a749a30b +F test/all.test 705b516d4df89be56b0f52577df0966e93d2ce72 F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748 F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 761177927cb51e4f5e66061ca39cf37edbe8346b -R f79c1bfda6a2029cdca9b19f9c8cc1f9 +P 40cfde8b4a59a09e52e62f9f029f8d3b32eb15fa +R 5b0b79093b4b7cf1c06b909710b57c2e U dan -Z 2a86c7dc006c06bc92b2aaaf78345975 +Z 58efdf0c0497e75e223f31c9f398e2ac diff --git a/manifest.uuid b/manifest.uuid index 1a55505521..5f09e782df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -40cfde8b4a59a09e52e62f9f029f8d3b32eb15fa \ No newline at end of file +82ad373f85aa0a87d24c6dbb2ea7dca8c5aff56a \ No newline at end of file diff --git a/test/all.test b/test/all.test index 54302d02e9..cd2a430390 100644 --- a/test/all.test +++ b/test/all.test @@ -39,6 +39,7 @@ run_test_suite pcache50 run_test_suite pcache90 run_test_suite pcache100 run_test_suite prepare +run_test_suite mmap if {$::tcl_platform(platform)=="unix"} { ifcapable !default_autovacuum { From 17f37c7d5a9c63864fb5433c3d92b29a8346067c Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 23 May 2013 20:52:16 +0000 Subject: [PATCH 025/144] Add OGC GeoPackage files to the magic.txt database. FossilOrigin-Name: dab6a32847ce17f12e3a2b09a3567945b2154f67 --- magic.txt | 3 ++- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/magic.txt b/magic.txt index a2ca209e5d..3351466680 100644 --- a/magic.txt +++ b/magic.txt @@ -19,10 +19,11 @@ # compatibility only. # 0 string =SQLite\ format\ 3 ->68 belong =0x0f055111 Fossil repository - >68 belong =0x0f055112 Fossil checkout - >68 belong =0x0f055113 Fossil global configuration - +>68 belong =0x0f055111 Fossil repository - >68 belong =0x42654462 Bentley Systems BeSQLite Database - >68 belong =0x42654c6e Bentley Systems Localization File - >60 belong =0x5f4d544e Monotone source repository - +>68 belong =0x47504b47 OGC GeoPackage file - >0 string =SQLite SQLite3 database diff --git a/manifest b/manifest index 222af90348..6f03cc1e01 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\sthe\s"make\sfulltest"\scommand\srun\sthe\s"mmap"\spermutation\stest. -D 2013-05-23T10:15:46.215 +C Add\sOGC\sGeoPackage\sfiles\sto\sthe\smagic.txt\sdatabase. +D 2013-05-23T20:52:16.211 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -113,7 +113,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 -F magic.txt 3f820e18c43504b25da40ff4b4cdb66dc4c4907e +F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d F main.mk a8ebdf910e2cc10db1f9f54ec316f637458e8001 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 40cfde8b4a59a09e52e62f9f029f8d3b32eb15fa -R 5b0b79093b4b7cf1c06b909710b57c2e -U dan -Z 58efdf0c0497e75e223f31c9f398e2ac +P 82ad373f85aa0a87d24c6dbb2ea7dca8c5aff56a +R b8114ddabfd98673e6d6ce93a982165c +U drh +Z 6c60065be51b126d35afa515cb8ed58f diff --git a/manifest.uuid b/manifest.uuid index 5f09e782df..d3fd55b00f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -82ad373f85aa0a87d24c6dbb2ea7dca8c5aff56a \ No newline at end of file +dab6a32847ce17f12e3a2b09a3567945b2154f67 \ No newline at end of file From c2bed0a2c964a1d486c85541354701d7a6772f03 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 24 May 2013 11:57:50 +0000 Subject: [PATCH 026/144] Fix harmless compiler warnings in the shell. FossilOrigin-Name: 9e2c17c5358b156b588542dbba38da7fedf5302b --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 6f03cc1e01..03025b6aed 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sOGC\sGeoPackage\sfiles\sto\sthe\smagic.txt\sdatabase. -D 2013-05-23T20:52:16.211 +C Fix\sharmless\scompiler\swarnings\sin\sthe\sshell. +D 2013-05-24T11:57:50.209 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -192,7 +192,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c a4641882279becc200f2680f55f3e89d4e7c7f78 -F src/shell.c 2109d54f67c815a100abd7dc6a6e25eddb3b97eb +F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 82ad373f85aa0a87d24c6dbb2ea7dca8c5aff56a -R b8114ddabfd98673e6d6ce93a982165c +P dab6a32847ce17f12e3a2b09a3567945b2154f67 +R 659d4081538710ab3b6917b836242fc7 U drh -Z 6c60065be51b126d35afa515cb8ed58f +Z b1f0db700bf1651929699f229849ec18 diff --git a/manifest.uuid b/manifest.uuid index d3fd55b00f..acce33da73 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dab6a32847ce17f12e3a2b09a3567945b2154f67 \ No newline at end of file +9e2c17c5358b156b588542dbba38da7fedf5302b \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 1be2871fed..d5fa9c6963 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1564,11 +1564,11 @@ static sqlite3_int64 integerValue(const char *zArg){ }else if( zArg[0]=='+' ){ zArg++; } - while( isdigit(zArg[0]) ){ + while( IsDigit(zArg[0]) ){ v = v*10 + zArg[0] - '0'; zArg++; } - for(i=0; i Date: Fri, 24 May 2013 12:47:26 +0000 Subject: [PATCH 027/144] Set _XOPEN_SOURCE to 600 so that fchmod() will (hopefully) work on FreeBSD. FossilOrigin-Name: 61a10452399db28cd5ea4ba9d416b87a34c2eddb --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqliteInt.h | 18 +++++------------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 03025b6aed..cf297405cb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings\sin\sthe\sshell. -D 2013-05-24T11:57:50.209 +C Set\s_XOPEN_SOURCE\sto\s600\sso\sthat\sfchmod()\swill\s(hopefully)\swork\son\sFreeBSD. +D 2013-05-24T12:47:26.703 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -196,7 +196,7 @@ F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 4cc782c9a89b3ddd663e7f68af3fa9e5af596f8b +F src/sqliteInt.h ba610d80822135ffbc92ac90710939e548c6a850 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P dab6a32847ce17f12e3a2b09a3567945b2154f67 -R 659d4081538710ab3b6917b836242fc7 +P 9e2c17c5358b156b588542dbba38da7fedf5302b +R 447bfb9d68d03e84058ef9e235e367ce U drh -Z b1f0db700bf1651929699f229849ec18 +Z 0a3675dfa27f37f077377df6c72c7598 diff --git a/manifest.uuid b/manifest.uuid index acce33da73..d490615225 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9e2c17c5358b156b588542dbba38da7fedf5302b \ No newline at end of file +61a10452399db28cd5ea4ba9d416b87a34c2eddb \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5950f237d9..d735a145ae 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -193,20 +193,12 @@ /* ** We need to define _XOPEN_SOURCE as follows in order to enable -** recursive mutexes on most Unix systems. But Mac OS X is different. -** The _XOPEN_SOURCE define causes problems for Mac OS X we are told, -** so it is omitted there. See ticket #2673. -** -** Later we learn that _XOPEN_SOURCE is poorly or incorrectly -** implemented on some systems. So we avoid defining it at all -** if it is already defined or if it is unneeded because we are -** not doing a threadsafe build. Ticket #2681. -** -** See also ticket #2741. +** recursive mutexes on most Unix systems and fchmod() on OpenBSD. +** But _XOPEN_SOURCE define causes problems for Mac OS X, so omit +** it. */ -#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) \ - && !defined(__APPLE__) && SQLITE_THREADSAFE -# define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */ +#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) +# define _XOPEN_SOURCE 600 #endif /* From 3bd26f0543ec42e0985ffbaa8f8d927fcb690de6 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 24 May 2013 14:52:03 +0000 Subject: [PATCH 028/144] Record in the WhereLoop object the set of virtual table constraints that need not be separately checked. FossilOrigin-Name: b49fa74561f38c945be6149693678fd6518c2de4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 8 ++++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 579e939060..010739cba8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\slatest\strunk\schanges\sinto\sthe\sNGQP\sbranch. -D 2013-05-24T13:55:23.561 +C Record\sin\sthe\sWhereLoop\sobject\sthe\sset\sof\svirtual\stable\sconstraints\sthat\nneed\snot\sbe\sseparately\schecked. +D 2013-05-24T14:52:03.958 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -265,7 +265,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 627bf1af3ab30e1efcc7ac362b15e7e945e9250d +F src/where.c 2fd11c00ffc37a65b762c8b2bbf5710723eefdd7 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P f783e8e6b10de44029c7c5f57e4648a4a677ca1b 61a10452399db28cd5ea4ba9d416b87a34c2eddb -R 5ae2bb9eca4144ac9f28ec145cae1f78 +P 7c8f992c04504a132686ad0652efdff19e43480d +R 91429a505370ccdd08f4d1fe64f3bf63 U drh -Z e63f19ec26c366b47598ade89ccbddd5 +Z 676fd5c7993f5cc12a1abed75be6a4c4 diff --git a/manifest.uuid b/manifest.uuid index 1dd79ce63e..bec1afe37d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c8f992c04504a132686ad0652efdff19e43480d \ No newline at end of file +b49fa74561f38c945be6149693678fd6518c2de4 \ No newline at end of file diff --git a/src/where.c b/src/where.c index fa38b57383..6416dd9503 100644 --- a/src/where.c +++ b/src/where.c @@ -76,6 +76,7 @@ struct WhereLoop { int idxNum; /* Index number */ u8 needFree; /* True if sqlite3_free(idxStr) is needed */ u8 isOrdered; /* True if satisfies ORDER BY */ + u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ } vtab; } u; @@ -5101,9 +5102,10 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ }else{ char *z; if( p->u.vtab.idxStr ){ - z = sqlite3_mprintf("(%d,\"%s\")", p->u.vtab.idxNum,p->u.vtab.idxStr); + z = sqlite3_mprintf("(%d,\"%s\",%x)", + p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask); }else{ - z = sqlite3_mprintf("(%d)", p->u.vtab.idxNum); + z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask); } sqlite3DebugPrintf(" %-15s", z); sqlite3_free(z); @@ -5629,6 +5631,7 @@ static int whereLoopAddVirtual( pNew->prereq = 0; mxTerm = -1; for(i=0; imxTerm; i++) pNew->aTerm[i] = 0; + pNew->u.vtab.omitMask = 0; for(i=0; inConstraint; i++, pIdxCons++){ if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){ if( iTerm>=pBuilder->mxTerm ) break; @@ -5646,6 +5649,7 @@ static int whereLoopAddVirtual( pNew->prereq |= pTerm->prereqRight; pNew->aTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; + if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ if( pUsage[i].omit==0 ){ /* Do not attempt to use an IN constraint if the virtual table From 87ddfeb079a3d67cbfa1334d9cce5b31263f3d13 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 27 May 2013 10:11:53 +0000 Subject: [PATCH 029/144] When writing to an FTS table, take an exclusive shared-cache lock on the %_segdir table before writing. Otherwise, an xCommit() call may report an SQLITE_LOCKED error. FossilOrigin-Name: 3cd2da42e9403b1e6243ad53f3f2bbf89c0fb9b0 --- ext/fts3/fts3.c | 4 -- ext/fts3/fts3_write.c | 44 ++++++++---------- manifest | 20 ++++---- manifest.uuid | 2 +- test/fts3shared.test | 105 ++++++++++++++++++++++++++++++++++++++++++ test/trace2.test | 1 + 6 files changed, 137 insertions(+), 39 deletions(-) diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index c00a13f5a1..374d690688 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -2984,11 +2984,7 @@ static int fts3FilterMethod( return rc; } - rc = sqlite3Fts3ReadLock(p); - if( rc!=SQLITE_OK ) return rc; - rc = fts3EvalStart(pCsr); - sqlite3Fts3SegmentsClose(p); if( rc!=SQLITE_OK ) return rc; pCsr->pNextId = pCsr->aDoclist; diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 269d1dd599..2ee0e3d5fa 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -489,37 +489,30 @@ static void fts3SqlExec( /* -** This function ensures that the caller has obtained a shared-cache -** table-lock on the %_content table. This is required before reading -** data from the fts3 table. If this lock is not acquired first, then -** the caller may end up holding read-locks on the %_segments and %_segdir -** tables, but no read-lock on the %_content table. If this happens -** a second connection will be able to write to the fts3 table, but -** attempting to commit those writes might return SQLITE_LOCKED or -** SQLITE_LOCKED_SHAREDCACHE (because the commit attempts to obtain -** write-locks on the %_segments and %_segdir ** tables). +** This function ensures that the caller has obtained an exclusive +** shared-cache table-lock on the %_segdir table. This is required before +** writing data to the fts3 table. If this lock is not acquired first, then +** the caller may end up attempting to take this lock as part of committing +** a transaction, causing SQLite to return SQLITE_LOCKED or +** LOCKED_SHAREDCACHEto a COMMIT command. ** -** We try to avoid this because if FTS3 returns any error when committing -** a transaction, the whole transaction will be rolled back. And this is -** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can -** still happen if the user reads data directly from the %_segments or -** %_segdir tables instead of going through FTS3 though. -** -** This reasoning does not apply to a content=xxx table. +** It is best to avoid this because if FTS3 returns any error when +** committing a transaction, the whole transaction will be rolled back. +** And this is not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. +** It can still happen if the user locks the underlying tables directly +** instead of accessing them via FTS. */ -int sqlite3Fts3ReadLock(Fts3Table *p){ - int rc; /* Return code */ - sqlite3_stmt *pStmt; /* Statement used to obtain lock */ - - if( p->zContentTbl==0 ){ - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); +static int fts3Writelock(Fts3Table *p){ + int rc = SQLITE_OK; + + if( p->nPendingData==0 ){ + sqlite3_stmt *pStmt; + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_null(pStmt, 1); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); } - }else{ - rc = SQLITE_OK; } return rc; @@ -5297,6 +5290,9 @@ int sqlite3Fts3UpdateMethod( aSzIns = &aSzDel[p->nColumn+1]; memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2); + rc = fts3Writelock(p); + if( rc!=SQLITE_OK ) goto update_out; + /* If this is an INSERT operation, or an UPDATE that modifies the rowid ** value, then this operation requires constraint handling. ** diff --git a/manifest b/manifest index cf297405cb..29a52f2578 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Set\s_XOPEN_SOURCE\sto\s600\sso\sthat\sfchmod()\swill\s(hopefully)\swork\son\sFreeBSD. -D 2013-05-24T12:47:26.703 +C When\swriting\sto\san\sFTS\stable,\stake\san\sexclusive\sshared-cache\slock\son\sthe\s%_segdir\stable\sbefore\swriting.\sOtherwise,\san\sxCommit()\scall\smay\sreport\san\sSQLITE_LOCKED\serror. +D 2013-05-27T10:11:53.308 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -55,7 +55,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 4bc160e6ff9ab5456b600f389f8941485ea5082f +F ext/fts3/fts3.c 931b3c83abdd1ab3bb389b2130431c2a9ff73b91 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 0b167bed9e63151635620a4f639bc62ac6012cba F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd @@ -73,7 +73,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9 F ext/fts3/fts3_unicode2.c a863f05f758af36777dffc2facc898bc73fec896 -F ext/fts3/fts3_write.c d92c6cbe07363791cfe8b62b4dee67e6f8afc9e2 +F ext/fts3/fts3_write.c 6a1fc0e922e76b68e594bf7bc33bac72af9dc47b F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197 @@ -513,7 +513,7 @@ F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1 F test/fts3prefix2.test 477ca96e67f60745b7ac931cfa6e9b080c562da5 F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2 F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0 -F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2 +F test/fts3shared.test c2f60e152e8554549eb25f0a7593ea01389c5037 F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2 F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659 F test/fts3tok1.test 4d9e7401679dc71f6b2f76416309b923210bfdbe @@ -924,7 +924,7 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1 F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7 F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5 -F test/trace2.test c1dc104a8d11a347c870cfea6235e3fc6f6cb06d +F test/trace2.test e7a988fdd982cdec62f1f1f34b0360e6476d01a0 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22 F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732 @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 9e2c17c5358b156b588542dbba38da7fedf5302b -R 447bfb9d68d03e84058ef9e235e367ce -U drh -Z 0a3675dfa27f37f077377df6c72c7598 +P 61a10452399db28cd5ea4ba9d416b87a34c2eddb +R 5b2b7d523083ab3d77d86c0cce4d267d +U dan +Z 5b590f475035536f2f371b845c79a1e4 diff --git a/manifest.uuid b/manifest.uuid index d490615225..cd1334fa37 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -61a10452399db28cd5ea4ba9d416b87a34c2eddb \ No newline at end of file +3cd2da42e9403b1e6243ad53f3f2bbf89c0fb9b0 \ No newline at end of file diff --git a/test/fts3shared.test b/test/fts3shared.test index 5f75bd5fe6..a587a437bf 100644 --- a/test/fts3shared.test +++ b/test/fts3shared.test @@ -1,3 +1,4 @@ +# # 2010 September 17 # # May you do good and not evil. @@ -5,6 +6,9 @@ # May you share freely, never taking more than you give. # #*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is the interactions between the FTS3/4 module +# and shared-cache mode. # set testdir [file dirname $argv0] @@ -14,6 +18,7 @@ ifcapable !fts3||!shared_cache { finish_test return } +set ::testprefix fts3shared db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] @@ -67,6 +72,106 @@ do_test fts3shared-1.6 { sqlite3_get_autocommit db2 } 0 db close db2 close +#------------------------------------------------------------------------- +# The following tests - fts3shared-2.* - test that unless FTS is bypassed +# and the underlying tables accessed directly, it is not possible for an +# SQLITE_LOCKED error to be enountered when committing an FTS transaction. +# +# Any SQLITE_LOCKED error should be returned when the fts4 (or fts4aux) +# table is first read/written within a transaction, not later on. +# +set LOCKED {1 {database table is locked}} +forcedelete test.db +sqlite3 dbR test.db +sqlite3 dbW test.db +do_test 2.1 { + execsql { + CREATE VIRTUAL TABLE t1 USING fts4; + CREATE TABLE t2ext(a, b); + CREATE VIRTUAL TABLE t2 USING fts4(content=t2ext); + CREATE VIRTUAL TABLE t1aux USING fts4aux(t1); + CREATE VIRTUAL TABLE t2aux USING fts4aux(t2); + + INSERT INTO t1 VALUES('a b c'); + INSERT INTO t2(rowid, a, b) VALUES(1, 'd e f', 'g h i'); + } dbW +} {} + +# Test that once [dbW] has written to the FTS table, no client may read +# from the FTS or fts4aux table. +do_test 2.2.1 { + execsql { + BEGIN; + INSERT INTO t1 VALUES('j k l'); + } dbW + execsql BEGIN dbR +} {} +do_test 2.2.2 { catchsql "SELECT * FROM t1 WHERE rowid=1" dbR } $LOCKED +do_test 2.2.3 { catchsql "SELECT * FROM t1 WHERE t1 MATCH 'a'" dbR } $LOCKED +do_test 2.2.4 { catchsql "SELECT rowid FROM t1 WHERE t1 MATCH 'a'" dbR } $LOCKED +do_test 2.2.5 { catchsql "SELECT * FROM t1" dbR } $LOCKED +do_test 2.2.6 { catchsql "SELECT * FROM t1aux" dbR } $LOCKED +do_test 2.2.7 { execsql COMMIT dbW } {} +do_test 2.2.8 { execsql COMMIT dbR } {} + +# Same test as 2.2.*, except with a content= table. +# +do_test 2.3.1 { + execsql { + BEGIN; + INSERT INTO t2(rowid, a, b) VALUES(2, 'j k l', 'm n o'); + } dbW + execsql BEGIN dbR +} {} +do_test 2.3.3 { catchsql "SELECT * FROM t2 WHERE t2 MATCH 'a'" dbR } $LOCKED +do_test 2.3.4 { catchsql "SELECT rowid FROM t2 WHERE t2 MATCH 'a'" dbR } $LOCKED +do_test 2.3.6 { catchsql "SELECT * FROM t2aux" dbR } $LOCKED +do_test 2.3.7 { execsql COMMIT dbW } {} +do_test 2.3.8 { execsql COMMIT dbR } {} + +# Test that once a connection has read from the FTS or fts4aux table, +# another connection may not write to the FTS table. +# +foreach {tn sql} { + 1 "SELECT * FROM t1 WHERE rowid=1" + 2 "SELECT * FROM t1 WHERE t1 MATCH 'a'" + 3 "SELECT rowid FROM t1 WHERE t1 MATCH 'a'" + 4 "SELECT * FROM t1" + 5 "SELECT * FROM t1aux" +} { + + do_test 2.4.$tn { + execsql BEGIN dbR + execsql $::sql dbR + execsql BEGIN dbW + catchsql "INSERT INTO t1 VALUES('p q r')" dbW + } $LOCKED + + execsql ROLLBACK dbR + execsql ROLLBACK dbW +} + +# Same test as 2.4.*, except with a content= table. +# +foreach {tn sql} { + 2 "SELECT * FROM t2 WHERE t2 MATCH 'a'" + 3 "SELECT rowid FROM t2 WHERE t2 MATCH 'a'" + 5 "SELECT * FROM t2aux" +} { + + do_test 2.5.$tn { + execsql BEGIN dbR + execsql $::sql dbR + execsql BEGIN dbW + catchsql "INSERT INTO t2(rowid, a, b) VALUES(3, 's t u', 'v w x')" dbW + } $LOCKED + + execsql ROLLBACK dbR + execsql ROLLBACK dbW +} + +dbW close +dbR close sqlite3_enable_shared_cache $::enable_shared_cache finish_test diff --git a/test/trace2.test b/test/trace2.test index 2f7ae7d5a2..8f68d87585 100644 --- a/test/trace2.test +++ b/test/trace2.test @@ -128,6 +128,7 @@ ifcapable fts3 { INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph'); } { "INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph');" + "-- DELETE FROM 'main'.'x1_segdir' WHERE level = ?" "-- INSERT INTO 'main'.'x1_content' VALUES(?,(?))" "-- REPLACE INTO 'main'.'x1_docsize' VALUES(?,?)" "-- SELECT value FROM 'main'.'x1_stat' WHERE id=?" From f6f8ac61041a5f8793d2e2ca9ac978cfc406de57 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 27 May 2013 17:19:58 +0000 Subject: [PATCH 030/144] Add the files used to build the amalgamation-autoconf package. FossilOrigin-Name: 048865e8fdd2bef6b43b6cebd45fae94c8a1ab20 --- autoconf/INSTALL | 370 ++ autoconf/Makefile.am | 19 + autoconf/README | 32 + autoconf/README.first | 57 + autoconf/config.guess | 1530 +++++ autoconf/config.sub | 1773 ++++++ autoconf/configure.ac | 108 + autoconf/depcomp | 708 +++ autoconf/install-sh | 527 ++ autoconf/ltmain.sh | 9655 +++++++++++++++++++++++++++++ autoconf/missing | 331 + autoconf/tea/Makefile.in | 439 ++ autoconf/tea/README | 36 + autoconf/tea/aclocal.m4 | 9 + autoconf/tea/configure.in | 200 + autoconf/tea/doc/sqlite3.n | 15 + autoconf/tea/license.terms | 6 + autoconf/tea/pkgIndex.tcl.in | 7 + autoconf/tea/tclconfig/install-sh | 119 + autoconf/tea/tclconfig/tcl.m4 | 3997 ++++++++++++ autoconf/tea/win/makefile.vc | 414 ++ autoconf/tea/win/nmakehlp.c | 694 +++ autoconf/tea/win/rules.vc | 711 +++ manifest | 36 +- manifest.uuid | 2 +- 25 files changed, 21789 insertions(+), 6 deletions(-) create mode 100644 autoconf/INSTALL create mode 100644 autoconf/Makefile.am create mode 100644 autoconf/README create mode 100644 autoconf/README.first create mode 100755 autoconf/config.guess create mode 100755 autoconf/config.sub create mode 100644 autoconf/configure.ac create mode 100755 autoconf/depcomp create mode 100755 autoconf/install-sh create mode 100644 autoconf/ltmain.sh create mode 100755 autoconf/missing create mode 100644 autoconf/tea/Makefile.in create mode 100644 autoconf/tea/README create mode 100644 autoconf/tea/aclocal.m4 create mode 100644 autoconf/tea/configure.in create mode 100644 autoconf/tea/doc/sqlite3.n create mode 100644 autoconf/tea/license.terms create mode 100644 autoconf/tea/pkgIndex.tcl.in create mode 100644 autoconf/tea/tclconfig/install-sh create mode 100644 autoconf/tea/tclconfig/tcl.m4 create mode 100644 autoconf/tea/win/makefile.vc create mode 100644 autoconf/tea/win/nmakehlp.c create mode 100644 autoconf/tea/win/rules.vc diff --git a/autoconf/INSTALL b/autoconf/INSTALL new file mode 100644 index 0000000000..a1e89e18ad --- /dev/null +++ b/autoconf/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am new file mode 100644 index 0000000000..6fc4f33c0e --- /dev/null +++ b/autoconf/Makefile.am @@ -0,0 +1,19 @@ + +AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE + +lib_LTLIBRARIES = libsqlite3.la +libsqlite3_la_SOURCES = sqlite3.c +libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 + +bin_PROGRAMS = sqlite3 +sqlite3_SOURCES = shell.c sqlite3.h +sqlite3_LDADD = $(top_builddir)/libsqlite3.la @READLINE_LIBS@ +sqlite3_DEPENDENCIES = $(top_builddir)/libsqlite3.la + +include_HEADERS = sqlite3.h sqlite3ext.h + +EXTRA_DIST = sqlite3.1 tea +pkgconfigdir = ${libdir}/pkgconfig +pkgconfig_DATA = sqlite3.pc + +man_MANS = sqlite3.1 diff --git a/autoconf/README b/autoconf/README new file mode 100644 index 0000000000..dd8cca24bd --- /dev/null +++ b/autoconf/README @@ -0,0 +1,32 @@ + +This package contains: + + * the SQLite library amalgamation (single file) source code distribution, + * the shell.c file used to build the sqlite3 shell too, and + * the sqlite3.h and sqlite3ext.h header files required to link programs + and sqlite extensions against the installed libary. + * autoconf/automake installation infrastucture. + +The generic installation instructions for autoconf/automake are found +in the INSTALL file. + +The following SQLite specific boolean options are supported: + + --enable-readline use readline in shell tool [default=yes] + --enable-threadsafe build a thread-safe library [default=yes] + --enable-dynamic-extensions support loadable extensions [default=yes] + +The default value for the CFLAGS variable (options passed to the C +compiler) includes debugging symbols in the build, resulting in larger +binaries than are necessary. Override it on the configure command +line like this: + + $ CFLAGS="-Os" ./configure + +to produce a smaller installation footprint. + +Other SQLite compilation parameters can also be set using CFLAGS. For +example: + + $ CFLAGS="-Os -DSQLITE_OMIT_TRIGGERS" ./configure + diff --git a/autoconf/README.first b/autoconf/README.first new file mode 100644 index 0000000000..6676228ad6 --- /dev/null +++ b/autoconf/README.first @@ -0,0 +1,57 @@ + +This file describes how to use the files in this directory to create a new +version of the "autoconf-amalgamation" package. + +1. The following files should have executable permission: + + chmod 755 install-sh + chmod 755 missing + chmod 755 depcomp + chmod 755 config.sub + chmod 755 config.guess + +2. Copy new versions of the following SQLite files into this directory: + + sqlite3.c + sqlite3.h + sqlite3ext.h + sqlite3.1 + sqlite3.pc.in + shell.c + +3. Update the SQLite version number in the AC_INIT macro in file + configure.ac: + + AC_INIT(sqlite, 3.6.3, http://www.sqlite.org) + +4. Run the following commands to push the version number change through + to the generated files. + + aclocal + autoconf + automake + +5. Create the tclsqlite3.c file in the tea/generic directory. As follows: + + mkdir -p tea/generic + echo "#ifdef USE_SYSTEM_SQLITE" > tea/generic/tclsqlite3.c + echo "# include " >> tea/generic/tclsqlite3.c + echo "#else" >> tea/generic/tclsqlite3.c + echo "#include \"../../sqlite3.c\"" >> tea/generic/tclsqlite3.c + echo "#endif" >> tea/generic/tclsqlite3.c + cat ../src/tclsqlite.c >> tea/generic/tclsqlite3.c + +6. Update the SQLite version in the AC_INIT macro in file tea/configure.in: + + AC_INIT([sqlite], [3.6.3]) + +7. From the 'tea' directory, run the following commands: + + autoconf + rm -rf autom4te.cache + +8. Run "./configure && make dist". This builds a distribution package + named something like "sqlite-3.6.3.tar.gz". Rename to + "sqlite-amalgamation-3.6.3.tar.gz" and use. + + diff --git a/autoconf/config.guess b/autoconf/config.guess new file mode 100755 index 0000000000..d622a44e55 --- /dev/null +++ b/autoconf/config.guess @@ -0,0 +1,1530 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/autoconf/config.sub b/autoconf/config.sub new file mode 100755 index 0000000000..c894da4550 --- /dev/null +++ b/autoconf/config.sub @@ -0,0 +1,1773 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ + | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i386-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/autoconf/configure.ac b/autoconf/configure.ac new file mode 100644 index 0000000000..46b6563edc --- /dev/null +++ b/autoconf/configure.ac @@ -0,0 +1,108 @@ + +#----------------------------------------------------------------------- +# Supports the following non-standard switches. +# +# --enable-threadsafe +# --enable-readline +# --enable-dynamic-extensions +# + +AC_PREREQ(2.61) +AC_INIT(sqlite, 3.7.5, http://www.sqlite.org) +AC_CONFIG_SRCDIR([sqlite3.c]) + +# Use automake. +AM_INIT_AUTOMAKE([foreign]) + +AC_SYS_LARGEFILE + +# Check for required programs. +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_LIBTOOL +AC_PROG_MKDIR_P + +# Check for library functions that SQLite can optionally use. +AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r]) +AC_FUNC_STRERROR_R + +AC_CONFIG_FILES([Makefile sqlite3.pc]) +AC_SUBST(BUILD_CFLAGS) + +#----------------------------------------------------------------------- +# --enable-readline +# +AC_ARG_ENABLE(readline, [AS_HELP_STRING( + [--enable-readline], + [use readline in shell tool (yes, no) [default=yes]])], + [], [enable_readline=yes]) +if test x"$enable_readline" != xno ; then + sLIBS=$LIBS + LIBS="" + AC_SEARCH_LIBS(tgetent, curses ncurses ncursesw, [], []) + AC_SEARCH_LIBS(readline, readline, [], [enable_readline=no]) + AC_CHECK_FUNCS(readline, [], []) + READLINE_LIBS=$LIBS + LIBS=$sLIBS +fi +AC_SUBST(READLINE_LIBS) +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# --enable-threadsafe +# +AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING( + [--enable-threadsafe], [build a thread-safe library [default=yes]])], + [], [enable_threadsafe=yes]) +THREADSAFE_FLAGS=-DSQLITE_THREADSAFE=0 +if test x"$enable_threadsafe" != "xno"; then + THREADSAFE_FLAGS="-D_REENTRANT=1 -DSQLITE_THREADSAFE=1" + AC_SEARCH_LIBS(pthread_create, pthread) +fi +AC_SUBST(THREADSAFE_FLAGS) +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# --enable-dynamic-extensions +# +AC_ARG_ENABLE(dynamic-extensions, [AS_HELP_STRING( + [--enable-dynamic-extensions], [support loadable extensions [default=yes]])], + [], [enable_dynamic_extensions=yes]) +if test x"$enable_dynamic_extensions" != "xno"; then + AC_SEARCH_LIBS(dlopen, dl) +else + DYNAMIC_EXTENSION_FLAGS=-DSQLITE_OMIT_LOAD_EXTENSION=1 +fi +AC_MSG_CHECKING([for whether to support dynamic extensions]) +AC_MSG_RESULT($enable_dynamic_extensions) +AC_SUBST(DYNAMIC_EXTENSION_FLAGS) +#----------------------------------------------------------------------- + +AC_CHECK_FUNCS(posix_fallocate) + +#----------------------------------------------------------------------- +# UPDATE: Maybe it's better if users just set CFLAGS before invoking +# configure. This option doesn't really add much... +# +# --enable-tempstore +# +# AC_ARG_ENABLE(tempstore, [AS_HELP_STRING( +# [--enable-tempstore], +# [in-memory temporary tables (never, no, yes, always) [default=no]])], +# [], [enable_tempstore=no]) +# AC_MSG_CHECKING([for whether or not to store temp tables in-memory]) +# case "$enable_tempstore" in +# never ) TEMP_STORE=0 ;; +# no ) TEMP_STORE=1 ;; +# always ) TEMP_STORE=3 ;; +# yes ) TEMP_STORE=3 ;; +# * ) +# TEMP_STORE=1 +# enable_tempstore=yes +# ;; +# esac +# AC_MSG_RESULT($enable_tempstore) +# AC_SUBST(TEMP_STORE) +#----------------------------------------------------------------------- + +AC_OUTPUT diff --git a/autoconf/depcomp b/autoconf/depcomp new file mode 100755 index 0000000000..25a39e6cd5 --- /dev/null +++ b/autoconf/depcomp @@ -0,0 +1,708 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2012-03-27.16; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' "$nl" < "$tmpdepfile" | +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like '#:fec' to the end of the + # dependency line. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependent.h'. + # Do two passes, one to just change these to + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. + # However on + # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\': + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + # tcc 0.9.26 (FIXME still under development at the moment of writing) + # will emit a similar output, but also prepend the continuation lines + # with horizontal tabulation characters. + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form 'foo.o: dependent.h', + # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. + # Do two passes, one to just change these to + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ + < "$tmpdepfile" > "$depfile" + sed ' + s/[ '"$tab"'][ '"$tab"']*/ /g + s/^ *// + s/ *\\*$// + s/^[^:]*: *// + /^$/d + /:$/d + s/$/ :/ + ' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test "$stat" = 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' "$nl" < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/autoconf/install-sh b/autoconf/install-sh new file mode 100755 index 0000000000..a9244eb078 --- /dev/null +++ b/autoconf/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-01-19.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for `test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/autoconf/ltmain.sh b/autoconf/ltmain.sh new file mode 100644 index 0000000000..6a2f1166a9 --- /dev/null +++ b/autoconf/ltmain.sh @@ -0,0 +1,9655 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.4.2 +TIMESTAMP="" +package_revision=1.3337 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + #func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + #test "$absdir" != "$libdir" && \ + # func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/autoconf/missing b/autoconf/missing new file mode 100755 index 0000000000..86a8fc31e3 --- /dev/null +++ b/autoconf/missing @@ -0,0 +1,331 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2012-01-06.13; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/autoconf/tea/Makefile.in b/autoconf/tea/Makefile.in new file mode 100644 index 0000000000..08b1a44182 --- /dev/null +++ b/autoconf/tea/Makefile.in @@ -0,0 +1,439 @@ +# Makefile.in -- +# +# This file is a Makefile for Sample TEA Extension. If it has the name +# "Makefile.in" then it is a template for a Makefile; to generate the +# actual Makefile, run "./configure", which is a configuration script +# generated by the "autoconf" program (constructs like "@foo@" will get +# replaced in the actual Makefile. +# +# Copyright (c) 1999 Scriptics Corporation. +# Copyright (c) 2002-2005 ActiveState Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: Makefile.in,v 1.59 2005/07/26 19:17:02 mdejong Exp $ + +#======================================================================== +# Add additional lines to handle any additional AC_SUBST cases that +# have been added in a customized configure script. +#======================================================================== + +#SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ + +#======================================================================== +# Nothing of the variables below this line should need to be changed. +# Please check the TARGETS section below to make sure the make targets +# are correct. +#======================================================================== + +#======================================================================== +# The names of the source files is defined in the configure script. +# The object files are used for linking into the final library. +# This will be used when a dist target is added to the Makefile. +# It is not important to specify the directory, as long as it is the +# $(srcdir) or in the generic, win or unix subdirectory. +#======================================================================== + +PKG_SOURCES = @PKG_SOURCES@ +PKG_OBJECTS = @PKG_OBJECTS@ + +PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ +PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ + +#======================================================================== +# PKG_TCL_SOURCES identifies Tcl runtime files that are associated with +# this package that need to be installed, if any. +#======================================================================== + +PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ + +#======================================================================== +# This is a list of public header files to be installed, if any. +#======================================================================== + +PKG_HEADERS = @PKG_HEADERS@ + +#======================================================================== +# "PKG_LIB_FILE" refers to the library (dynamic or static as per +# configuration options) composed of the named objects. +#======================================================================== + +PKG_LIB_FILE = @PKG_LIB_FILE@ +PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ + +lib_BINARIES = $(PKG_LIB_FILE) +BINARIES = $(lib_BINARIES) + +SHELL = @SHELL@ + +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +libdir = @libdir@ +datadir = @datadir@ +mandir = @mandir@ +includedir = @includedir@ + +DESTDIR = + +PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) +pkgdatadir = $(datadir)/$(PKG_DIR) +pkglibdir = $(libdir)/$(PKG_DIR) +pkgincludedir = $(includedir)/$(PKG_DIR) + +top_builddir = . + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ + +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +CC = @CC@ +CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ +CFLAGS_WARNING = @CFLAGS_WARNING@ +CLEANFILES = @CLEANFILES@ +EXEEXT = @EXEEXT@ +LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ +MAKE_LIB = @MAKE_LIB@ +MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ +MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ +MAKE_STUB_LIB = @MAKE_STUB_LIB@ +OBJEXT = @OBJEXT@ +RANLIB = @RANLIB@ +RANLIB_STUB = @RANLIB_STUB@ +SHLIB_CFLAGS = @SHLIB_CFLAGS@ +SHLIB_LD = @SHLIB_LD@ +SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ +STLIB_LD = @STLIB_LD@ +#TCL_DEFS = @TCL_DEFS@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +#TK_BIN_DIR = @TK_BIN_DIR@ +#TK_SRC_DIR = @TK_SRC_DIR@ + +# This is no longer necessary even for packages that use private Tcl headers +#TCL_TOP_DIR_NATIVE = @TCL_TOP_DIR_NATIVE@ +# Not used, but retained for reference of what libs Tcl required +#TCL_LIBS = @TCL_LIBS@ + +#======================================================================== +# TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our +# package without installing. The other environment variables allow us +# to test against an uninstalled Tcl. Add special env vars that you +# require for testing here (like TCLX_LIBRARY). +#======================================================================== + +EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) +#EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) +TCLLIBPATH = $(top_builddir) +TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ + @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ + PATH="$(EXTRA_PATH):$(PATH)" \ + TCLLIBPATH="$(TCLLIBPATH)" +# TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` + +TCLSH_PROG = @TCLSH_PROG@ +TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) + +#WISH_PROG = @WISH_PROG@ +#WISH = $(TCLSH_ENV) $(WISH_PROG) + + +SHARED_BUILD = @SHARED_BUILD@ + +INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ -I$(srcdir)/.. +#INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ + +PKG_CFLAGS = @PKG_CFLAGS@ + +# TCL_DEFS is not strictly need here, but if you remove it, then you +# must make sure that configure.in checks for the necessary components +# that your library may use. TCL_DEFS can actually be a problem if +# you do not compile with a similar machine setup as the Tcl core was +# compiled with. +#DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) +DEFS = @DEFS@ $(PKG_CFLAGS) + +CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl + +CPPFLAGS = @CPPFLAGS@ +LIBS = @PKG_LIBS@ @LIBS@ +AR = @AR@ +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) + +#======================================================================== +# Start of user-definable TARGETS section +#======================================================================== + +#======================================================================== +# TEA TARGETS. Please note that the "libraries:" target refers to platform +# independent files, and the "binaries:" target inclues executable programs and +# platform-dependent libraries. Modify these targets so that they install +# the various pieces of your package. The make and install rules +# for the BINARIES that you specified above have already been done. +#======================================================================== + +all: binaries libraries doc + +#======================================================================== +# The binaries target builds executable programs, Windows .dll's, unix +# shared/static libraries, and any other platform-dependent files. +# The list of targets to build for "binaries:" is specified at the top +# of the Makefile, in the "BINARIES" variable. +#======================================================================== + +binaries: $(BINARIES) + +libraries: + + +#======================================================================== +# Your doc target should differentiate from doc builds (by the developer) +# and doc installs (see install-doc), which just install the docs on the +# end user machine when building from source. +#======================================================================== + +doc: + @echo "If you have documentation to create, place the commands to" + @echo "build the docs in the 'doc:' target. For example:" + @echo " xml2nroff sample.xml > sample.n" + @echo " xml2html sample.xml > sample.html" + +install: all install-binaries install-libraries install-doc + +install-binaries: binaries install-lib-binaries install-bin-binaries + +#======================================================================== +# This rule installs platform-independent files, such as header files. +# The list=...; for p in $$list handles the empty list case x-platform. +#======================================================================== + +install-libraries: libraries + @mkdir -p $(DESTDIR)$(includedir) + @echo "Installing header files in $(DESTDIR)$(includedir)" + @list='$(PKG_HEADERS)'; for i in $$list; do \ + echo "Installing $(srcdir)/$$i" ; \ + $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ + done; + +#======================================================================== +# Install documentation. Unix manpages should go in the $(mandir) +# directory. +#======================================================================== + +install-doc: doc + @mkdir -p $(DESTDIR)$(mandir)/mann + @echo "Installing documentation in $(DESTDIR)$(mandir)" + @list='$(srcdir)/doc/*.n'; for i in $$list; do \ + echo "Installing $$i"; \ + rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ + done + +test: binaries libraries + @echo "SQLite TEA distribution does not include tests" + +shell: binaries libraries + @$(TCLSH) $(SCRIPT) + +gdb: + $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) + +depend: + +#======================================================================== +# $(PKG_LIB_FILE) should be listed as part of the BINARIES variable +# mentioned above. That will ensure that this target is built when you +# run "make binaries". +# +# The $(PKG_OBJECTS) objects are created and linked into the final +# library. In most cases these object files will correspond to the +# source files above. +#======================================================================== + +$(PKG_LIB_FILE): $(PKG_OBJECTS) + -rm -f $(PKG_LIB_FILE) + ${MAKE_LIB} + $(RANLIB) $(PKG_LIB_FILE) + +$(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) + -rm -f $(PKG_STUB_LIB_FILE) + ${MAKE_STUB_LIB} + $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) + +#======================================================================== +# We need to enumerate the list of .c to .o lines here. +# +# In the following lines, $(srcdir) refers to the toplevel directory +# containing your extension. If your sources are in a subdirectory, +# you will have to modify the paths to reflect this: +# +# sample.$(OBJEXT): $(srcdir)/generic/sample.c +# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ +# +# Setting the VPATH variable to a list of paths will cause the makefile +# to look into these paths when resolving .c to .obj dependencies. +# As necessary, add $(srcdir):$(srcdir)/compat:.... +#======================================================================== + +VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win + +.c.@OBJEXT@: + $(COMPILE) -c `@CYGPATH@ $<` -o $@ + +#======================================================================== +# Distribution creation +# You may need to tweak this target to make it work correctly. +#======================================================================== + +#COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar +COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) +DIST_ROOT = /tmp/dist +DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) + +dist-clean: + rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* + +dist: dist-clean + mkdir -p $(DIST_DIR) + cp -p $(srcdir)/README* $(srcdir)/license* \ + $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ + $(DIST_DIR)/ + chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 + chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in + + for i in $(srcdir)/*.[ch]; do \ + if [ -f $$i ]; then \ + cp -p $$i $(DIST_DIR)/ ; \ + fi; \ + done; + + mkdir $(DIST_DIR)/tclconfig + cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ + $(DIST_DIR)/tclconfig/ + chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 + chmod +x $(DIST_DIR)/tclconfig/install-sh + + list='demos doc generic library mac tests unix win'; \ + for p in $$list; do \ + if test -d $(srcdir)/$$p ; then \ + mkdir $(DIST_DIR)/$$p; \ + cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ + fi; \ + done + + (cd $(DIST_ROOT); $(COMPRESS);) + +#======================================================================== +# End of user-definable section +#======================================================================== + +#======================================================================== +# Don't modify the file to clean here. Instead, set the "CLEANFILES" +# variable in configure.in +#======================================================================== + +clean: + -test -z "$(BINARIES)" || rm -f $(BINARIES) + -rm -f *.$(OBJEXT) core *.core + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean: clean + -rm -f *.tab.c + -rm -f $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log config.status + +#======================================================================== +# Install binary object libraries. On Windows this includes both .dll and +# .lib files. Because the .lib files are not explicitly listed anywhere, +# we need to deduce their existence from the .dll file of the same name. +# Library files go into the lib directory. +# In addition, this will generate the pkgIndex.tcl +# file in the install location (assuming it can find a usable tclsh shell) +# +# You should not have to modify this target. +#======================================================================== + +install-lib-binaries: binaries + @mkdir -p $(DESTDIR)$(pkglibdir) + @list='$(lib_BINARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ + stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ + if test "x$$stub" = "xstub"; then \ + echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ + $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ + else \ + echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ + $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ + fi; \ + ext=`echo $$p|sed -e "s/.*\.//"`; \ + if test "x$$ext" = "xdll"; then \ + lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ + if test -f $$lib; then \ + echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ + $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ + fi; \ + fi; \ + fi; \ + done + @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + destp=`basename $$p`; \ + echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ + $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ + fi; \ + done + @if test "x$(SHARED_BUILD)" = "x1"; then \ + echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ + $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ + fi + +#======================================================================== +# Install binary executables (e.g. .exe files and dependent .dll files) +# This is for files that must go in the bin directory (located next to +# wish and tclsh), like dependent .dll files on Windows. +# +# You should not have to modify this target, except to define bin_BINARIES +# above if necessary. +#======================================================================== + +install-bin-binaries: binaries + @mkdir -p $(DESTDIR)$(bindir) + @list='$(bin_BINARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ + fi; \ + done + +.SUFFIXES: .c .$(OBJEXT) + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +uninstall-binaries: + list='$(lib_BINARIES)'; for p in $$list; do \ + rm -f $(DESTDIR)$(pkglibdir)/$$p; \ + done + list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ + p=`basename $$p`; \ + rm -f $(DESTDIR)$(pkglibdir)/$$p; \ + done + list='$(bin_BINARIES)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/$$p; \ + done + +.PHONY: all binaries clean depend distclean doc install libraries test + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/autoconf/tea/README b/autoconf/tea/README new file mode 100644 index 0000000000..99dc8b8f03 --- /dev/null +++ b/autoconf/tea/README @@ -0,0 +1,36 @@ +This is the SQLite extension for Tcl using the Tcl Extension +Architecture (TEA). For additional information on SQLite see + + http://www.sqlite.org/ + + +UNIX BUILD +========== + +Building under most UNIX systems is easy, just run the configure script +and then run make. For more information about the build process, see +the tcl/unix/README file in the Tcl src dist. The following minimal +example will install the extension in the /opt/tcl directory. + + $ cd sqlite-*-tea + $ ./configure --prefix=/opt/tcl + $ make + $ make install + +WINDOWS BUILD +============= + +The recommended method to build extensions under windows is to use the +Msys + Mingw build process. This provides a Unix-style build while +generating native Windows binaries. Using the Msys + Mingw build tools +means that you can use the same configure script as per the Unix build +to create a Makefile. See the tcl/win/README file for the URL of +the Msys + Mingw download. + +If you have VC++ then you may wish to use the files in the win +subdirectory and build the extension using just VC++. These files have +been designed to be as generic as possible but will require some +additional maintenance by the project developer to synchronise with +the TEA configure.in and Makefile.in files. Instructions for using the +VC++ makefile are written in the first part of the Makefile.vc +file. diff --git a/autoconf/tea/aclocal.m4 b/autoconf/tea/aclocal.m4 new file mode 100644 index 0000000000..0b057391d2 --- /dev/null +++ b/autoconf/tea/aclocal.m4 @@ -0,0 +1,9 @@ +# +# Include the TEA standard macro set +# + +builtin(include,tclconfig/tcl.m4) + +# +# Add here whatever m4 macros you want to define for your package +# diff --git a/autoconf/tea/configure.in b/autoconf/tea/configure.in new file mode 100644 index 0000000000..ec9c565c6f --- /dev/null +++ b/autoconf/tea/configure.in @@ -0,0 +1,200 @@ +#!/bin/bash -norc +dnl This file is an input file used by the GNU "autoconf" program to +dnl generate the file "configure", which is run during Tcl installation +dnl to configure the system for the local environment. +# +# RCS: @(#) $Id: configure.in,v 1.43 2005/07/26 19:17:05 mdejong Exp $ + +#----------------------------------------------------------------------- +# Sample configure.in for Tcl Extensions. The only places you should +# need to modify this file are marked by the string __CHANGE__ +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# __CHANGE__ +# Set your package name and version numbers here. +# +# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION +# set as provided. These will also be added as -D defs in your Makefile +# so you can encode the package version directly into the source files. +#----------------------------------------------------------------------- + +AC_INIT([sqlite], [3.7.4]) + +#-------------------------------------------------------------------- +# Call TEA_INIT as the first TEA_ macro to set up initial vars. +# This will define a ${TEA_PLATFORM} variable == "unix" or "windows" +# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. +#-------------------------------------------------------------------- + +TEA_INIT([3.9]) + +AC_CONFIG_AUX_DIR(tclconfig) + +#-------------------------------------------------------------------- +# Load the tclConfig.sh file +#-------------------------------------------------------------------- + +TEA_PATH_TCLCONFIG +TEA_LOAD_TCLCONFIG + +#-------------------------------------------------------------------- +# Load the tkConfig.sh file if necessary (Tk extension) +#-------------------------------------------------------------------- + +#TEA_PATH_TKCONFIG +#TEA_LOAD_TKCONFIG + +#----------------------------------------------------------------------- +# Handle the --prefix=... option by defaulting to what Tcl gave. +# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. +#----------------------------------------------------------------------- + +TEA_PREFIX + +#----------------------------------------------------------------------- +# Standard compiler checks. +# This sets up CC by using the CC env var, or looks for gcc otherwise. +# This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create +# the basic setup necessary to compile executables. +#----------------------------------------------------------------------- + +TEA_SETUP_COMPILER + +#----------------------------------------------------------------------- +# __CHANGE__ +# Specify the C source files to compile in TEA_ADD_SOURCES, +# public headers that need to be installed in TEA_ADD_HEADERS, +# stub library C source files to compile in TEA_ADD_STUB_SOURCES, +# and runtime Tcl library files in TEA_ADD_TCL_SOURCES. +# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS +# and PKG_TCL_SOURCES. +#----------------------------------------------------------------------- + +TEA_ADD_SOURCES([tclsqlite3.c]) +TEA_ADD_HEADERS([]) +TEA_ADD_INCLUDES([-I\"`\${CYGPATH} \${srcdir}/generic`\"]) +TEA_ADD_LIBS([]) +TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1]) +TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1]) +TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1]) +TEA_ADD_CFLAGS([-DSQLITE_OMIT_DEPRECATED=1]) +TEA_ADD_STUB_SOURCES([]) +TEA_ADD_TCL_SOURCES([]) + +#-------------------------------------------------------------------- +# The --with-system-sqlite causes the TCL bindings to SQLite to use +# the system shared library for SQLite rather than statically linking +# against its own private copy. This is dangerous and leads to +# undersirable dependences and is not recommended. +# Patchs from rmax. +#-------------------------------------------------------------------- +AC_ARG_WITH([system-sqlite], + [AC_HELP_STRING([--with-system-sqlite], + [use a system-supplied libsqlite3 instead of the bundled one])], + [], [with_system_sqlite=no]) +if test x$with_system_sqlite != xno; then + AC_CHECK_HEADER([sqlite3.h], + [AC_CHECK_LIB([sqlite3],[sqlite3_initialize], + [AC_DEFINE(USE_SYSTEM_SQLITE) + LIBS="$LIBS -lsqlite3"])]) +fi + +#-------------------------------------------------------------------- +# __CHANGE__ +# Choose which headers you need. Extension authors should try very +# hard to only rely on the Tcl public header files. Internal headers +# contain private data structures and are subject to change without +# notice. +# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG +#-------------------------------------------------------------------- + +TEA_PUBLIC_TCL_HEADERS +#TEA_PRIVATE_TCL_HEADERS + +#TEA_PUBLIC_TK_HEADERS +#TEA_PRIVATE_TK_HEADERS +#TEA_PATH_X + +#-------------------------------------------------------------------- +# Check whether --enable-threads or --disable-threads was given. +# This auto-enables if Tcl was compiled threaded. +#-------------------------------------------------------------------- + +TEA_ENABLE_THREADS +if test "${TCL_THREADS}" = "1" ; then + AC_DEFINE(SQLITE_THREADSAFE, 1, [Trigger sqlite threadsafe build]) + # Not automatically added by Tcl because its assumed Tcl links to them, + # but it may not if it isn't really a threaded build. + TEA_ADD_LIBS([$THREADS_LIBS]) +else + AC_DEFINE(SQLITE_THREADSAFE, 0, [Trigger sqlite non-threadsafe build]) +fi + +#-------------------------------------------------------------------- +# The statement below defines a collection of symbols related to +# building as a shared library instead of a static library. +#-------------------------------------------------------------------- + +TEA_ENABLE_SHARED + +#-------------------------------------------------------------------- +# This macro figures out what flags to use with the compiler/linker +# when building shared/static debug/optimized objects. This information +# can be taken from the tclConfig.sh file, but this figures it all out. +#-------------------------------------------------------------------- + +TEA_CONFIG_CFLAGS + +#-------------------------------------------------------------------- +# Set the default compiler switches based on the --enable-symbols option. +#-------------------------------------------------------------------- + +TEA_ENABLE_SYMBOLS + +#-------------------------------------------------------------------- +# Everyone should be linking against the Tcl stub library. If you +# can't for some reason, remove this definition. If you aren't using +# stubs, you also need to modify the SHLIB_LD_LIBS setting below to +# link against the non-stubbed Tcl library. Add Tk too if necessary. +#-------------------------------------------------------------------- + +AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) +#AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) + + +#-------------------------------------------------------------------- +# Redefine fdatasync as fsync on systems that lack fdatasync +#-------------------------------------------------------------------- + +AC_CHECK_FUNC(fdatasync, , AC_DEFINE(fdatasync, fsync)) + +AC_FUNC_STRERROR_R + + +#-------------------------------------------------------------------- +# This macro generates a line to use when building a library. It +# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, +# and TEA_LOAD_TCLCONFIG macros above. +#-------------------------------------------------------------------- + +TEA_MAKE_LIB + +#-------------------------------------------------------------------- +# Determine the name of the tclsh and/or wish executables in the +# Tcl and Tk build directories or the location they were installed +# into. These paths are used to support running test cases only, +# the Makefile should not be making use of these paths to generate +# a pkgIndex.tcl file or anything else at extension build time. +#-------------------------------------------------------------------- + +TEA_PROG_TCLSH +#TEA_PROG_WISH + +#-------------------------------------------------------------------- +# Finally, substitute all of the various values into the Makefile. +# You may alternatively have a special pkgIndex.tcl.in or other files +# which require substituting th AC variables in. Include these here. +#-------------------------------------------------------------------- + +AC_OUTPUT([Makefile pkgIndex.tcl]) diff --git a/autoconf/tea/doc/sqlite3.n b/autoconf/tea/doc/sqlite3.n new file mode 100644 index 0000000000..cee765f94c --- /dev/null +++ b/autoconf/tea/doc/sqlite3.n @@ -0,0 +1,15 @@ +.TH sqlite3 n 4.1 "Tcl-Extensions" +.HS sqlite3 tcl +.BS +.SH NAME +sqlite3 \- an interface to the SQLite3 database engine +.SH SYNOPSIS +\fBsqlite3\fI command_name ?filename?\fR +.br +.SH DESCRIPTION +SQLite3 is a self-contains, zero-configuration, transactional SQL database +engine. This extension provides an easy to use interface for accessing +SQLite database files from Tcl. +.PP +For full documentation see http://www.sqlite.org/ and +in particular http://www.sqlite.org/tclsqlite.html. diff --git a/autoconf/tea/license.terms b/autoconf/tea/license.terms new file mode 100644 index 0000000000..723c4cd3c6 --- /dev/null +++ b/autoconf/tea/license.terms @@ -0,0 +1,6 @@ +The author disclaims copyright to this source code. In place of +a legal notice, here is a blessing: + + May you do good and not evil. + May you find forgiveness for yourself and forgive others. + May you share freely, never taking more than you give. diff --git a/autoconf/tea/pkgIndex.tcl.in b/autoconf/tea/pkgIndex.tcl.in new file mode 100644 index 0000000000..bc585f73b3 --- /dev/null +++ b/autoconf/tea/pkgIndex.tcl.in @@ -0,0 +1,7 @@ +# +# Tcl package index file +# +# Note sqlite*3* init specifically +# +package ifneeded sqlite3 @PACKAGE_VERSION@ \ + [list load [file join $dir @PKG_LIB_FILE@] Sqlite3] diff --git a/autoconf/tea/tclconfig/install-sh b/autoconf/tea/tclconfig/install-sh new file mode 100644 index 0000000000..0ff4b6a08e --- /dev/null +++ b/autoconf/tea/tclconfig/install-sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/autoconf/tea/tclconfig/tcl.m4 b/autoconf/tea/tclconfig/tcl.m4 new file mode 100644 index 0000000000..f910bc2a1f --- /dev/null +++ b/autoconf/tea/tclconfig/tcl.m4 @@ -0,0 +1,3997 @@ +# tcl.m4 -- +# +# This file provides a set of autoconf macros to help TEA-enable +# a Tcl extension. +# +# Copyright (c) 1999-2000 Ajuba Solutions. +# Copyright (c) 2002-2005 ActiveState Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: tcl.m4,v 1.145 2010/08/17 00:33:40 hobbs Exp $ + +AC_PREREQ(2.57) + +dnl TEA extensions pass us the version of TEA they think they +dnl are compatible with (must be set in TEA_INIT below) +dnl TEA_VERSION="3.9" + +# Possible values for key variables defined: +# +# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') +# TEA_PLATFORM - windows unix +# + +#------------------------------------------------------------------------ +# TEA_PATH_TCLCONFIG -- +# +# Locate the tclConfig.sh file and perform a sanity check on +# the Tcl compile flags +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tcl=... +# +# Defines the following vars: +# TCL_BIN_DIR Full path to the directory containing +# the tclConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_TCLCONFIG], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + AC_ARG_WITH(tcl, + AC_HELP_STRING([--with-tcl], + [directory containing tcl configuration (tclConfig.sh)]), + with_tclconfig="${withval}") + AC_MSG_CHECKING([for Tcl configuration]) + AC_CACHE_VAL(ac_cv_c_tclconfig,[ + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + case "${with_tclconfig}" in + */tclConfig.sh ) + if test -f "${with_tclconfig}"; then + AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) + with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + ; do + if test -f "$i/Tcl.framework/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + AC_MSG_ERROR([Can't find Tcl configuration definitions]) + else + no_tcl= + TCL_BIN_DIR="${ac_cv_c_tclconfig}" + AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_PATH_TKCONFIG -- +# +# Locate the tkConfig.sh file +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tk=... +# +# Defines the following vars: +# TK_BIN_DIR Full path to the directory containing +# the tkConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_TKCONFIG], [ + # + # Ok, lets find the tk configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tk + # + + if test x"${no_tk}" = x ; then + # we reset no_tk in case something fails here + no_tk=true + AC_ARG_WITH(tk, + AC_HELP_STRING([--with-tk], + [directory containing tk configuration (tkConfig.sh)]), + with_tkconfig="${withval}") + AC_MSG_CHECKING([for Tk configuration]) + AC_CACHE_VAL(ac_cv_c_tkconfig,[ + + # First check to see if --with-tkconfig was specified. + if test x"${with_tkconfig}" != x ; then + case "${with_tkconfig}" in + */tkConfig.sh ) + if test -f "${with_tkconfig}"; then + AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) + with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tkconfig}/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) + fi + fi + + # then check for a private Tk library + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + ; do + if test -f "$i/Tk.framework/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tkconfig}" = x ; then + TK_BIN_DIR="# no Tk configs found" + AC_MSG_ERROR([Can't find Tk configuration definitions]) + else + no_tk= + TK_BIN_DIR="${ac_cv_c_tkconfig}" + AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_TCLCONFIG -- +# +# Load the tclConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TCL_BIN_DIR +# +# Results: +# +# Subst the following vars: +# TCL_BIN_DIR +# TCL_SRC_DIR +# TCL_LIB_FILE +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_TCLCONFIG], [ + AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) + + if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TCL_BIN_DIR}/tclConfig.sh" + else + AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" + TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" + TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tcl.framework installed in an arbitrary location. + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then + for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ + "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then + TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" + break + fi + done + fi + if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then + TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" + TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + AC_SUBST(TCL_VERSION) + AC_SUBST(TCL_PATCH_LEVEL) + AC_SUBST(TCL_BIN_DIR) + AC_SUBST(TCL_SRC_DIR) + + AC_SUBST(TCL_LIB_FILE) + AC_SUBST(TCL_LIB_FLAG) + AC_SUBST(TCL_LIB_SPEC) + + AC_SUBST(TCL_STUB_LIB_FILE) + AC_SUBST(TCL_STUB_LIB_FLAG) + AC_SUBST(TCL_STUB_LIB_SPEC) + + case "`uname -s`" in + *CYGWIN_*) + AC_MSG_CHECKING([for cygwin variant]) + case ${TCL_EXTRA_CFLAGS} in + *-mwin32*|*-mno-cygwin*) + TEA_PLATFORM="windows" + CFLAGS="$CFLAGS -mwin32" + AC_MSG_RESULT([win32]) + ;; + *) + TEA_PLATFORM="unix" + AC_MSG_RESULT([unix]) + ;; + esac + EXEEXT=".exe" + ;; + *) + ;; + esac + + # Do this here as we have fully defined TEA_PLATFORM now + if test "${TEA_PLATFORM}" = "windows" ; then + # The BUILD_$pkg is to define the correct extern storage class + # handling when making this package + AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}) + CLEANFILES="$CLEANFILES *.lib *.dll *.pdb" + fi + + # TEA specific: + AC_SUBST(CLEANFILES) + AC_SUBST(TCL_LIBS) + AC_SUBST(TCL_DEFS) + AC_SUBST(TCL_EXTRA_CFLAGS) + AC_SUBST(TCL_LD_FLAGS) + AC_SUBST(TCL_SHLIB_LD_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_TKCONFIG -- +# +# Load the tkConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TK_BIN_DIR +# +# Results: +# +# Sets the following vars that should be in tkConfig.sh: +# TK_BIN_DIR +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_TKCONFIG], [ + AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) + + if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TK_BIN_DIR}/tkConfig.sh" + else + AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" + eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" + + # If the TK_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TK_LIB_SPEC will be set to the value + # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC + # instead of TK_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TK_BIN_DIR}/Makefile" ; then + TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" + TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" + TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tk.framework installed in an arbitrary location. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then + for i in "`cd "${TK_BIN_DIR}"; pwd`" \ + "`cd "${TK_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then + TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" + break + fi + done + fi + if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then + TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" + TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" + eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" + eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" + eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" + + # TEA specific: Ensure windowingsystem is defined + if test "${TEA_PLATFORM}" = "unix" ; then + case ${TK_DEFS} in + *MAC_OSX_TK*) + AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) + TEA_WINDOWINGSYSTEM="aqua" + ;; + *) + TEA_WINDOWINGSYSTEM="x11" + ;; + esac + elif test "${TEA_PLATFORM}" = "windows" ; then + TEA_WINDOWINGSYSTEM="win32" + fi + + AC_SUBST(TK_VERSION) + AC_SUBST(TK_BIN_DIR) + AC_SUBST(TK_SRC_DIR) + + AC_SUBST(TK_LIB_FILE) + AC_SUBST(TK_LIB_FLAG) + AC_SUBST(TK_LIB_SPEC) + + AC_SUBST(TK_STUB_LIB_FILE) + AC_SUBST(TK_STUB_LIB_FLAG) + AC_SUBST(TK_STUB_LIB_SPEC) + + # TEA specific: + AC_SUBST(TK_LIBS) + AC_SUBST(TK_XINCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_TCLSH +# Determine the fully qualified path name of the tclsh executable +# in the Tcl build directory or the tclsh installed in a bin +# directory. This macro will correctly determine the name +# of the tclsh executable even if tclsh has not yet been +# built in the build directory. The tclsh found is always +# associated with a tclConfig.sh file. This tclsh should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments +# none +# +# Results +# Subst's the following values: +# TCLSH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_TCLSH], [ + AC_MSG_CHECKING([for tclsh]) + if test -f "${TCL_BIN_DIR}/Makefile" ; then + # tclConfig.sh is in Tcl build directory + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + else + TCLSH_PROG="${TCL_BIN_DIR}/tclsh" + fi + else + # tclConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + else + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" + fi + list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${TCLSH_PROG}" ; then + REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" + fi + AC_MSG_RESULT([${TCLSH_PROG}]) + AC_SUBST(TCLSH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_WISH +# Determine the fully qualified path name of the wish executable +# in the Tk build directory or the wish installed in a bin +# directory. This macro will correctly determine the name +# of the wish executable even if wish has not yet been +# built in the build directory. The wish found is always +# associated with a tkConfig.sh file. This wish should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments +# none +# +# Results +# Subst's the following values: +# WISH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_WISH], [ + AC_MSG_CHECKING([for wish]) + if test -f "${TK_BIN_DIR}/Makefile" ; then + # tkConfig.sh is in Tk build directory + if test "${TEA_PLATFORM}" = "windows"; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + else + WISH_PROG="${TK_BIN_DIR}/wish" + fi + else + # tkConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + else + WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" + fi + list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TK_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${WISH_PROG}" ; then + REAL_TK_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" + fi + AC_MSG_RESULT([${WISH_PROG}]) + AC_SUBST(WISH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SHARED -- +# +# Allows the building of shared libraries +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-shared=yes|no +# +# Defines the following vars: +# STATIC_BUILD Used for building import/export libraries +# on Windows. +# +# Sets the following vars: +# SHARED_BUILD Value of 1 or 0 +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_SHARED], [ + AC_MSG_CHECKING([how to build libraries]) + AC_ARG_ENABLE(shared, + AC_HELP_STRING([--enable-shared], + [build and link with shared libraries (default: on)]), + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" ; then + AC_MSG_RESULT([shared]) + SHARED_BUILD=1 + else + AC_MSG_RESULT([static]) + SHARED_BUILD=0 + AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) + fi + AC_SUBST(SHARED_BUILD) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_THREADS -- +# +# Specify if thread support should be enabled. If "yes" is specified +# as an arg (optional), threads are enabled by default, "no" means +# threads are disabled. "yes" is the default. +# +# TCL_THREADS is checked so that if you are compiling an extension +# against a threaded core, your extension must be compiled threaded +# as well. +# +# Note that it is legal to have a thread enabled extension run in a +# threaded or non-threaded Tcl core, but a non-threaded extension may +# only run in a non-threaded Tcl core. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-threads +# +# Sets the following vars: +# THREADS_LIBS Thread library(s) +# +# Defines the following vars: +# TCL_THREADS +# _REENTRANT +# _THREAD_SAFE +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_THREADS], [ + AC_ARG_ENABLE(threads, + AC_HELP_STRING([--enable-threads], + [build with threads]), + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_threads+set}" = set; then + enableval="$enable_threads" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then + TCL_THREADS=1 + + if test "${TEA_PLATFORM}" != "windows" ; then + # We are always OK on Windows, so check what this platform wants: + + # USE_THREAD_ALLOC tells us to try the special thread-based + # allocator that significantly reduces lock contention + AC_DEFINE(USE_THREAD_ALLOC, 1, + [Do we want to use the threaded memory allocator?]) + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + if test "`uname -s`" = "SunOS" ; then + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + fi + AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) + AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "no"; then + # Check a little harder for __pthread_mutex_init in the same + # library, as some systems hide it there until pthread.h is + # defined. We could alternatively do an AC_TRY_COMPILE with + # pthread.h, but that will work with libpthread really doesn't + # exist, like AIX 4.2. [Bug: 4359] + AC_CHECK_LIB(pthread, __pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + AC_CHECK_LIB(pthreads, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthreads" + else + AC_CHECK_LIB(c, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "no"; then + AC_CHECK_LIB(c_r, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -pthread" + else + TCL_THREADS=0 + AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) + fi + fi + fi + fi + fi + else + TCL_THREADS=0 + fi + # Do checking message here to not mess up interleaved configure output + AC_MSG_CHECKING([for building with threads]) + if test "${TCL_THREADS}" = 1; then + AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) + AC_MSG_RESULT([yes (default)]) + else + AC_MSG_RESULT([no]) + fi + # TCL_THREADS sanity checking. See if our request for building with + # threads is the same as the way Tcl was built. If not, warn the user. + case ${TCL_DEFS} in + *THREADS=1*) + if test "${TCL_THREADS}" = "0"; then + AC_MSG_WARN([ + Building ${PACKAGE_NAME} without threads enabled, but building against Tcl + that IS thread-enabled. It is recommended to use --enable-threads.]) + fi + ;; + *) + if test "${TCL_THREADS}" = "1"; then + AC_MSG_WARN([ + --enable-threads requested, but building against a Tcl that is NOT + thread-enabled. This is an OK configuration that will also run in + a thread-enabled core.]) + fi + ;; + esac + AC_SUBST(TCL_THREADS) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SYMBOLS -- +# +# Specify if debugging symbols should be used. +# Memory (TCL_MEM_DEBUG) debugging can also be enabled. +# +# Arguments: +# none +# +# TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives +# the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. +# Requires the following vars to be set in the Makefile: +# CFLAGS_DEFAULT +# LDFLAGS_DEFAULT +# +# Results: +# +# Adds the following arguments to configure: +# --enable-symbols +# +# Defines the following vars: +# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true +# Sets to $(CFLAGS_OPTIMIZE) if false +# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true +# Sets to $(LDFLAGS_OPTIMIZE) if false +# DBGX Formerly used as debug library extension; +# always blank now. +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_SYMBOLS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_CONFIG_CFLAGS]) + AC_MSG_CHECKING([for build with symbols]) + AC_ARG_ENABLE(symbols, + AC_HELP_STRING([--enable-symbols], + [build with debugging symbols (default: off)]), + [tcl_ok=$enableval], [tcl_ok=no]) + DBGX="" + if test "$tcl_ok" = "no"; then + CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" + LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" + AC_MSG_RESULT([no]) + else + CFLAGS_DEFAULT="${CFLAGS_DEBUG}" + LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" + if test "$tcl_ok" = "yes"; then + AC_MSG_RESULT([yes (standard debugging)]) + fi + fi + # TEA specific: + if test "${TEA_PLATFORM}" != "windows" ; then + LDFLAGS_DEFAULT="${LDFLAGS}" + fi + AC_SUBST(CFLAGS_DEFAULT) + AC_SUBST(LDFLAGS_DEFAULT) + AC_SUBST(TCL_DBGX) + + if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then + AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) + fi + + if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then + if test "$tcl_ok" = "all"; then + AC_MSG_RESULT([enabled symbols mem debugging]) + else + AC_MSG_RESULT([enabled $tcl_ok debugging]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_LANGINFO -- +# +# Allows use of modern nl_langinfo check for better l10n. +# This is only relevant for Unix. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-langinfo=yes|no (default is yes) +# +# Defines the following vars: +# HAVE_LANGINFO Triggers use of nl_langinfo if defined. +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_LANGINFO], [ + AC_ARG_ENABLE(langinfo, + AC_HELP_STRING([--enable-langinfo], + [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), + [langinfo_ok=$enableval], [langinfo_ok=yes]) + + HAVE_LANGINFO=0 + if test "$langinfo_ok" = "yes"; then + AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) + fi + AC_MSG_CHECKING([whether to use nl_langinfo]) + if test "$langinfo_ok" = "yes"; then + AC_CACHE_VAL(tcl_cv_langinfo_h, [ + AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], + [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) + AC_MSG_RESULT([$tcl_cv_langinfo_h]) + if test $tcl_cv_langinfo_h = yes; then + AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) + fi + else + AC_MSG_RESULT([$langinfo_ok]) + fi +]) + +#-------------------------------------------------------------------- +# TEA_CONFIG_SYSTEM +# +# Determine what the system is (some things cannot be easily checked +# on a feature-driven basis, alas). This can usually be done via the +# "uname" command. +# +# Arguments: +# none +# +# Results: +# Defines the following var: +# +# system - System/platform/version identification code. +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_CONFIG_SYSTEM], [ + AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ + # TEA specific: + if test "${TEA_PLATFORM}" = "windows" ; then + tcl_cv_sys_version=windows + else + tcl_cv_sys_version=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + AC_MSG_WARN([can't find uname command]) + tcl_cv_sys_version=unknown + else + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + fi + fi + ]) + system=$tcl_cv_sys_version +]) + +#-------------------------------------------------------------------- +# TEA_CONFIG_CFLAGS +# +# Try to determine the proper flags to pass to the compiler +# for building shared libraries and other such nonsense. +# +# Arguments: +# none +# +# Results: +# +# Defines and substitutes the following vars: +# +# DL_OBJS, DL_LIBS - removed for TEA, only needed by core. +# LDFLAGS - Flags to pass to the compiler when linking object +# files into an executable application binary such +# as tclsh. +# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. Could +# be the same as CC_SEARCH_FLAGS if ${CC} is used to link. +# CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. +# SHLIB_CFLAGS - Flags to pass to cc when compiling the components +# of a shared library (may request position-independent +# code, among other things). +# SHLIB_LD - Base command to use for combining object files +# into a shared library. +# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when +# creating shared libraries. This symbol typically +# goes at the end of the "ld" commands that build +# shared libraries. The value of the symbol defaults to +# "${LIBS}" if all of the dependent libraries should +# be specified when creating a shared library. If +# dependent libraries should not be specified (as on +# SunOS 4.x, where they cause the link to fail, or in +# general if Tcl and Tk aren't themselves shared +# libraries), then this symbol has an empty string +# as its value. +# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable +# extensions. An empty string means we don't know how +# to use shared libraries on this platform. +# LIB_SUFFIX - Specifies everything that comes after the "libfoo" +# in a static or shared library name, using the $VERSION variable +# to put the version in the right place. This is used +# by platforms that need non-standard library names. +# Examples: ${VERSION}.so.1.1 on NetBSD, since it needs +# to have a version after the .so, and ${VERSION}.a +# on AIX, since a shared library needs to have +# a .a extension whereas shared objects for loadable +# extensions have a .so extension. Defaults to +# ${VERSION}${SHLIB_SUFFIX}. +# CFLAGS_DEBUG - +# Flags used when running the compiler in debug mode +# CFLAGS_OPTIMIZE - +# Flags used when running the compiler in optimize mode +# CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_CONFIG_CFLAGS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + + # Step 0.a: Enable 64 bit support? + + AC_MSG_CHECKING([if 64bit support is requested]) + AC_ARG_ENABLE(64bit, + AC_HELP_STRING([--enable-64bit], + [enable 64bit support (default: off)]), + [do64bit=$enableval], [do64bit=no]) + AC_MSG_RESULT([$do64bit]) + + # Step 0.b: Enable Solaris 64 bit VIS support? + + AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) + AC_ARG_ENABLE(64bit-vis, + AC_HELP_STRING([--enable-64bit-vis], + [enable 64bit Sparc VIS support (default: off)]), + [do64bitVIS=$enableval], [do64bitVIS=no]) + AC_MSG_RESULT([$do64bitVIS]) + # Force 64bit on with VIS + AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) + + # Step 0.c: Check if visibility support is available. Do this here so + # that platform specific alternatives can be used below if this fails. + + AC_CACHE_CHECK([if compiler supports visibility "hidden"], + tcl_cv_cc_visibility_hidden, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" + AC_TRY_LINK([ + extern __attribute__((__visibility__("hidden"))) void f(void); + void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, + tcl_cv_cc_visibility_hidden=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ + AC_DEFINE(MODULE_SCOPE, + [extern __attribute__((__visibility__("hidden")))], + [Compiler support for module scope symbols]) + ]) + + # Step 0.d: Disable -rpath support? + + AC_MSG_CHECKING([if rpath support is requested]) + AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath], + [disable rpath support (default: on)]), + [doRpath=$enableval], [doRpath=yes]) + AC_MSG_RESULT([$doRpath]) + + # TEA specific: Cross-compiling options for Windows/CE builds? + + AS_IF([test "${TEA_PLATFORM}" = windows], [ + AC_MSG_CHECKING([if Windows/CE build is requested]) + AC_ARG_ENABLE(wince, + AC_HELP_STRING([--enable-wince], + [enable Win/CE support (where applicable)]), + [doWince=$enableval], [doWince=no]) + AC_MSG_RESULT([$doWince]) + ]) + + # Set the variable "system" to hold the name and version number + # for the system. + + TEA_CONFIG_SYSTEM + + # Require ranlib early so we can override it in special cases below. + + AC_REQUIRE([AC_PROG_RANLIB]) + + # Set configuration options based on system name and version. + # This is similar to Tcl's unix/tcl.m4 except that we've added a + # "windows" case and removed some core-only vars. + + do64bit_ok=no + # default to '{$LIBS}' and set to "" on per-platform necessary basis + SHLIB_LD_LIBS='${LIBS}' + # When ld needs options to work in 64-bit mode, put them in + # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] + # is disabled by the user. [Bug 1016796] + LDFLAGS_ARCH="" + UNSHARED_LIB_SUFFIX="" + # TEA specific: use PACKAGE_VERSION instead of VERSION + TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' + ECHO_VERSION='`echo ${PACKAGE_VERSION}`' + TCL_LIB_VERSIONS_OK=ok + CFLAGS_DEBUG=-g + CFLAGS_OPTIMIZE=-O + AS_IF([test "$GCC" = yes], [ + # TEA specific: + CFLAGS_OPTIMIZE=-O2 + CFLAGS_WARNING="-Wall" + ], [CFLAGS_WARNING=""]) +dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. +dnl AC_CHECK_TOOL(AR, ar) + AC_CHECK_PROG(AR, ar, ar) + STLIB_LD='${AR} cr' + LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" + AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"]) + case $system in + # TEA specific: + windows) + # This is a 2-stage check to make sure we have the 64-bit SDK + # We have to know where the SDK is installed. + # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs + # MACHINE is IX86 for LINK, but this is used by the manifest, + # which requires x86|amd64|ia64. + MACHINE="X86" + if test "$do64bit" != "no" ; then + if test "x${MSSDK}x" = "xx" ; then + MSSDK="C:/Progra~1/Microsoft Platform SDK" + fi + MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` + PATH64="" + case "$do64bit" in + amd64|x64|yes) + MACHINE="AMD64" ; # default to AMD64 64-bit build + PATH64="${MSSDK}/Bin/Win64/x86/AMD64" + ;; + ia64) + MACHINE="IA64" + PATH64="${MSSDK}/Bin/Win64" + ;; + esac + if test ! -d "${PATH64}" ; then + AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) + AC_MSG_WARN([Ensure latest Platform SDK is installed]) + do64bit="no" + else + AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) + do64bit_ok="yes" + fi + fi + + if test "$doWince" != "no" ; then + if test "$do64bit" != "no" ; then + AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) + fi + if test "$GCC" = "yes" ; then + AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) + fi + TEA_PATH_CELIB + # Set defaults for common evc4/PPC2003 setup + # Currently Tcl requires 300+, possibly 420+ for sockets + CEVERSION=420; # could be 211 300 301 400 420 ... + TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... + ARCH=ARM; # could be ARM MIPS X86EM ... + PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" + if test "$doWince" != "yes"; then + # If !yes then the user specified something + # Reset ARCH to allow user to skip specifying it + ARCH= + eval `echo $doWince | awk -F, '{ \ + if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ + if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ + if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ + if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ + if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ + }'` + if test "x${ARCH}" = "x" ; then + ARCH=$TARGETCPU; + fi + fi + OSVERSION=WCE$CEVERSION; + if test "x${WCEROOT}" = "x" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" + if test ! -d "${WCEROOT}" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded Tools" + fi + fi + if test "x${SDKROOT}" = "x" ; then + SDKROOT="C:/Program Files/Windows CE Tools" + if test ! -d "${SDKROOT}" ; then + SDKROOT="C:/Windows CE Tools" + fi + fi + WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` + SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` + if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ + -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then + AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) + doWince="no" + else + # We could PATH_NOSPACE these, but that's not important, + # as long as we quote them when used. + CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" + if test -d "${CEINCLUDE}/${TARGETCPU}" ; then + CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" + fi + CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" + fi + fi + + if test "$GCC" != "yes" ; then + if test "${SHARED_BUILD}" = "0" ; then + runtime=-MT + else + runtime=-MD + fi + + if test "$do64bit" != "no" ; then + # All this magic is necessary for the Win64 SDK RC1 - hobbs + CC="\"${PATH64}/cl.exe\"" + CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" + RC="\"${MSSDK}/bin/rc.exe\"" + lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" + LINKBIN="\"${PATH64}/link.exe\"" + CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + # Avoid 'unresolved external symbol __security_cookie' + # errors, c.f. http://support.microsoft.com/?id=894573 + TEA_ADD_LIBS([bufferoverflowU.lib]) + elif test "$doWince" != "no" ; then + CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" + if test "${TARGETCPU}" = "X86"; then + CC="\"${CEBINROOT}/cl.exe\"" + else + CC="\"${CEBINROOT}/cl${ARCH}.exe\"" + fi + CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" + RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" + arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` + defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" + if test "${SHARED_BUILD}" = "1" ; then + # Static CE builds require static celib as well + defs="${defs} _DLL" + fi + for i in $defs ; do + AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) + done + AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) + AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) + CFLAGS_DEBUG="-nologo -Zi -Od" + CFLAGS_OPTIMIZE="-nologo -Ox" + lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` + lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" + LINKBIN="\"${CEBINROOT}/link.exe\"" + AC_SUBST(CELIB_DIR) + else + RC="rc" + lflags="-nologo" + LINKBIN="link" + CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + fi + fi + + if test "$GCC" = "yes"; then + # mingw gcc mode + RC="windres" + CFLAGS_DEBUG="-g" + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + SHLIB_LD="$CC -shared" + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" + LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" + else + SHLIB_LD="${LINKBIN} -dll ${lflags}" + # link -lib only works when -lib is the first arg + STLIB_LD="${LINKBIN} -lib ${lflags}" + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' + PATHTYPE=-w + # For information on what debugtype is most useful, see: + # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp + # and also + # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx + # This essentially turns it all on. + LDFLAGS_DEBUG="-debug -debugtype:cv" + LDFLAGS_OPTIMIZE="-release" + if test "$doWince" != "no" ; then + LDFLAGS_CONSOLE="-link ${lflags}" + LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} + else + LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" + LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" + fi + fi + + SHLIB_SUFFIX=".dll" + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' + + TCL_LIB_VERSIONS_OK=nodots + ;; + AIX-*) + AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ + # AIX requires the _r compiler when gcc isn't being used + case "${CC}" in + *_r|*_r\ *) + # ok ... + ;; + *) + # Make sure only first arg gets _r + CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` + ;; + esac + AC_MSG_RESULT([Using $CC for compiling with threads]) + ]) + LIBS="$LIBS -lc" + SHLIB_CFLAGS="" + SHLIB_SUFFIX=".so" + + LD_LIBRARY_PATH_VAR="LIBPATH" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -q64" + LDFLAGS_ARCH="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + ]) + ]) + + AS_IF([test "`uname -m`" = ia64], [ + # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + AS_IF([test "$GCC" = yes], [ + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + ], [ + CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' + ]) + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ], [ + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared -Wl,-bexpall' + ], [ + SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" + LDFLAGS="$LDFLAGS -brtl" + ]) + SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + BeOS*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -nostart' + SHLIB_SUFFIX=".so" + + #----------------------------------------------------------- + # Check for inet_ntoa in -lbind, for BeOS (which also needs + # -lsocket, even if the network functions are in -lnet which + # is always linked to, for compatibility. + #----------------------------------------------------------- + AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) + ;; + BSD/OS-4.*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + CYGWIN_*) + SHLIB_CFLAGS="" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".dll" + EXE_SUFFIX=".exe" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + Haiku*) + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) + ;; + HP-UX-*.11.*) + # Use updated header definitions where possible + AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) + # TEA specific: Needed by Tcl, but not most extensions + #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) + #LIBS="$LIBS -lxnet" # Use the XOPEN network library + + AS_IF([test "`uname -m`" = ia64], [ + SHLIB_SUFFIX=".so" + # Use newer C++ library for C++ extensions + #if test "$GCC" != "yes" ; then + # CPPFLAGS="-AA" + #fi + ], [ + SHLIB_SUFFIX=".sl" + ]) + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + AS_IF([test "$tcl_ok" = yes], [ + LDFLAGS="$LDFLAGS -E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + ]) + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + CFLAGS="$CFLAGS -z" + # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc + #CFLAGS="$CFLAGS +DAportable" + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + ]) + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = "yes"], [ + AS_IF([test "$GCC" = yes], [ + case `${CC} -dumpmachine` in + hppa64*) + # 64-bit gcc in use. Fix flags for GNU ld. + do64bit_ok=yes + SHLIB_LD='${CC} -shared' + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ;; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ;; + esac + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS +DD64" + LDFLAGS_ARCH="+DD64" + ]) + ]) ;; + IRIX-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [ + CFLAGS="$CFLAGS -mabi=n32" + LDFLAGS="$LDFLAGS -mabi=n32" + ], [ + case $system in + IRIX-6.3) + # Use to build 6.2 compatible binaries on 6.3. + CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" + ;; + *) + CFLAGS="$CFLAGS -n32" + ;; + esac + LDFLAGS="$LDFLAGS -n32" + ]) + ;; + IRIX64-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + + # Check to enable 64-bit flags for compiler/linker + + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported by gcc]) + ], [ + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + CFLAGS="$CFLAGS -64" + LDFLAGS_ARCH="-64" + ]) + ]) + ;; + Linux*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + + # TEA specific: + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + AS_IF([test $do64bit = yes], [ + AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -m64" + AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_m64 = yes], [ + CFLAGS="$CFLAGS -m64" + do64bit_ok=yes + ]) + ]) + + # The combo of gcc + glibc has a bug related to inlining of + # functions like strtod(). The -fno-builtin flag should address + # this problem but it does not work. The -fno-inline flag is kind + # of overkill but it works. Disable inlining only when one of the + # files in compat/*.c is being linked in. + + AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) + + ;; + GNU*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + + SHLIB_LD='${CC} -shared' + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + ;; + Lynx*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + CFLAGS_OPTIMIZE=-02 + SHLIB_LD='${CC} -shared' + LD_FLAGS="-Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + ;; + OpenBSD-*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' + AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ + AC_EGREP_CPP(yes, [ +#ifdef __ELF__ + yes +#endif + ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) + AS_IF([test $tcl_cv_ld_elf = yes], [ + LDFLAGS=-Wl,-export-dynamic + ], [LDFLAGS=""]) + AS_IF([test "${TCL_THREADS}" = "1"], [ + # OpenBSD builds and links with -pthread, never -lpthread. + LIBS=`echo $LIBS | sed s/-lpthread//` + CFLAGS="$CFLAGS -pthread" + SHLIB_CFLAGS="$SHLIB_CFLAGS -pthread" + ]) + # OpenBSD doesn't do version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + NetBSD-*|FreeBSD-[[3-4]].*) + # FreeBSD 3.* and greater have ELF. + # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the CFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + case $system in + FreeBSD-3.*) + # FreeBSD-3 doesn't handle version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' + TCL_LIB_VERSIONS_OK=nodots + ;; + esac + ;; + FreeBSD-*) + # This configuration from FreeBSD Ports. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="${CC} -shared" + TCL_SHLIB_LD_EXTRAS="-soname \$[@]" + SHLIB_SUFFIX=".so" + LDFLAGS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the LDFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) + # Version numbers are dot-stripped by system policy. + TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' + TCL_LIB_VERSIONS_OK=nodots + ;; + Darwin-*) + CFLAGS_OPTIMIZE="-Os" + SHLIB_CFLAGS="-fno-common" + # To avoid discrepancies between what headers configure sees during + # preprocessing tests and compiling tests, move any -isysroot and + # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: + CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" + CFLAGS="`echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" + AS_IF([test $do64bit = yes], [ + case `arch` in + ppc) + AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], + tcl_cv_cc_arch_ppc64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, + tcl_cv_cc_arch_ppc64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + do64bit_ok=yes + ]);; + i386) + AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], + tcl_cv_cc_arch_x86_64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch x86_64" + AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, + tcl_cv_cc_arch_x86_64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ + CFLAGS="$CFLAGS -arch x86_64" + do64bit_ok=yes + ]);; + *) + AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; + esac + ], [ + # Check for combined 32-bit and 64-bit fat build + AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ + && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ + fat_32_64=yes]) + ]) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' + AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" + AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_single_module = yes], [ + SHLIB_LD="${SHLIB_LD} -Wl,-single_module" + ]) + # TEA specific: link shlib with current and compatiblity version flags + vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` + SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" + SHLIB_SUFFIX=".dylib" + # Don't use -prebind when building for Mac OS X 10.4 or later only: + AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ + "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ + LDFLAGS="$LDFLAGS -prebind"]) + LDFLAGS="$LDFLAGS -headerpad_max_install_names" + AC_CACHE_CHECK([if ld accepts -search_paths_first flag], + tcl_cv_ld_search_paths_first, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, + tcl_cv_ld_search_paths_first=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + ]) + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [__private_extern__], + [Compiler support for module scope symbols]) + tcl_cv_cc_visibility_hidden=yes + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" + # TEA specific: for combined 32 & 64 bit fat builds of Tk + # extensions, verify that 64-bit build is possible. + AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ + AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" + LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" + AC_TRY_LINK([#include ], [XrmInitialize();], + tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ + AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" + LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" + AC_TRY_LINK([#include ], [Tk_InitStubs(NULL, "", 0);], + tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + # remove 64-bit arch flags from CFLAGS et al. if configuration + # does not support 64-bit. + AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ + AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' + done]) + ]) + ;; + OS/390-*) + CFLAGS_OPTIMIZE="" # Optimizer is buggy + AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h + [Should OS/390 do the right thing with sockets?]) + ;; + OSF1-V*) + # Digital OSF/1 + SHLIB_CFLAGS="" + AS_IF([test "$SHARED_BUILD" = 1], [ + SHLIB_LD='ld -shared -expect_unresolved "*"' + ], [ + SHLIB_LD='ld -non_shared -expect_unresolved "*"' + ]) + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ + CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) + # see pthread_intro(3) for pthread support on osf1, k.furukawa + AS_IF([test "${TCL_THREADS}" = 1], [ + CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" + CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" + LIBS=`echo $LIBS | sed s/-lpthreads//` + AS_IF([test "$GCC" = yes], [ + LIBS="$LIBS -lpthread -lmach -lexc" + ], [ + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + ]) + ;; + QNX-6*) + # QNX RTP + # This may work for all QNX, but it was only reported for v6. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SCO_SV-3.2*) + AS_IF([test "$GCC" = yes], [ + SHLIB_CFLAGS="-fPIC -melf" + LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" + ], [ + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" + ]) + SHLIB_LD="ld -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SunOS-5.[[0-6]]) + # Careful to not let 5.10+ fall into this case + + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + SHLIB_SUFFIX=".so" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + SunOS-5*) + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + arch=`isainfo` + AS_IF([test "$arch" = "sparcv9 sparc"], [ + AS_IF([test "$GCC" = yes], [ + AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ + AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -m64 -mcpu=v9" + LDFLAGS="$LDFLAGS -m64 -mcpu=v9" + SHLIB_CFLAGS="-fPIC" + ]) + ], [ + do64bit_ok=yes + AS_IF([test "$do64bitVIS" = yes], [ + CFLAGS="$CFLAGS -xarch=v9a" + LDFLAGS_ARCH="-xarch=v9a" + ], [ + CFLAGS="$CFLAGS -xarch=v9" + LDFLAGS_ARCH="-xarch=v9" + ]) + # Solaris 64 uses this as well + #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" + ]) + ], [AS_IF([test "$arch" = "amd64 i386"], [ + AS_IF([test "$GCC" = yes], [ + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + do64bit_ok=yes + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]);; + esac + ], [ + do64bit_ok=yes + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + CFLAGS="$CFLAGS -xarch=amd64" + LDFLAGS="$LDFLAGS -xarch=amd64";; + esac + ]) + ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) + ]) + + SHLIB_SUFFIX=".so" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "$do64bit_ok" = yes], [ + AS_IF([test "$arch" = "sparcv9 sparc"], [ + # We need to specify -static-libgcc or we need to + # add the path to the sparv9 libgcc. + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" + # for finding sparcv9 libgcc, get the regular libgcc + # path, remove so name and append 'sparcv9' + #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." + #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" + ], [AS_IF([test "$arch" = "amd64 i386"], [ + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" + ])]) + ]) + ], [ + case $system in + SunOS-5.[[1-9]][[0-9]]*) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; + *) + SHLIB_LD='/usr/ccs/bin/ld -G -z text';; + esac + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ]) + ;; + esac + + AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ + AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) + ]) + +dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so +dnl # until the end of configure, as configure's compile and link tests use +dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's +dnl # preprocessing tests use only CPPFLAGS. + AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) + + # Add in the arch flags late to ensure it wasn't removed. + # Not necessary in TEA, but this is aligned with core + LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" + + # If we're running gcc, then change the C flags for compiling shared + # libraries to the right flags for gcc, instead of those for the + # standard manufacturer compiler. + + AS_IF([test "$GCC" = yes], [ + case $system in + AIX-*) ;; + BSD/OS*) ;; + CYGWIN_*) ;; + IRIX*) ;; + NetBSD-*|FreeBSD-*|OpenBSD-*) ;; + Darwin-*) ;; + SCO_SV-3.2*) ;; + windows) ;; + *) SHLIB_CFLAGS="-fPIC" ;; + esac]) + + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [extern], + [No Compiler support for module scope symbols]) + AC_DEFINE(NO_VIZ) + ]) + + AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) + AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) + + AC_SUBST(CFLAGS_DEBUG) + AC_SUBST(CFLAGS_OPTIMIZE) + AC_SUBST(CFLAGS_WARNING) + + AC_SUBST(STLIB_LD) + AC_SUBST(SHLIB_LD) + + AC_SUBST(SHLIB_LD_LIBS) + AC_SUBST(SHLIB_CFLAGS) + + AC_SUBST(LD_LIBRARY_PATH_VAR) + + # These must be called after we do the basic CFLAGS checks and + # verify any possible 64-bit or similar switches are necessary + TEA_TCL_EARLY_FLAGS + TEA_TCL_64BIT_FLAGS +]) + +#-------------------------------------------------------------------- +# TEA_SERIAL_PORT +# +# Determine which interface to use to talk to the serial port. +# Note that #include lines must begin in leftmost column for +# some compilers to recognize them as preprocessor directives, +# and some build environments have stdin not pointing at a +# pseudo-terminal (usually /dev/null instead.) +# +# Arguments: +# none +# +# Results: +# +# Defines only one of the following vars: +# HAVE_SYS_MODEM_H +# USE_TERMIOS +# USE_TERMIO +# USE_SGTTY +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_SERIAL_PORT], [ + AC_CHECK_HEADERS(sys/modem.h) + AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ + AC_TRY_RUN([ +#include + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; + }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) + fi]) + case $tcl_cv_api_serial in + termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; + termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; + sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; + esac +]) + +#-------------------------------------------------------------------- +# TEA_MISSING_POSIX_HEADERS +# +# Supply substitutes for missing POSIX header files. Special +# notes: +# - stdlib.h doesn't define strtol, strtoul, or +# strtod in some versions of SunOS +# - some versions of string.h don't declare procedures such +# as strstr +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# NO_DIRENT_H +# NO_ERRNO_H +# NO_VALUES_H +# HAVE_LIMITS_H or NO_LIMITS_H +# NO_STDLIB_H +# NO_STRING_H +# NO_SYS_WAIT_H +# NO_DLFCN_H +# HAVE_SYS_PARAM_H +# +# HAVE_STRING_H ? +# +# tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and +# CHECK on limits.h +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ + AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ + AC_TRY_LINK([#include +#include ], [ +#ifndef _POSIX_SOURCE +# ifdef __Lynx__ + /* + * Generate compilation error to make the test fail: Lynx headers + * are only valid if really in the POSIX environment. + */ + + missing_procedure(); +# endif +#endif +DIR *d; +struct dirent *entryPtr; +char *p; +d = opendir("foobar"); +entryPtr = readdir(d); +p = entryPtr->d_name; +closedir(d); +], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) + + if test $tcl_cv_dirent_h = no; then + AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) + fi + + # TEA specific: + AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(limits.h, + [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], + [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) + if test $tcl_ok = 0; then + AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) + fi + AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) + AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) + + # See also memmove check below for a place where NO_STRING_H can be + # set and why. + + if test $tcl_ok = 0; then + AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) + fi + + AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) + + # OS/390 lacks sys/param.h (and doesn't need it, by chance). + AC_HAVE_HEADERS(sys/param.h) +]) + +#-------------------------------------------------------------------- +# TEA_PATH_X +# +# Locate the X11 header files and the X11 library archive. Try +# the ac_path_x macro first, but if it doesn't find the X stuff +# (e.g. because there's no xmkmf program) then check through +# a list of possible directories. Under some conditions the +# autoconf macro will return an include directory that contains +# no include files, so double-check its result just to be safe. +# +# This should be called after TEA_CONFIG_CFLAGS as setting the +# LIBS line can confuse some configure macro magic. +# +# Arguments: +# none +# +# Results: +# +# Sets the following vars: +# XINCLUDES +# XLIBSW +# PKG_LIBS (appends to) +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_PATH_X], [ + if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then + TEA_PATH_UNIX_X + fi +]) + +AC_DEFUN([TEA_PATH_UNIX_X], [ + AC_PATH_X + not_really_there="" + if test "$no_x" = ""; then + if test "$x_includes" = ""; then + AC_TRY_CPP([#include ], , not_really_there="yes") + else + if test ! -r $x_includes/X11/Intrinsic.h; then + not_really_there="yes" + fi + fi + fi + if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then + AC_MSG_CHECKING([for X11 header files]) + found_xincludes="no" + AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") + if test "$found_xincludes" = "no"; then + dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" + for i in $dirs ; do + if test -r $i/X11/Intrinsic.h; then + AC_MSG_RESULT([$i]) + XINCLUDES=" -I$i" + found_xincludes="yes" + break + fi + done + fi + else + if test "$x_includes" != ""; then + XINCLUDES="-I$x_includes" + found_xincludes="yes" + fi + fi + if test "$found_xincludes" = "no"; then + AC_MSG_RESULT([couldn't find any!]) + fi + + if test "$no_x" = yes; then + AC_MSG_CHECKING([for X11 libraries]) + XLIBSW=nope + dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" + for i in $dirs ; do + if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then + AC_MSG_RESULT([$i]) + XLIBSW="-L$i -lX11" + x_libraries="$i" + break + fi + done + else + if test "$x_libraries" = ""; then + XLIBSW=-lX11 + else + XLIBSW="-L$x_libraries -lX11" + fi + fi + if test "$XLIBSW" = nope ; then + AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) + fi + if test "$XLIBSW" = nope ; then + AC_MSG_RESULT([could not find any! Using -lX11.]) + XLIBSW=-lX11 + fi + # TEA specific: + if test x"${XLIBSW}" != x ; then + PKG_LIBS="${PKG_LIBS} ${XLIBSW}" + fi +]) + +#-------------------------------------------------------------------- +# TEA_BLOCKING_STYLE +# +# The statements below check for systems where POSIX-style +# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. +# On these systems (mostly older ones), use the old BSD-style +# FIONBIO approach instead. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# HAVE_SYS_IOCTL_H +# HAVE_SYS_FILIO_H +# USE_FIONBIO +# O_NONBLOCK +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_BLOCKING_STYLE], [ + AC_CHECK_HEADERS(sys/ioctl.h) + AC_CHECK_HEADERS(sys/filio.h) + TEA_CONFIG_SYSTEM + AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) + case $system in + OSF*) + AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) + AC_MSG_RESULT([FIONBIO]) + ;; + *) + AC_MSG_RESULT([O_NONBLOCK]) + ;; + esac +]) + +#-------------------------------------------------------------------- +# TEA_TIME_HANDLER +# +# Checks how the system deals with time.h, what time structures +# are used on the system, and what fields the structures have. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# USE_DELTA_FOR_TZ +# HAVE_TM_GMTOFF +# HAVE_TM_TZADJ +# HAVE_TIMEZONE_VAR +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TIME_HANDLER], [ + AC_CHECK_HEADERS(sys/time.h) + AC_HEADER_TIME + AC_STRUCT_TIMEZONE + + AC_CHECK_FUNCS(gmtime_r localtime_r) + + AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ + AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], + tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) + if test $tcl_cv_member_tm_tzadj = yes ; then + AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) + fi + + AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ + AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], + tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) + if test $tcl_cv_member_tm_gmtoff = yes ; then + AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) + fi + + # + # Its important to include time.h in this check, as some systems + # (like convex) have timezone functions, etc. + # + AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ + AC_TRY_COMPILE([#include ], + [extern long timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) + if test $tcl_cv_timezone_long = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + else + # + # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. + # + AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ + AC_TRY_COMPILE([#include ], + [extern time_t timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) + if test $tcl_cv_timezone_time = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# TEA_BUGGY_STRTOD +# +# Under Solaris 2.4, strtod returns the wrong value for the +# terminating character under some conditions. Check for this +# and if the problem exists use a substitute procedure +# "fixstrtod" (provided by Tcl) that corrects the error. +# Also, on Compaq's Tru64 Unix 5.0, +# strtod(" ") returns 0.0 instead of a failure to convert. +# +# Arguments: +# none +# +# Results: +# +# Might defines some of the following vars: +# strtod (=fixstrtod) +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_BUGGY_STRTOD], [ + AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) + if test "$tcl_strtod" = 1; then + AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ + AC_TRY_RUN([ + extern double strtod(); + int main() { + char *infString="Inf", *nanString="NaN", *spaceString=" "; + char *term; + double value; + value = strtod(infString, &term); + if ((term != infString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(nanString, &term); + if ((term != nanString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(spaceString, &term); + if (term == (spaceString+1)) { + exit(1); + } + exit(0); + }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, + tcl_cv_strtod_buggy=buggy)]) + if test "$tcl_cv_strtod_buggy" = buggy; then + AC_LIBOBJ([fixstrtod]) + USE_COMPAT=1 + AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# TEA_TCL_LINK_LIBS +# +# Search for the libraries needed to link the Tcl shell. +# Things like the math library (-lm) and socket stuff (-lsocket vs. +# -lnsl) are dealt with here. +# +# Arguments: +# Requires the following vars to be set in the Makefile: +# DL_LIBS (not in TEA, only needed in core) +# LIBS +# MATH_LIBS +# +# Results: +# +# Subst's the following var: +# TCL_LIBS +# MATH_LIBS +# +# Might append to the following vars: +# LIBS +# +# Might define the following vars: +# HAVE_NET_ERRNO_H +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_LINK_LIBS], [ + #-------------------------------------------------------------------- + # On a few very rare systems, all of the libm.a stuff is + # already in libc.a. Set compiler flags accordingly. + # Also, Linux requires the "ieee" library for math to work + # right (and it must appear before "-lm"). + #-------------------------------------------------------------------- + + AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") + AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) + + #-------------------------------------------------------------------- + # Interactive UNIX requires -linet instead of -lsocket, plus it + # needs net/errno.h to define the socket-related error codes. + #-------------------------------------------------------------------- + + AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) + AC_CHECK_HEADER(net/errno.h, [ + AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) + + #-------------------------------------------------------------------- + # Check for the existence of the -lsocket and -lnsl libraries. + # The order here is important, so that they end up in the right + # order in the command line generated by make. Here are some + # special considerations: + # 1. Use "connect" and "accept" to check for -lsocket, and + # "gethostbyname" to check for -lnsl. + # 2. Use each function name only once: can't redo a check because + # autoconf caches the results of the last check and won't redo it. + # 3. Use -lnsl and -lsocket only if they supply procedures that + # aren't already present in the normal libraries. This is because + # IRIX 5.2 has libraries, but they aren't needed and they're + # bogus: they goof up name resolution if used. + # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. + # To get around this problem, check for both libraries together + # if -lsocket doesn't work by itself. + #-------------------------------------------------------------------- + + tcl_checkBoth=0 + AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) + if test "$tcl_checkSocket" = 1; then + AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, + LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) + fi + if test "$tcl_checkBoth" = 1; then + tk_oldLibs=$LIBS + LIBS="$LIBS -lsocket -lnsl" + AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) + fi + AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, + [LIBS="$LIBS -lnsl"])]) + + # TEA specific: Don't perform the eval of the libraries here because + # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS + + TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' + AC_SUBST(TCL_LIBS) + AC_SUBST(MATH_LIBS) +]) + +#-------------------------------------------------------------------- +# TEA_TCL_EARLY_FLAGS +# +# Check for what flags are needed to be passed so the correct OS +# features are available. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# _ISOC99_SOURCE +# _LARGEFILE64_SOURCE +# _LARGEFILE_SOURCE64 +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_EARLY_FLAG],[ + AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), + AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, + AC_TRY_COMPILE([[#define ]$1[ 1 +]$2], $3, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) + if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then + AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) + tcl_flags="$tcl_flags $1" + fi +]) + +AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ + AC_MSG_CHECKING([for required early compiler flags]) + tcl_flags="" + TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], + [char *p = (char *)strtoll; char *q = (char *)strtoull;]) + TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], + [struct stat64 buf; int i = stat64("/", &buf);]) + TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], + [char *p = (char *)open64;]) + if test "x${tcl_flags}" = "x" ; then + AC_MSG_RESULT([none]) + else + AC_MSG_RESULT([${tcl_flags}]) + fi +]) + +#-------------------------------------------------------------------- +# TEA_TCL_64BIT_FLAGS +# +# Check for what is defined in the way of 64-bit features. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# TCL_WIDE_INT_IS_LONG +# TCL_WIDE_INT_TYPE +# HAVE_STRUCT_DIRENT64 +# HAVE_STRUCT_STAT64 +# HAVE_TYPE_OFF64_T +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ + AC_MSG_CHECKING([for 64-bit integer type]) + AC_CACHE_VAL(tcl_cv_type_64bit,[ + tcl_cv_type_64bit=none + # See if the compiler knows natively about __int64 + AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], + tcl_type_64bit=__int64, tcl_type_64bit="long long") + # See if we should use long anyway Note that we substitute in the + # type that is our current guess for a 64-bit type inside this check + # program, so it should be modified only carefully... + AC_TRY_COMPILE(,[switch (0) { + case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; + }],tcl_cv_type_64bit=${tcl_type_64bit})]) + if test "${tcl_cv_type_64bit}" = none ; then + AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) + AC_MSG_RESULT([using long]) + elif test "${tcl_cv_type_64bit}" = "__int64" \ + -a "${TEA_PLATFORM}" = "windows" ; then + # TEA specific: We actually want to use the default tcl.h checks in + # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* + AC_MSG_RESULT([using Tcl header defaults]) + else + AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, + [What type should be used to define wide integers?]) + AC_MSG_RESULT([${tcl_cv_type_64bit}]) + + # Now check for auxiliary declarations + AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ + AC_TRY_COMPILE([#include +#include ],[struct dirent64 p;], + tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) + if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) + fi + + AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ + AC_TRY_COMPILE([#include ],[struct stat64 p; +], + tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) + if test "x${tcl_cv_struct_stat64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) + fi + + AC_CHECK_FUNCS(open64 lseek64) + AC_MSG_CHECKING([for off64_t]) + AC_CACHE_VAL(tcl_cv_type_off64_t,[ + AC_TRY_COMPILE([#include ],[off64_t offset; +], + tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) + dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the + dnl functions lseek64 and open64 are defined. + if test "x${tcl_cv_type_off64_t}" = "xyes" && \ + test "x${ac_cv_func_lseek64}" = "xyes" && \ + test "x${ac_cv_func_open64}" = "xyes" ; then + AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi +]) + +## +## Here ends the standard Tcl configuration bits and starts the +## TEA specific functions +## + +#------------------------------------------------------------------------ +# TEA_INIT -- +# +# Init various Tcl Extension Architecture (TEA) variables. +# This should be the first called TEA_* macro. +# +# Arguments: +# none +# +# Results: +# +# Defines and substs the following vars: +# CYGPATH +# EXEEXT +# Defines only: +# TEA_VERSION +# TEA_INITED +# TEA_PLATFORM (windows or unix) +# +# "cygpath" is used on windows to generate native path names for include +# files. These variables should only be used with the compiler and linker +# since they generate native path names. +# +# EXEEXT +# Select the executable extension based on the host type. This +# is a lightweight replacement for AC_EXEEXT that doesn't require +# a compiler. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_INIT], [ + # TEA extensions pass this us the version of TEA they think they + # are compatible with. + TEA_VERSION="3.9" + + AC_MSG_CHECKING([for correct TEA configuration]) + if test x"${PACKAGE_NAME}" = x ; then + AC_MSG_ERROR([ +The PACKAGE_NAME variable must be defined by your TEA configure.in]) + fi + if test x"$1" = x ; then + AC_MSG_ERROR([ +TEA version not specified.]) + elif test "$1" != "${TEA_VERSION}" ; then + AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) + else + AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) + fi + case "`uname -s`" in + *win32*|*WIN32*|*MINGW32_*) + AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *CYGWIN_*) + CYGPATH=echo + EXEEXT=".exe" + # TEA_PLATFORM is determined later in LOAD_TCLCONFIG + ;; + *) + CYGPATH=echo + EXEEXT="" + TEA_PLATFORM="unix" + ;; + esac + + # Check if exec_prefix is set. If not use fall back to prefix. + # Note when adjusted, so that TEA_PREFIX can correct for this. + # This is needed for recursive configures, since autoconf propagates + # $prefix, but not $exec_prefix (doh!). + if test x$exec_prefix = xNONE ; then + exec_prefix_default=yes + exec_prefix=$prefix + fi + + AC_SUBST(EXEEXT) + AC_SUBST(CYGPATH) + + # This package name must be replaced statically for AC_SUBST to work + AC_SUBST(PKG_LIB_FILE) + # Substitute STUB_LIB_FILE in case package creates a stub library too. + AC_SUBST(PKG_STUB_LIB_FILE) + + # We AC_SUBST these here to ensure they are subst'ed, + # in case the user doesn't call TEA_ADD_... + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) + AC_SUBST(PKG_TCL_SOURCES) + AC_SUBST(PKG_HEADERS) + AC_SUBST(PKG_INCLUDES) + AC_SUBST(PKG_LIBS) + AC_SUBST(PKG_CFLAGS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_SOURCES +# PKG_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_SOURCES], [ + vars="$@" + for i in $vars; do + case $i in + [\$]*) + # allow $-var names + PKG_SOURCES="$PKG_SOURCES $i" + PKG_OBJECTS="$PKG_OBJECTS $i" + ;; + *) + # check for existence - allows for generic/win/unix VPATH + # To add more dirs here (like 'src'), you have to update VPATH + # in Makefile.in as well + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find source file '$i']) + fi + PKG_SOURCES="$PKG_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_OBJECTS="$PKG_OBJECTS $j" + ;; + esac + done + AC_SUBST(PKG_SOURCES) + AC_SUBST(PKG_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_STUB_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_STUB_SOURCES +# PKG_STUB_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_STUB_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence - allows for generic/win/unix VPATH + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find stub source file '$i']) + fi + PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" + done + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_TCL_SOURCES -- +# +# Specify one or more Tcl source files. These should be platform +# independent runtime files. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_TCL_SOURCES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_TCL_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) + fi + PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" + done + AC_SUBST(PKG_TCL_SOURCES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_HEADERS -- +# +# Specify one or more source headers. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_HEADERS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_HEADERS], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find header file '${srcdir}/$i']) + fi + PKG_HEADERS="$PKG_HEADERS $i" + done + AC_SUBST(PKG_HEADERS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_INCLUDES -- +# +# Specify one or more include dirs. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_INCLUDES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_INCLUDES], [ + vars="$@" + for i in $vars; do + PKG_INCLUDES="$PKG_INCLUDES $i" + done + AC_SUBST(PKG_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_LIBS -- +# +# Specify one or more libraries. Users should check for +# the right platform before adding to their list. For Windows, +# libraries provided in "foo.lib" format will be converted to +# "-lfoo" when using GCC (mingw). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_LIBS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_LIBS], [ + vars="$@" + for i in $vars; do + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then + # Convert foo.lib to -lfoo for GCC. No-op if not *.lib + i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` + fi + PKG_LIBS="$PKG_LIBS $i" + done + AC_SUBST(PKG_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_CFLAGS -- +# +# Specify one or more CFLAGS. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_CFLAGS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_CFLAGS], [ + PKG_CFLAGS="$PKG_CFLAGS $@" + AC_SUBST(PKG_CFLAGS) +]) + +#------------------------------------------------------------------------ +# TEA_PREFIX -- +# +# Handle the --prefix=... option by defaulting to what Tcl gave +# +# Arguments: +# none +# +# Results: +# +# If --prefix or --exec-prefix was not specified, $prefix and +# $exec_prefix will be set to the values given to Tcl when it was +# configured. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_PREFIX], [ + if test "${prefix}" = "NONE"; then + prefix_default=yes + if test x"${TCL_PREFIX}" != x; then + AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) + prefix=${TCL_PREFIX} + else + AC_MSG_NOTICE([--prefix defaulting to /usr/local]) + prefix=/usr/local + fi + fi + if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ + -o x"${exec_prefix_default}" = x"yes" ; then + if test x"${TCL_EXEC_PREFIX}" != x; then + AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) + exec_prefix=${TCL_EXEC_PREFIX} + else + AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) + exec_prefix=$prefix + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER_CC -- +# +# Do compiler checks the way we want. This is just a replacement +# for AC_PROG_CC in TEA configure.in files to make them cleaner. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER_CC], [ + # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) + # in this macro, they need to go into TEA_SETUP_COMPILER instead. + + # If the user did not set CFLAGS, set it now to keep + # the AC_PROG_CC macro from adding "-g -O2". + if test "${CFLAGS+set}" != "set" ; then + CFLAGS="" + fi + + AC_PROG_CC + AC_PROG_CPP + + AC_PROG_INSTALL + + #-------------------------------------------------------------------- + # Checks to see if the make program sets the $MAKE variable. + #-------------------------------------------------------------------- + + AC_PROG_MAKE_SET + + #-------------------------------------------------------------------- + # Find ranlib + #-------------------------------------------------------------------- + + AC_PROG_RANLIB + + #-------------------------------------------------------------------- + # Determines the correct binary file extension (.o, .obj, .exe etc.) + #-------------------------------------------------------------------- + + AC_OBJEXT + AC_EXEEXT +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER -- +# +# Do compiler checks that use the compiler. This must go after +# TEA_SETUP_COMPILER_CC, which does the actual compiler check. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER], [ + # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. + AC_REQUIRE([TEA_SETUP_COMPILER_CC]) + + #------------------------------------------------------------------------ + # If we're using GCC, see if the compiler understands -pipe. If so, use it. + # It makes compiling go faster. (This is only a performance feature.) + #------------------------------------------------------------------------ + + if test -z "$no_pipe" -a -n "$GCC"; then + AC_CACHE_CHECK([if the compiler understands -pipe], + tcl_cv_cc_pipe, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" + AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) + CFLAGS=$hold_cflags]) + if test $tcl_cv_cc_pipe = yes; then + CFLAGS="$CFLAGS -pipe" + fi + fi + + #-------------------------------------------------------------------- + # Common compiler flag setup + #-------------------------------------------------------------------- + + AC_C_BIGENDIAN + if test "${TEA_PLATFORM}" = "unix" ; then + TEA_TCL_LINK_LIBS + TEA_MISSING_POSIX_HEADERS + # Let the user call this, because if it triggers, they will + # need a compat/strtod.c that is correct. Users can also + # use Tcl_GetDouble(FromObj) instead. + #TEA_BUGGY_STRTOD + fi +]) + +#------------------------------------------------------------------------ +# TEA_MAKE_LIB -- +# +# Generate a line that can be used to build a shared/unshared library +# in a platform independent manner. +# +# Arguments: +# none +# +# Requires: +# +# Results: +# +# Defines the following vars: +# CFLAGS - Done late here to note disturb other AC macros +# MAKE_LIB - Command to execute to build the Tcl library; +# differs depending on whether or not Tcl is being +# compiled as a shared library. +# MAKE_SHARED_LIB Makefile rule for building a shared library +# MAKE_STATIC_LIB Makefile rule for building a static library +# MAKE_STUB_LIB Makefile rule for building a stub library +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_MAKE_LIB], [ + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then + MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" + MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" + else + MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" + MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" + fi + + if test "${SHARED_BUILD}" = "1" ; then + MAKE_LIB="${MAKE_SHARED_LIB} " + else + MAKE_LIB="${MAKE_STATIC_LIB} " + fi + + #-------------------------------------------------------------------- + # Shared libraries and static libraries have different names. + # Use the double eval to make sure any variables in the suffix is + # substituted. (@@@ Might not be necessary anymore) + #-------------------------------------------------------------------- + + if test "${TEA_PLATFORM}" = "windows" ; then + if test "${SHARED_BUILD}" = "1" ; then + # We force the unresolved linking of symbols that are really in + # the private libraries of Tcl and Tk. + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" + fi + eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + else + eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + if test "$GCC" = "yes"; then + PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} + fi + # These aren't needed on Windows (either MSVC or gcc) + RANLIB=: + RANLIB_STUB=: + else + RANLIB_STUB="${RANLIB}" + if test "${SHARED_BUILD}" = "1" ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" + fi + eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + RANLIB=: + else + eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + fi + + # These are escaped so that only CFLAGS is picked up at configure time. + # The other values will be substituted at make time. + CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" + if test "${SHARED_BUILD}" = "1" ; then + CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" + fi + + AC_SUBST(MAKE_LIB) + AC_SUBST(MAKE_SHARED_LIB) + AC_SUBST(MAKE_STATIC_LIB) + AC_SUBST(MAKE_STUB_LIB) + AC_SUBST(RANLIB_STUB) +]) + +#------------------------------------------------------------------------ +# TEA_LIB_SPEC -- +# +# Compute the name of an existing object library located in libdir +# from the given base name and produce the appropriate linker flags. +# +# Arguments: +# basename The base name of the library without version +# numbers, extensions, or "lib" prefixes. +# extra_dir Extra directory in which to search for the +# library. This location is used first, then +# $prefix/$exec-prefix, then some defaults. +# +# Requires: +# TEA_INIT and TEA_PREFIX must be called first. +# +# Results: +# +# Defines the following vars: +# ${basename}_LIB_NAME The computed library name. +# ${basename}_LIB_SPEC The computed linker flags. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LIB_SPEC], [ + AC_MSG_CHECKING([for $1 library]) + + # Look in exec-prefix for the library (defined by TEA_PREFIX). + + tea_lib_name_dir="${exec_prefix}/lib" + + # Or in a user-specified location. + + if test x"$2" != x ; then + tea_extra_lib_dir=$2 + else + tea_extra_lib_dir=NONE + fi + + for i in \ + `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do + if test -f "$i" ; then + tea_lib_name_dir=`dirname $i` + $1_LIB_NAME=`basename $i` + $1_LIB_PATH_NAME=$i + break + fi + done + + if test "${TEA_PLATFORM}" = "windows"; then + $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" + else + # Strip off the leading "lib" and trailing ".a" or ".so" + + tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` + $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" + fi + + if test "x${$1_LIB_NAME}" = x ; then + AC_MSG_ERROR([not found]) + else + AC_MSG_RESULT([${$1_LIB_SPEC}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TCL_HEADERS -- +# +# Locate the private Tcl include files +# +# Arguments: +# +# Requires: +# TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has +# already been called. +# +# Results: +# +# Substs the following vars: +# TCL_TOP_DIR_NATIVE +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ + # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} + AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) + AC_MSG_CHECKING([for Tcl private include files]) + + TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` + TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" + + # Check to see if tclPort.h isn't already with the public headers + # Don't look for tclInt.h because that resides with tcl.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tclh}/tclWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tclh}/tclUnixPort.h"; then + result="private headers found with public headers" + else + TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" + if test "${TEA_PLATFORM}" = "windows"; then + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" + else + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TCL_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -d "${TCL_BIN_DIR}/Headers" -a \ + -d "${TCL_BIN_DIR}/PrivateHeaders"; then + TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" + else + TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TCL_INCLUDES}" + else + if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then + AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) + fi + result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" + fi + fi + + AC_SUBST(TCL_TOP_DIR_NATIVE) + + AC_SUBST(TCL_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TCL_HEADERS -- +# +# Locate the installed public Tcl header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tclinclude switch to configure. +# Result is cached. +# +# Substs the following vars: +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ + AC_MSG_CHECKING([for Tcl public headers]) + + AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tclh, [ + # Use the value from --with-tclinclude, if it was given + + if test x"${with_tclinclude}" != x ; then + if test -f "${with_tclinclude}/tcl.h" ; then + ac_cv_c_tclh=${with_tclinclude} + else + AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers directory + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tcl is not installed, + # and in that situation, look there before installed locations. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TCL_INCLUDE_SPEC}" != x ; then + d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tcl.h" ; then + ac_cv_c_tclh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tclh}" = x ; then + AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tclh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` + + TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TCL_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TK_HEADERS -- +# +# Locate the private Tk include files +# +# Arguments: +# +# Requires: +# TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has +# already been called. +# +# Results: +# +# Substs the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ + # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} + AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) + AC_MSG_CHECKING([for Tk private include files]) + + TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` + TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" + + # Check to see if tkPort.h isn't already with the public headers + # Don't look for tkInt.h because that resides with tk.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tkh}/tkWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tkh}/tkUnixPort.h"; then + result="private headers found with public headers" + else + TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" + TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" + if test "${TEA_PLATFORM}" = "windows"; then + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" + else + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TK_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" + # Detect and add ttk subdir + if test -d "${TK_SRC_DIR}/generic/ttk"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" + fi + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -d "${TK_BIN_DIR}/Headers" -a \ + -d "${TK_BIN_DIR}/PrivateHeaders"; then + TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" + else + TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TK_INCLUDES}" + else + if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then + AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) + fi + result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" + fi + fi + + AC_SUBST(TK_TOP_DIR_NATIVE) + AC_SUBST(TK_XLIB_DIR_NATIVE) + + AC_SUBST(TK_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TK_HEADERS -- +# +# Locate the installed public Tk header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tkinclude switch to configure. +# Result is cached. +# +# Substs the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ + AC_MSG_CHECKING([for Tk public headers]) + + AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tkh, [ + # Use the value from --with-tkinclude, if it was given + + if test x"${with_tkinclude}" != x ; then + if test -f "${with_tkinclude}/tk.h" ; then + ac_cv_c_tkh=${with_tkinclude} + else + AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers directory. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tk is not installed, + # and in that situation, look there before installed locations. + if test -f "${TK_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tk's --prefix location, + # relative to directory of tkConfig.sh, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TK_PREFIX}/include 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TK_INCLUDE_SPEC}" != x ; then + d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tk.h" ; then + ac_cv_c_tkh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tkh}" = x ; then + AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tkh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` + + TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TK_INCLUDES) + + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + # On Windows and Aqua, we need the X compat headers + AC_MSG_CHECKING([for X11 header files]) + if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then + INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" + TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + AC_SUBST(TK_XINCLUDES) + fi + AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PATH_CONFIG -- +# +# Locate the ${1}Config.sh file and perform a sanity check on +# the ${1} compile flags. These are used by packages like +# [incr Tk] that load *Config.sh files from more than Tcl and Tk. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-$1=... +# +# Defines the following vars: +# $1_BIN_DIR Full path to the directory containing +# the $1Config.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_CONFIG], [ + # + # Ok, lets find the $1 configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-$1 + # + + if test x"${no_$1}" = x ; then + # we reset no_$1 in case something fails here + no_$1=true + AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) + AC_MSG_CHECKING([for $1 configuration]) + AC_CACHE_VAL(ac_cv_c_$1config,[ + + # First check to see if --with-$1 was specified. + if test x"${with_$1config}" != x ; then + case ${with_$1config} in + */$1Config.sh ) + if test -f ${with_$1config}; then + AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) + with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` + fi;; + esac + if test -f "${with_$1config}/$1Config.sh" ; then + ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` + else + AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) + fi + fi + + # then check for a private $1 installation + if test x"${ac_cv_c_$1config}" = x ; then + for i in \ + ../$1 \ + `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../$1 \ + `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../../$1 \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ${srcdir}/../$1 \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + if test -f "$i/unix/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i/unix; pwd)` + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_$1config}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + done + fi + ]) + + if test x"${ac_cv_c_$1config}" = x ; then + $1_BIN_DIR="# no $1 configs found" + AC_MSG_WARN([Cannot find $1 configuration definitions]) + exit 0 + else + no_$1= + $1_BIN_DIR=${ac_cv_c_$1config} + AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG -- +# +# Load the $1Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1_BIN_DIR +# +# Results: +# +# Subst the following vars: +# $1_SRC_DIR +# $1_LIB_FILE +# $1_LIB_SPEC +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_CONFIG], [ + AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) + + if test -f "${$1_BIN_DIR}/$1Config.sh" ; then + AC_MSG_RESULT([loading]) + . "${$1_BIN_DIR}/$1Config.sh" + else + AC_MSG_RESULT([file not found]) + fi + + # + # If the $1_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable $1_LIB_SPEC will be set to the value + # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC + # instead of $1_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + # + + if test -f "${$1_BIN_DIR}/Makefile" ; then + AC_MSG_WARN([Found Makefile - using build library specs for $1]) + $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} + $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} + $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} + fi + + AC_SUBST($1_VERSION) + AC_SUBST($1_BIN_DIR) + AC_SUBST($1_SRC_DIR) + + AC_SUBST($1_LIB_FILE) + AC_SUBST($1_LIB_SPEC) + + AC_SUBST($1_STUB_LIB_FILE) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_PATH) + + # Allow the caller to prevent this auto-check by specifying any 2nd arg + AS_IF([test "x$2" = x], [ + # Check both upper and lower-case variants + # If a dev wanted non-stubs libs, this function could take an option + # to not use _STUB in the paths below + AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], + [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], + [TEA_LOAD_CONFIG_LIB($1_STUB)]) + ]) +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG_LIB -- +# +# Helper function to load correct library from another extension's +# ${PACKAGE}Config.sh. +# +# Results: +# Adds to LIBS the appropriate extension library +# +#------------------------------------------------------------------------ +AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ + AC_MSG_CHECKING([For $1 library for LIBS]) + # This simplifies the use of stub libraries by automatically adding + # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, + # but this is called before CONFIG_CFLAGS. More importantly, this adds + # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. + if test "x${$1_LIB_SPEC}" != "x" ; then + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then + TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) + AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) + else + TEA_ADD_LIBS([${$1_LIB_SPEC}]) + AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) + fi + else + AC_MSG_RESULT([file not found]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_EXPORT_CONFIG -- +# +# Define the data to insert into the ${PACKAGE}Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1 +# +# Results: +# Subst the following vars: +# +#------------------------------------------------------------------------ + +AC_DEFUN(TEA_EXPORT_CONFIG, [ + #-------------------------------------------------------------------- + # These are for $1Config.sh + #-------------------------------------------------------------------- + + # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) + eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" + if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then + eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" + eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" + else + eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + fi + $1_BUILD_LIB_SPEC="-L`pwd` ${$1_LIB_FLAG}" + $1_LIB_SPEC="-L${pkglibdir} ${$1_LIB_FLAG}" + $1_BUILD_STUB_LIB_SPEC="-L`pwd` [$]{$1_STUB_LIB_FLAG}" + $1_STUB_LIB_SPEC="-L${pkglibdir} [$]{$1_STUB_LIB_FLAG}" + $1_BUILD_STUB_LIB_PATH="`pwd`/[$]{PKG_STUB_LIB_FILE}" + $1_STUB_LIB_PATH="${pkglibdir}/[$]{PKG_STUB_LIB_FILE}" + + AC_SUBST($1_BUILD_LIB_SPEC) + AC_SUBST($1_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_PATH) + AC_SUBST($1_STUB_LIB_PATH) + + AC_SUBST(MAJOR_VERSION) + AC_SUBST(MINOR_VERSION) + AC_SUBST(PATCHLEVEL) +]) + + +#------------------------------------------------------------------------ +# TEA_PATH_CELIB -- +# +# Locate Keuchel's celib emulation layer for targeting Win/CE +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-celib=... +# +# Defines the following vars: +# CELIB_DIR Full path to the directory containing +# the include and platform lib files +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_CELIB], [ + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-celib + + if test x"${no_celib}" = x ; then + # we reset no_celib in case something fails here + no_celib=true + AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) + AC_MSG_CHECKING([for Windows/CE celib directory]) + AC_CACHE_VAL(ac_cv_c_celibconfig,[ + # First check to see if --with-celibconfig was specified. + if test x"${with_celibconfig}" != x ; then + if test -d "${with_celibconfig}/inc" ; then + ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` + else + AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) + fi + fi + + # then check for a celib library + if test x"${ac_cv_c_celibconfig}" = x ; then + for i in \ + ../celib-palm-3.0 \ + ../celib \ + ../../celib-palm-3.0 \ + ../../celib \ + `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ + ${srcdir}/../celib-palm-3.0 \ + ${srcdir}/../celib \ + `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ + ; do + if test -d "$i/inc" ; then + ac_cv_c_celibconfig=`(cd $i; pwd)` + break + fi + done + fi + ]) + if test x"${ac_cv_c_celibconfig}" = x ; then + AC_MSG_ERROR([Cannot find celib support library directory]) + else + no_celib= + CELIB_DIR=${ac_cv_c_celibconfig} + CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` + AC_MSG_RESULT([found $CELIB_DIR]) + fi + fi +]) + + +# Local Variables: +# mode: autoconf +# End: diff --git a/autoconf/tea/win/makefile.vc b/autoconf/tea/win/makefile.vc new file mode 100644 index 0000000000..a5e4627707 --- /dev/null +++ b/autoconf/tea/win/makefile.vc @@ -0,0 +1,414 @@ +# makefile.vc -- -*- Makefile -*- +# +# Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+) +# +# This makefile is based upon the Tcl 8.4 Makefile.vc and modified to +# make it suitable as a general package makefile. Look for the word EDIT +# which marks sections that may need modification. As a minumum you will +# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values +# relevant to your package. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# Copyright (c) 1995-1996 Sun Microsystems, Inc. +# Copyright (c) 1998-2000 Ajuba Solutions. +# Copyright (c) 2001 ActiveState Corporation. +# Copyright (c) 2001-2002 David Gravereaux. +# Copyright (c) 2003 Pat Thoyts +# +#------------------------------------------------------------------------- +# RCS: @(#)$Id: makefile.vc,v 1.4 2004/07/26 08:22:05 patthoyts Exp $ +#------------------------------------------------------------------------- + +!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) +MSG = ^ +You will need to run vcvars32.bat from Developer Studio, first, to setup^ +the environment. Jump to this line to read the new instructions. +!error $(MSG) +!endif + +#------------------------------------------------------------------------------ +# HOW TO USE this makefile: +# +# 1) It is now necessary to have %MSVCDir% set in the environment. This is +# used as a check to see if vcvars32.bat had been run prior to running +# nmake or during the installation of Microsoft Visual C++, MSVCDir had +# been set globally and the PATH adjusted. Either way is valid. +# +# You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin +# directory to setup the proper environment, if needed, for your current +# setup. This is a needed bootstrap requirement and allows the swapping of +# different environments to be easier. +# +# 2) To use the Platform SDK (not expressly needed), run setenv.bat after +# vcvars32.bat according to the instructions for it. This can also turn on +# the 64-bit compiler, if your SDK has it. +# +# 3) Targets are: +# all -- Builds everything. +# -- Builds the project (eg: nmake sample) +# test -- Builds and runs the test suite. +# install -- Installs the built binaries and libraries to $(INSTALLDIR) +# in an appropriate subdirectory. +# clean/realclean/distclean -- varying levels of cleaning. +# +# 4) Macros usable on the commandline: +# INSTALLDIR= +# Sets where to install Tcl from the built binaries. +# C:\Progra~1\Tcl is assumed when not specified. +# +# OPTS=static,msvcrt,staticpkg,threads,symbols,profile,loimpact,none +# Sets special options for the core. The default is for none. +# Any combination of the above may be used (comma separated). +# 'none' will over-ride everything to nothing. +# +# static = Builds a static library of the core instead of a +# dll. The shell will be static (and large), as well. +# msvcrt = Effects the static option only to switch it from +# using libcmt(d) as the C runtime [by default] to +# msvcrt(d). This is useful for static embedding +# support. +# staticpkg = Effects the static option only to switch +# tclshXX.exe to have the dde and reg extension linked +# inside it. +# threads = Turns on full multithreading support. +# thrdalloc = Use the thread allocator (shared global free pool). +# symbols = Adds symbols for step debugging. +# profile = Adds profiling hooks. Map file is assumed. +# loimpact = Adds a flag for how NT treats the heap to keep memory +# in use, low. This is said to impact alloc performance. +# +# STATS=memdbg,compdbg,none +# Sets optional memory and bytecode compiler debugging code added +# to the core. The default is for none. Any combination of the +# above may be used (comma separated). 'none' will over-ride +# everything to nothing. +# +# memdbg = Enables the debugging memory allocator. +# compdbg = Enables byte compilation logging. +# +# MACHINE=(IX86|IA64|ALPHA) +# Set the machine type used for the compiler, linker, and +# resource compiler. This hook is needed to tell the tools +# when alternate platforms are requested. IX86 is the default +# when not specified. +# +# TMP_DIR= +# OUT_DIR= +# Hooks to allow the intermediate and output directories to be +# changed. $(OUT_DIR) is assumed to be +# $(BINROOT)\(Release|Debug) based on if symbols are requested. +# $(TMP_DIR) will de $(OUT_DIR)\ by default. +# +# TESTPAT= +# Reads the tests requested to be run from this file. +# +# CFG_ENCODING=encoding +# name of encoding for configuration information. Defaults +# to cp1252 +# +# 5) Examples: +# +# Basic syntax of calling nmake looks like this: +# nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]] +# +# Standard (no frills) +# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat +# Setting environment for using Microsoft Visual C++ tools. +# c:\tcl_src\win\>nmake -f makefile.vc all +# c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl +# +# Building for Win64 +# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat +# Setting environment for using Microsoft Visual C++ tools. +# c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL +# Targeting Windows pre64 RETAIL +# c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64 +# +#------------------------------------------------------------------------------ +#============================================================================== +############################################################################### +#------------------------------------------------------------------------------ + +!if !exist("makefile.vc") +MSG = ^ +You must run this makefile only from the directory it is in.^ +Please `cd` to its location first. +!error $(MSG) +!endif + +#------------------------------------------------------------------------- +# Project specific information (EDIT) +# +# You should edit this with the name and version of your project. This +# information is used to generate the name of the package library and +# it's install location. +# +# For example, the sample extension is going to build sample04.dll and +# would install it into $(INSTALLDIR)\lib\sample04 +# +# You need to specify the object files that need to be linked into your +# binary here. +# +#------------------------------------------------------------------------- + +PROJECT = sqlite3 +!include "rules.vc" + +# nmakehelp -V will search the file for tag, skips until a +# number and returns all character until a character not in [0-9.ab] +# is read. + +!if [echo REM = This file is generated from Makefile.vc > versions.vc] +!endif +# get project version from row "AC_INIT([sqlite], [3.7.14])" +!if [echo DOTVERSION = \>> versions.vc] \ + && [nmakehlp -V ..\configure.in AC_INIT >> versions.vc] +!endif +!include "versions.vc" + +VERSION = $(DOTVERSION:.=) +STUBPREFIX = $(PROJECT)stub + +DLLOBJS = \ + $(TMP_DIR)\tclsqlite3.obj + +#------------------------------------------------------------------------- +# Target names and paths ( shouldn't need changing ) +#------------------------------------------------------------------------- + +BINROOT = . +ROOT = .. + +PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib +PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) +PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) + +PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib +PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) + +### Make sure we use backslash only. +PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) +LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) +BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) +DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) +SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) +INCLUDE_INSTALL_DIR = $(_TCLDIR)\include + +### The following paths CANNOT have spaces in them. +GENERICDIR = $(ROOT)\generic +WINDIR = $(ROOT)\win +LIBDIR = $(ROOT)\library +DOCDIR = $(ROOT)\doc +TOOLSDIR = $(ROOT)\tools +COMPATDIR = $(ROOT)\compat + +#--------------------------------------------------------------------- +# Compile flags +#--------------------------------------------------------------------- + +!if !$(DEBUG) +!if $(OPTIMIZING) +### This cranks the optimization level to maximize speed +cdebug = -O2 -Op -Gs +!else +cdebug = +!endif +!else if "$(MACHINE)" == "IA64" +### Warnings are too many, can't support warnings into errors. +cdebug = -Z7 -Od -GZ +!else +cdebug = -Z7 -WX -Od -GZ +!endif + +### Declarations common to all compiler options +cflags = -nologo -c -W3 -YX -Fp$(TMP_DIR)^\ + +!if $(MSVCRT) +!if $(DEBUG) +crt = -MDd +!else +crt = -MD +!endif +!else +!if $(DEBUG) +crt = -MTd +!else +crt = -MT +!endif +!endif + +INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" \ + -I"$(ROOT)\.." +BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) \ + -DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \ + -DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1 +CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE -DSQLITE_ENABLE_FTS3=1 +TCL_CFLAGS = -DBUILD_sqlite -DUSE_TCL_STUBS \ + -DPACKAGE_VERSION="\"$(DOTVERSION)\"" $(BASE_CLFAGS) \ + $(OPTDEFINES) + +#--------------------------------------------------------------------- +# Link flags +#--------------------------------------------------------------------- + +!if $(DEBUG) +ldebug = -debug:full -debugtype:cv +!else +ldebug = -release -opt:ref -opt:icf,3 +!endif + +### Declarations common to all linker options +lflags = -nologo -machine:$(MACHINE) $(ldebug) + +!if $(PROFILE) +lflags = $(lflags) -profile +!endif + +!if $(ALIGN98_HACK) && !$(STATIC_BUILD) +### Align sections for PE size savings. +lflags = $(lflags) -opt:nowin98 +!else if !$(ALIGN98_HACK) && $(STATIC_BUILD) +### Align sections for speed in loading by choosing the virtual page size. +lflags = $(lflags) -align:4096 +!endif + +!if $(LOIMPACT) +lflags = $(lflags) -ws:aggressive +!endif + +dlllflags = $(lflags) -dll +conlflags = $(lflags) -subsystem:console +guilflags = $(lflags) -subsystem:windows +baselibs = $(TCLSTUBLIB) + +#--------------------------------------------------------------------- +# TclTest flags +#--------------------------------------------------------------------- + +!IF "$(TESTPAT)" != "" +TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) +!ENDIF + +#--------------------------------------------------------------------- +# Project specific targets (EDIT) +#--------------------------------------------------------------------- + +all: setup $(PROJECT) +$(PROJECT): setup $(PRJLIB) +install: install-binaries install-libraries install-docs + +# Tests need to ensure we load the right dll file we +# have to handle the output differently on Win9x. +# +!if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" +test: setup $(PROJECT) + set TCL_LIBRARY=$(ROOT)/library + $(TCLSH) << +load $(PRJLIB:\=/) +cd "$(ROOT)/tests" +set argv "$(TESTFLAGS)" +source all.tcl +<< +!else +test: setup $(PROJECT) + echo Please wait while the test results are collected + set TCL_LIBRARY=$(ROOT)/library + $(TCLSH) << >tests.log +load $(PRJLIB:\=/) +cd "$(ROOT)/tests" +set argv "$(TESTFLAGS)" +source all.tcl +<< + type tests.log | more +!endif + +setup: + @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) + @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) + +$(PRJLIB): $(DLLOBJS) + $(link32) $(dlllflags) -out:$@ $(baselibs) @<< +$** +<< + -@del $*.exp + +$(PRJSTUBLIB): $(PRJSTUBOBJS) + $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) + +#--------------------------------------------------------------------- +# Implicit rules +#--------------------------------------------------------------------- + +{$(WINDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(WINDIR)}.rc{$(TMP_DIR)}.res: + $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ +!if $(DEBUG) + -d DEBUG \ +!endif +!if $(TCL_THREADS) + -d TCL_THREADS \ +!endif +!if $(STATIC_BUILD) + -d STATIC_BUILD \ +!endif + $< + +.SUFFIXES: +.SUFFIXES:.c .rc + +#--------------------------------------------------------------------- +# Installation. (EDIT) +# +# You may need to modify this section to reflect the final distribution +# of your files and possibly to generate documentation. +# +#--------------------------------------------------------------------- + +install-binaries: + @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' + @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" + @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL + +install-libraries: + @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' + @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" + @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' + @type << >"$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl" +package ifneeded $(PROJECT) $(DOTVERSION) \ + [list load [file join $$dir $(PRJLIBNAME)] sqlite3] +<< + +install-docs: + @echo Installing documentation files to '$(DOC_INSTALL_DIR)' + @if exist $(DOCDIR) $(CPY) $(DOCDIR)\*.n "$(DOC_INSTALL_DIR)" + +#--------------------------------------------------------------------- +# Clean up +#--------------------------------------------------------------------- + +clean: + @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) + @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc + +realclean: clean + @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) + +distclean: realclean + @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe + @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj diff --git a/autoconf/tea/win/nmakehlp.c b/autoconf/tea/win/nmakehlp.c new file mode 100644 index 0000000000..2868857efd --- /dev/null +++ b/autoconf/tea/win/nmakehlp.c @@ -0,0 +1,694 @@ +/* + * ---------------------------------------------------------------------------- + * nmakehlp.c -- + * + * This is used to fix limitations within nmake and the environment. + * + * Copyright (c) 2002 by David Gravereaux. + * Copyright (c) 2006 by Pat Thoyts + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * ---------------------------------------------------------------------------- + */ + +#define _CRT_SECURE_NO_DEPRECATE +#include +#define NO_SHLWAPI_GDI +#define NO_SHLWAPI_STREAM +#define NO_SHLWAPI_REG +#include +#pragma comment (lib, "user32.lib") +#pragma comment (lib, "kernel32.lib") +#pragma comment (lib, "shlwapi.lib") +#include +#include + +/* + * This library is required for x64 builds with _some_ versions of MSVC + */ +#if defined(_M_IA64) || defined(_M_AMD64) +#if _MSC_VER >= 1400 && _MSC_VER < 1500 +#pragma comment(lib, "bufferoverflowU") +#endif +#endif + +/* ISO hack for dumb VC++ */ +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + + +/* protos */ + +static int CheckForCompilerFeature(const char *option); +static int CheckForLinkerFeature(const char *option); +static int IsIn(const char *string, const char *substring); +static int SubstituteFile(const char *substs, const char *filename); +static int QualifyPath(const char *path); +static const char *GetVersionFromFile(const char *filename, const char *match); +static DWORD WINAPI ReadFromPipe(LPVOID args); + +/* globals */ + +#define CHUNK 25 +#define STATICBUFFERSIZE 1000 +typedef struct { + HANDLE pipe; + char buffer[STATICBUFFERSIZE]; +} pipeinfo; + +pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; +pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; + +/* + * exitcodes: 0 == no, 1 == yes, 2 == error + */ + +int +main( + int argc, + char *argv[]) +{ + char msg[300]; + DWORD dwWritten; + int chars; + + /* + * Make sure children (cl.exe and link.exe) are kept quiet. + */ + + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + + /* + * Make sure the compiler and linker aren't effected by the outside world. + */ + + SetEnvironmentVariable("CL", ""); + SetEnvironmentVariable("LINK", ""); + + if (argc > 1 && *argv[1] == '-') { + switch (*(argv[1]+1)) { + case 'c': + if (argc != 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -c \n" + "Tests for whether cl.exe supports an option\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return CheckForCompilerFeature(argv[2]); + case 'l': + if (argc != 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -l \n" + "Tests for whether link.exe supports an option\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return CheckForLinkerFeature(argv[2]); + case 'f': + if (argc == 2) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -f \n" + "Find a substring within another\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } else if (argc == 3) { + /* + * If the string is blank, there is no match. + */ + + return 0; + } else { + return IsIn(argv[2], argv[3]); + } + case 's': + if (argc == 2) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -s \n" + "Perform a set of string map type substutitions on a file\n" + "exitcodes: 0\n", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return SubstituteFile(argv[2], argv[3]); + case 'V': + if (argc != 4) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -V filename matchstring\n" + "Extract a version from a file:\n" + "eg: pkgIndex.tcl \"package ifneeded http\"", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 0; + } + printf("%s\n", GetVersionFromFile(argv[2], argv[3])); + return 0; + case 'Q': + if (argc != 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -Q path\n" + "Emit the fully qualified path\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return QualifyPath(argv[2]); + } + } + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -c|-f|-l|-Q|-s|-V ...\n" + "This is a little helper app to equalize shell differences between WinNT and\n" + "Win9x and get nmake.exe to accomplish its job.\n", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + return 2; +} + +static int +CheckForCompilerFeature( + const char *option) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + DWORD threadID; + char msg[300]; + BOOL ok; + HANDLE hProcess, h, pipeThreads[2]; + char cmdline[100]; + + hProcess = GetCurrentProcess(); + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = INVALID_HANDLE_VALUE; + + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + + /* + * Create a non-inheritible pipe. + */ + + CreatePipe(&Out.pipe, &h, &sa, 0); + + /* + * Dupe the write side, make it inheritible, and close the original. + */ + + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Same as above, but for the error side. + */ + + CreatePipe(&Err.pipe, &h, &sa, 0); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Base command line. + */ + + lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); + + /* + * Append our option for testing + */ + + lstrcat(cmdline, option); + + /* + * Filename to compile, which exists, but is nothing and empty. + */ + + lstrcat(cmdline, " .\\nul"); + + ok = CreateProcess( + NULL, /* Module name. */ + cmdline, /* Command line. */ + NULL, /* Process handle not inheritable. */ + NULL, /* Thread handle not inheritable. */ + TRUE, /* yes, inherit handles. */ + DETACHED_PROCESS, /* No console for you. */ + NULL, /* Use parent's environment block. */ + NULL, /* Use parent's starting directory. */ + &si, /* Pointer to STARTUPINFO structure. */ + &pi); /* Pointer to PROCESS_INFORMATION structure. */ + + if (!ok) { + DWORD err = GetLastError(); + int chars = snprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], + (300-chars), 0); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); + return 2; + } + + /* + * Close our references to the write handles that have now been inherited. + */ + + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + WaitForInputIdle(pi.hProcess, 5000); + CloseHandle(pi.hThread); + + /* + * Start the pipe reader threads. + */ + + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); + pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); + + /* + * Block waiting for the process to end. + */ + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ + + WaitForMultipleObjects(2, pipeThreads, TRUE, 500); + CloseHandle(pipeThreads[0]); + CloseHandle(pipeThreads[1]); + + /* + * Look for the commandline warning code in both streams. + * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. + */ + + return !(strstr(Out.buffer, "D4002") != NULL + || strstr(Err.buffer, "D4002") != NULL + || strstr(Out.buffer, "D9002") != NULL + || strstr(Err.buffer, "D9002") != NULL + || strstr(Out.buffer, "D2021") != NULL + || strstr(Err.buffer, "D2021") != NULL); +} + +static int +CheckForLinkerFeature( + const char *option) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + DWORD threadID; + char msg[300]; + BOOL ok; + HANDLE hProcess, h, pipeThreads[2]; + char cmdline[100]; + + hProcess = GetCurrentProcess(); + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = INVALID_HANDLE_VALUE; + + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + /* + * Create a non-inheritible pipe. + */ + + CreatePipe(&Out.pipe, &h, &sa, 0); + + /* + * Dupe the write side, make it inheritible, and close the original. + */ + + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Same as above, but for the error side. + */ + + CreatePipe(&Err.pipe, &h, &sa, 0); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Base command line. + */ + + lstrcpy(cmdline, "link.exe -nologo "); + + /* + * Append our option for testing. + */ + + lstrcat(cmdline, option); + + ok = CreateProcess( + NULL, /* Module name. */ + cmdline, /* Command line. */ + NULL, /* Process handle not inheritable. */ + NULL, /* Thread handle not inheritable. */ + TRUE, /* yes, inherit handles. */ + DETACHED_PROCESS, /* No console for you. */ + NULL, /* Use parent's environment block. */ + NULL, /* Use parent's starting directory. */ + &si, /* Pointer to STARTUPINFO structure. */ + &pi); /* Pointer to PROCESS_INFORMATION structure. */ + + if (!ok) { + DWORD err = GetLastError(); + int chars = snprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], + (300-chars), 0); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); + return 2; + } + + /* + * Close our references to the write handles that have now been inherited. + */ + + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + WaitForInputIdle(pi.hProcess, 5000); + CloseHandle(pi.hThread); + + /* + * Start the pipe reader threads. + */ + + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); + pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); + + /* + * Block waiting for the process to end. + */ + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ + + WaitForMultipleObjects(2, pipeThreads, TRUE, 500); + CloseHandle(pipeThreads[0]); + CloseHandle(pipeThreads[1]); + + /* + * Look for the commandline warning code in the stderr stream. + */ + + return !(strstr(Out.buffer, "LNK1117") != NULL || + strstr(Err.buffer, "LNK1117") != NULL || + strstr(Out.buffer, "LNK4044") != NULL || + strstr(Err.buffer, "LNK4044") != NULL); +} + +static DWORD WINAPI +ReadFromPipe( + LPVOID args) +{ + pipeinfo *pi = (pipeinfo *) args; + char *lastBuf = pi->buffer; + DWORD dwRead; + BOOL ok; + + again: + if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { + CloseHandle(pi->pipe); + return (DWORD)-1; + } + ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); + if (!ok || dwRead == 0) { + CloseHandle(pi->pipe); + return 0; + } + lastBuf += dwRead; + goto again; + + return 0; /* makes the compiler happy */ +} + +static int +IsIn( + const char *string, + const char *substring) +{ + return (strstr(string, substring) != NULL); +} + +/* + * GetVersionFromFile -- + * Looks for a match string in a file and then returns the version + * following the match where a version is anything acceptable to + * package provide or package ifneeded. + */ + +static const char * +GetVersionFromFile( + const char *filename, + const char *match) +{ + size_t cbBuffer = 100; + static char szBuffer[100]; + char *szResult = NULL; + FILE *fp = fopen(filename, "rt"); + + if (fp != NULL) { + /* + * Read data until we see our match string. + */ + + while (fgets(szBuffer, cbBuffer, fp) != NULL) { + LPSTR p, q; + + p = strstr(szBuffer, match); + if (p != NULL) { + /* + * Skip to first digit. + */ + + while (*p && !isdigit(*p)) { + ++p; + } + + /* + * Find ending whitespace. + */ + + q = p; + while (*q && (isalnum(*q) || *q == '.')) { + ++q; + } + + memcpy(szBuffer, p, q - p); + szBuffer[q-p] = 0; + szResult = szBuffer; + break; + } + } + fclose(fp); + } + return szResult; +} + +/* + * List helpers for the SubstituteFile function + */ + +typedef struct list_item_t { + struct list_item_t *nextPtr; + char * key; + char * value; +} list_item_t; + +/* insert a list item into the list (list may be null) */ +static list_item_t * +list_insert(list_item_t **listPtrPtr, const char *key, const char *value) +{ + list_item_t *itemPtr = malloc(sizeof(list_item_t)); + if (itemPtr) { + itemPtr->key = strdup(key); + itemPtr->value = strdup(value); + itemPtr->nextPtr = NULL; + + while(*listPtrPtr) { + listPtrPtr = &(*listPtrPtr)->nextPtr; + } + *listPtrPtr = itemPtr; + } + return itemPtr; +} + +static void +list_free(list_item_t **listPtrPtr) +{ + list_item_t *tmpPtr, *listPtr = *listPtrPtr; + while (listPtr) { + tmpPtr = listPtr; + listPtr = listPtr->nextPtr; + free(tmpPtr->key); + free(tmpPtr->value); + free(tmpPtr); + } +} + +/* + * SubstituteFile -- + * As windows doesn't provide anything useful like sed and it's unreliable + * to use the tclsh you are building against (consider x-platform builds - + * eg compiling AMD64 target from IX86) we provide a simple substitution + * option here to handle autoconf style substitutions. + * The substitution file is whitespace and line delimited. The file should + * consist of lines matching the regular expression: + * \s*\S+\s+\S*$ + * + * Usage is something like: + * nmakehlp -S << $** > $@ + * @PACKAGE_NAME@ $(PACKAGE_NAME) + * @PACKAGE_VERSION@ $(PACKAGE_VERSION) + * << + */ + +static int +SubstituteFile( + const char *substitutions, + const char *filename) +{ + size_t cbBuffer = 1024; + static char szBuffer[1024], szCopy[1024]; + char *szResult = NULL; + list_item_t *substPtr = NULL; + FILE *fp, *sp; + + fp = fopen(filename, "rt"); + if (fp != NULL) { + + /* + * Build a list of substutitions from the first filename + */ + + sp = fopen(substitutions, "rt"); + if (sp != NULL) { + while (fgets(szBuffer, cbBuffer, sp) != NULL) { + char *ks, *ke, *vs, *ve; + ks = szBuffer; + while (ks && *ks && isspace(*ks)) ++ks; + ke = ks; + while (ke && *ke && !isspace(*ke)) ++ke; + vs = ke; + while (vs && *vs && isspace(*vs)) ++vs; + ve = vs; + while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; + *ke = 0, *ve = 0; + list_insert(&substPtr, ks, vs); + } + fclose(sp); + } + + /* debug: dump the list */ +#ifdef _DEBUG + { + int n = 0; + list_item_t *p = NULL; + for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { + fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); + } + } +#endif + + /* + * Run the substitutions over each line of the input + */ + + while (fgets(szBuffer, cbBuffer, fp) != NULL) { + list_item_t *p = NULL; + for (p = substPtr; p != NULL; p = p->nextPtr) { + char *m = strstr(szBuffer, p->key); + if (m) { + char *cp, *op, *sp; + cp = szCopy; + op = szBuffer; + while (op != m) *cp++ = *op++; + sp = p->value; + while (sp && *sp) *cp++ = *sp++; + op += strlen(p->key); + while (*op) *cp++ = *op++; + *cp = 0; + memcpy(szBuffer, szCopy, sizeof(szCopy)); + } + } + printf(szBuffer); + } + + list_free(&substPtr); + } + fclose(fp); + return 0; +} + +/* + * QualifyPath -- + * + * This composes the current working directory with a provided path + * and returns the fully qualified and normalized path. + * Mostly needed to setup paths for testing. + */ + +static int +QualifyPath( + const char *szPath) +{ + char szCwd[MAX_PATH + 1]; + char szTmp[MAX_PATH + 1]; + char *p; + GetCurrentDirectory(MAX_PATH, szCwd); + while ((p = strchr(szPath, '/')) && *p) + *p = '\\'; + PathCombine(szTmp, szCwd, szPath); + PathCanonicalize(szCwd, szTmp); + printf("%s\n", szCwd); + return 0; +} + +/* + * Local variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff --git a/autoconf/tea/win/rules.vc b/autoconf/tea/win/rules.vc new file mode 100644 index 0000000000..99471053c8 --- /dev/null +++ b/autoconf/tea/win/rules.vc @@ -0,0 +1,711 @@ +#------------------------------------------------------------------------------ +# rules.vc -- +# +# Microsoft Visual C++ makefile include for decoding the commandline +# macros. This file does not need editing to build Tcl. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# Copyright (c) 2001-2003 David Gravereaux. +# Copyright (c) 2003-2008 Patrick Thoyts +#------------------------------------------------------------------------------ + +!ifndef _RULES_VC +_RULES_VC = 1 + +cc32 = $(CC) # built-in default. +link32 = link +lib32 = lib +rc32 = $(RC) # built-in default. + +!ifndef INSTALLDIR +### Assume the normal default. +_INSTALLDIR = C:\Program Files\Tcl +!else +### Fix the path separators. +_INSTALLDIR = $(INSTALLDIR:/=\) +!endif + +#---------------------------------------------------------- +# Set the proper copy method to avoid overwrite questions +# to the user when copying files and selecting the right +# "delete all" method. +#---------------------------------------------------------- + +!if "$(OS)" == "Windows_NT" +RMDIR = rmdir /S /Q +ERRNULL = 2>NUL +!if ![ver | find "4.0" > nul] +CPY = echo y | xcopy /i >NUL +COPY = copy >NUL +!else +CPY = xcopy /i /y >NUL +COPY = copy /y >NUL +!endif +!else # "$(OS)" != "Windows_NT" +CPY = xcopy /i >_JUNK.OUT # On Win98 NUL does not work here. +COPY = copy >_JUNK.OUT # On Win98 NUL does not work here. +RMDIR = deltree /Y +NULL = \NUL # Used in testing directory existence +ERRNULL = >NUL # Win9x shell cannot redirect stderr +!endif +MKDIR = mkdir + +#------------------------------------------------------------------------------ +# Determine the host and target architectures and compiler version. +#------------------------------------------------------------------------------ + +_HASH=^# +_VC_MANIFEST_EMBED_EXE= +_VC_MANIFEST_EMBED_DLL= +VCVER=0 +!if ![echo VCVERSION=_MSC_VER > vercl.x] \ + && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ + && ![echo ARCH=IX86 >> vercl.x] \ + && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ + && ![echo ARCH=AMD64 >> vercl.x] \ + && ![echo $(_HASH)endif >> vercl.x] \ + && ![cl -nologo -TC -P vercl.x $(ERRNULL)] +!include vercl.i +!if ![echo VCVER= ^\> vercl.vc] \ + && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] +!include vercl.vc +!endif +!endif +!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc] +!endif + +!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] +NATIVE_ARCH=IX86 +!else +NATIVE_ARCH=AMD64 +!endif + +# Since MSVC8 we must deal with manifest resources. +!if $(VCVERSION) >= 1400 +_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 +_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 +!endif + +!ifndef MACHINE +MACHINE=$(ARCH) +!endif + +!ifndef CFG_ENCODING +CFG_ENCODING = \"cp1252\" +!endif + +!message =============================================================================== + +#---------------------------------------------------------- +# build the helper app we need to overcome nmake's limiting +# environment. +#---------------------------------------------------------- + +!if !exist(nmakehlp.exe) +!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul] +!endif +!endif + +#---------------------------------------------------------- +# Test for compiler features +#---------------------------------------------------------- + +### test for optimizations +!if [nmakehlp -c -Ot] +!message *** Compiler has 'Optimizations' +OPTIMIZING = 1 +!else +!message *** Compiler does not have 'Optimizations' +OPTIMIZING = 0 +!endif + +OPTIMIZATIONS = + +!if [nmakehlp -c -Ot] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot +!endif + +!if [nmakehlp -c -Oi] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi +!endif + +!if [nmakehlp -c -Op] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Op +!endif + +!if [nmakehlp -c -fp:strict] +OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict +!endif + +!if [nmakehlp -c -Gs] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs +!endif + +!if [nmakehlp -c -GS] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GS +!endif + +!if [nmakehlp -c -GL] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GL +!endif + +DEBUGFLAGS = + +!if [nmakehlp -c -RTC1] +DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 +!elseif [nmakehlp -c -GZ] +DEBUGFLAGS = $(DEBUGFLAGS) -GZ +!endif + +COMPILERFLAGS =-W3 -DUNICODE -D_UNICODE + +# In v13 -GL and -YX are incompatible. +!if [nmakehlp -c -YX] +!if ![nmakehlp -c -GL] +OPTIMIZATIONS = $(OPTIMIZATIONS) -YX +!endif +!endif + +!if "$(MACHINE)" == "IX86" +### test for pentium errata +!if [nmakehlp -c -QI0f] +!message *** Compiler has 'Pentium 0x0f fix' +COMPILERFLAGS = $(COMPILERFLAGS) -QI0f +!else +!message *** Compiler does not have 'Pentium 0x0f fix' +!endif +!endif + +!if "$(MACHINE)" == "IA64" +### test for Itanium errata +!if [nmakehlp -c -QIA64_Bx] +!message *** Compiler has 'B-stepping errata workarounds' +COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx +!else +!message *** Compiler does not have 'B-stepping errata workarounds' +!endif +!endif + +!if "$(MACHINE)" == "IX86" +### test for -align:4096, when align:512 will do. +!if [nmakehlp -l -opt:nowin98] +!message *** Linker has 'Win98 alignment problem' +ALIGN98_HACK = 1 +!else +!message *** Linker does not have 'Win98 alignment problem' +ALIGN98_HACK = 0 +!endif +!else +ALIGN98_HACK = 0 +!endif + +LINKERFLAGS = + +!if [nmakehlp -l -ltcg] +LINKERFLAGS =-ltcg +!endif + +#---------------------------------------------------------- +# Decode the options requested. +#---------------------------------------------------------- + +!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"] +STATIC_BUILD = 0 +TCL_THREADS = 1 +DEBUG = 0 +SYMBOLS = 0 +PROFILE = 0 +PGO = 0 +MSVCRT = 0 +LOIMPACT = 0 +TCL_USE_STATIC_PACKAGES = 0 +USE_THREAD_ALLOC = 1 +UNCHECKED = 0 +!else +!if [nmakehlp -f $(OPTS) "static"] +!message *** Doing static +STATIC_BUILD = 1 +!else +STATIC_BUILD = 0 +!endif +!if [nmakehlp -f $(OPTS) "msvcrt"] +!message *** Doing msvcrt +MSVCRT = 1 +!else +MSVCRT = 0 +!endif +!if [nmakehlp -f $(OPTS) "staticpkg"] +!message *** Doing staticpkg +TCL_USE_STATIC_PACKAGES = 1 +!else +TCL_USE_STATIC_PACKAGES = 0 +!endif +!if [nmakehlp -f $(OPTS) "nothreads"] +!message *** Compile explicitly for non-threaded tcl +TCL_THREADS = 0 +!else +TCL_THREADS = 1 +USE_THREAD_ALLOC= 1 +!endif +!if [nmakehlp -f $(OPTS) "symbols"] +!message *** Doing symbols +DEBUG = 1 +!else +DEBUG = 0 +!endif +!if [nmakehlp -f $(OPTS) "pdbs"] +!message *** Doing pdbs +SYMBOLS = 1 +!else +SYMBOLS = 0 +!endif +!if [nmakehlp -f $(OPTS) "profile"] +!message *** Doing profile +PROFILE = 1 +!else +PROFILE = 0 +!endif +!if [nmakehlp -f $(OPTS) "pgi"] +!message *** Doing profile guided optimization instrumentation +PGO = 1 +!elseif [nmakehlp -f $(OPTS) "pgo"] +!message *** Doing profile guided optimization +PGO = 2 +!else +PGO = 0 +!endif +!if [nmakehlp -f $(OPTS) "loimpact"] +!message *** Doing loimpact +LOIMPACT = 1 +!else +LOIMPACT = 0 +!endif +!if [nmakehlp -f $(OPTS) "thrdalloc"] +!message *** Doing thrdalloc +USE_THREAD_ALLOC = 1 +!endif +!if [nmakehlp -f $(OPTS) "tclalloc"] +!message *** Doing tclalloc +USE_THREAD_ALLOC = 0 +!endif +!if [nmakehlp -f $(OPTS) "unchecked"] +!message *** Doing unchecked +UNCHECKED = 1 +!else +UNCHECKED = 0 +!endif +!endif + + +!if !$(STATIC_BUILD) +# Make sure we don't build overly fat DLLs. +MSVCRT = 1 +# We shouldn't statically put the extensions inside the shell when dynamic. +TCL_USE_STATIC_PACKAGES = 0 +!endif + + +#---------------------------------------------------------- +# Figure-out how to name our intermediate and output directories. +# We wouldn't want different builds to use the same .obj files +# by accident. +#---------------------------------------------------------- + +#---------------------------------------- +# Naming convention: +# t = full thread support. +# s = static library (as opposed to an +# import library) +# g = linked to the debug enabled C +# run-time. +# x = special static build when it +# links to the dynamic C run-time. +#---------------------------------------- +SUFX = tsgx + +!if $(DEBUG) +BUILDDIRTOP = Debug +!else +BUILDDIRTOP = Release +!endif + +!if "$(MACHINE)" != "IX86" +BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) +!endif +!if $(VCVER) > 6 +BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) +!endif + +!if !$(DEBUG) || $(DEBUG) && $(UNCHECKED) +SUFX = $(SUFX:g=) +!endif + +TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX + +!if !$(STATIC_BUILD) +TMP_DIRFULL = $(TMP_DIRFULL:Static=) +SUFX = $(SUFX:s=) +EXT = dll +!if $(MSVCRT) +TMP_DIRFULL = $(TMP_DIRFULL:X=) +SUFX = $(SUFX:x=) +!endif +!else +TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) +EXT = lib +!if !$(MSVCRT) +TMP_DIRFULL = $(TMP_DIRFULL:X=) +SUFX = $(SUFX:x=) +!endif +!endif + +!if !$(TCL_THREADS) +TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) +SUFX = $(SUFX:t=) +!endif + +!ifndef TMP_DIR +TMP_DIR = $(TMP_DIRFULL) +!ifndef OUT_DIR +OUT_DIR = .\$(BUILDDIRTOP) +!endif +!else +!ifndef OUT_DIR +OUT_DIR = $(TMP_DIR) +!endif +!endif + + +#---------------------------------------------------------- +# Decode the statistics requested. +#---------------------------------------------------------- + +!if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"] +TCL_MEM_DEBUG = 0 +TCL_COMPILE_DEBUG = 0 +!else +!if [nmakehlp -f $(STATS) "memdbg"] +!message *** Doing memdbg +TCL_MEM_DEBUG = 1 +!else +TCL_MEM_DEBUG = 0 +!endif +!if [nmakehlp -f $(STATS) "compdbg"] +!message *** Doing compdbg +TCL_COMPILE_DEBUG = 1 +!else +TCL_COMPILE_DEBUG = 0 +!endif +!endif + + +#---------------------------------------------------------- +# Decode the checks requested. +#---------------------------------------------------------- + +!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"] +TCL_NO_DEPRECATED = 0 +WARNINGS = -W3 +!else +!if [nmakehlp -f $(CHECKS) "nodep"] +!message *** Doing nodep check +TCL_NO_DEPRECATED = 1 +!else +TCL_NO_DEPRECATED = 0 +!endif +!if [nmakehlp -f $(CHECKS) "fullwarn"] +!message *** Doing full warnings check +WARNINGS = -W4 +!if [nmakehlp -l -warn:3] +LINKERFLAGS = $(LINKERFLAGS) -warn:3 +!endif +!else +WARNINGS = -W3 +!endif +!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] +!message *** Doing 64bit portability warnings +WARNINGS = $(WARNINGS) -Wp64 +!endif +!endif + +!if $(PGO) > 1 +!if [nmakehlp -l -ltcg:pgoptimize] +LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize +!else +MSG=^ +This compiler does not support profile guided optimization. +!error $(MSG) +!endif +!elseif $(PGO) > 0 +!if [nmakehlp -l -ltcg:pginstrument] +LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument +!else +MSG=^ +This compiler does not support profile guided optimization. +!error $(MSG) +!endif +!endif + +#---------------------------------------------------------- +# Set our defines now armed with our options. +#---------------------------------------------------------- + +OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS + +!if $(TCL_MEM_DEBUG) +OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG +!endif +!if $(TCL_COMPILE_DEBUG) +OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS +!endif +!if $(TCL_THREADS) +OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 +!if $(USE_THREAD_ALLOC) +OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 +!endif +!endif +!if $(STATIC_BUILD) +OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD +!endif +!if $(TCL_NO_DEPRECATED) +OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED +!endif + +!if !$(DEBUG) +OPTDEFINES = $(OPTDEFINES) -DNDEBUG +!if $(OPTIMIZING) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED +!endif +!endif +!if $(PROFILE) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED +!endif +!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT +!endif +!if $(VCVERSION) < 1300 +OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64 +!endif + +#---------------------------------------------------------- +# Locate the Tcl headers to build against +#---------------------------------------------------------- + +!if "$(PROJECT)" == "tcl" + +_TCL_H = ..\generic\tcl.h + +!else + +# If INSTALLDIR set to tcl root dir then reset to the lib dir. +!if exist("$(_INSTALLDIR)\include\tcl.h") +_INSTALLDIR=$(_INSTALLDIR)\lib +!endif + +!if !defined(TCLDIR) +!if exist("$(_INSTALLDIR)\..\include\tcl.h") +TCLINSTALL = 1 +_TCLDIR = $(_INSTALLDIR)\.. +_TCL_H = $(_INSTALLDIR)\..\include\tcl.h +TCLDIR = $(_INSTALLDIR)\.. +!else +MSG=^ +Failed to find tcl.h. Set the TCLDIR macro. +!error $(MSG) +!endif +!else +_TCLDIR = $(TCLDIR:/=\) +!if exist("$(_TCLDIR)\include\tcl.h") +TCLINSTALL = 1 +_TCL_H = $(_TCLDIR)\include\tcl.h +!elseif exist("$(_TCLDIR)\generic\tcl.h") +TCLINSTALL = 0 +_TCL_H = $(_TCLDIR)\generic\tcl.h +!else +MSG =^ +Failed to find tcl.h. The TCLDIR macro does not appear correct. +!error $(MSG) +!endif +!endif +!endif + +#-------------------------------------------------------------- +# Extract various version numbers from tcl headers +# The generated file is then included in the makefile. +#-------------------------------------------------------------- + +!if [echo REM = This file is generated from rules.vc > versions.vc] +!endif +!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc] +!endif +!if [echo TCL_MINOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc] +!endif +!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] +!endif + +# If building the tcl core then we need additional package versions +!if "$(PROJECT)" == "tcl" +!if [echo PKG_HTTP_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\http\pkgIndex.tcl http >> versions.vc] +!endif +!if [echo PKG_TCLTEST_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\tcltest\pkgIndex.tcl tcltest >> versions.vc] +!endif +!if [echo PKG_MSGCAT_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\msgcat\pkgIndex.tcl msgcat >> versions.vc] +!endif +!if [echo PKG_PLATFORM_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform " >> versions.vc] +!endif +!if [echo PKG_SHELL_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform::shell" >> versions.vc] +!endif +!if [echo PKG_DDE_VER = \>> versions.vc] \ + && [nmakehlp -V ..\library\dde\pkgIndex.tcl "dde " >> versions.vc] +!endif +!if [echo PKG_REG_VER =\>> versions.vc] \ + && [nmakehlp -V ..\library\reg\pkgIndex.tcl registry >> versions.vc] +!endif +!endif + +!include versions.vc + +#-------------------------------------------------------------- +# Setup tcl version dependent stuff headers +#-------------------------------------------------------------- + +!if "$(PROJECT)" != "tcl" + +TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) + +!if $(TCL_VERSION) < 81 +TCL_DOES_STUBS = 0 +!else +TCL_DOES_STUBS = 1 +!endif + +!if $(TCLINSTALL) +TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe" +!if !exist($(TCLSH)) && $(TCL_THREADS) +TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe" +!endif +TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib" +TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib" +TCL_LIBRARY = $(_TCLDIR)\lib +TCLREGLIB = "$(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib" +TCLDDELIB = "$(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib" +COFFBASE = \must\have\tcl\sources\to\build\this\target +TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target +TCL_INCLUDES = -I"$(_TCLDIR)\include" +!else +TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe" +!if !exist($(TCLSH)) && $(TCL_THREADS) +TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe" +!endif +TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib" +TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib" +TCL_LIBRARY = $(_TCLDIR)\library +TCLREGLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib" +TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib" +COFFBASE = "$(_TCLDIR)\win\coffbase.txt" +TCLTOOLSDIR = $(_TCLDIR)\tools +TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" +!endif + +!endif + +#------------------------------------------------------------------------- +# Locate the Tk headers to build against +#------------------------------------------------------------------------- + +!if "$(PROJECT)" == "tk" +_TK_H = ..\generic\tk.h +_INSTALLDIR = $(_INSTALLDIR)\.. +!endif + +!ifdef PROJECT_REQUIRES_TK +!if !defined(TKDIR) +!if exist("$(_INSTALLDIR)\..\include\tk.h") +TKINSTALL = 1 +_TKDIR = $(_INSTALLDIR)\.. +_TK_H = $(_TKDIR)\include\tk.h +TKDIR = $(_TKDIR) +!elseif exist("$(_TCLDIR)\include\tk.h") +TKINSTALL = 1 +_TKDIR = $(_TCLDIR) +_TK_H = $(_TKDIR)\include\tk.h +TKDIR = $(_TKDIR) +!endif +!else +_TKDIR = $(TKDIR:/=\) +!if exist("$(_TKDIR)\include\tk.h") +TKINSTALL = 1 +_TK_H = $(_TKDIR)\include\tk.h +!elseif exist("$(_TKDIR)\generic\tk.h") +TKINSTALL = 0 +_TK_H = $(_TKDIR)\generic\tk.h +!else +MSG =^ +Failed to find tk.h. The TKDIR macro does not appear correct. +!error $(MSG) +!endif +!endif +!endif + +#------------------------------------------------------------------------- +# Extract Tk version numbers +#------------------------------------------------------------------------- + +!if defined(PROJECT_REQUIRES_TK) || "$(PROJECT)" == "tk" + +!if [echo TK_MAJOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc] +!endif +!if [echo TK_MINOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc] +!endif +!if [echo TK_PATCH_LEVEL = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] +!endif + +!include versions.vc + +TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) +TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) + +!if "$(PROJECT)" != "tk" +!if $(TKINSTALL) +WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)$(SUFX).exe" +TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib" +TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib" +TK_INCLUDES = -I"$(_TKDIR)\include" +!else +WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(SUFX).exe" +TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib" +TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib" +TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" +!endif +!endif + +!endif + +#---------------------------------------------------------- +# Display stats being used. +#---------------------------------------------------------- + +!message *** Intermediate directory will be '$(TMP_DIR)' +!message *** Output directory will be '$(OUT_DIR)' +!message *** Suffix for binaries will be '$(SUFX)' +!message *** Optional defines are '$(OPTDEFINES)' +!message *** Compiler version $(VCVER). Target machine is $(MACHINE) +!message *** Host architecture is $(NATIVE_ARCH) +!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)' +!message *** Link options '$(LINKERFLAGS)' + +!endif + diff --git a/manifest b/manifest index 29a52f2578..233b7d48c5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\swriting\sto\san\sFTS\stable,\stake\san\sexclusive\sshared-cache\slock\son\sthe\s%_segdir\stable\sbefore\swriting.\sOtherwise,\san\sxCommit()\scall\smay\sreport\san\sSQLITE_LOCKED\serror. -D 2013-05-27T10:11:53.308 +C Add\sthe\sfiles\sused\sto\sbuild\sthe\samalgamation-autoconf\spackage. +D 2013-05-27T17:19:58.423 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -12,6 +12,29 @@ F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90 F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2 +F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903 +F autoconf/Makefile.am 8fc2972d92769cf20ab8e4a73ea901b84d69bf44 +F autoconf/README 14458f1046c118efa721aadec5f227e876d3cd38 +F autoconf/README.first 47dd53221023b18c836ab00dba6e00bd86132453 +F autoconf/config.guess 94cc57e2a3fdb9c235b362ace86d77e89d188cad x +F autoconf/config.sub 1efb390a8fb4bfafd74783a15a8fb5311c84300e x +F autoconf/configure.ac ba3e99ba1a8171d0682b68443517088fc5d6f13a +F autoconf/depcomp 0b26f101e3bc9fd1ff0be1da9fb4a82371142f92 x +F autoconf/install-sh 06ee6336e63bb845c8439d777c32eb2eccc4fbf1 x +F autoconf/ltmain.sh 7a658a24028f02331c1d2446562758083c5eadd1 +F autoconf/missing d7c9981a81af13370d4ed152b24c0a82b7028585 x +F autoconf/tea/Makefile.in 5c3b0bdfb66c20d55ebff59d1718864461570ca9 +F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873 +F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43 +F autoconf/tea/configure.in e0466b881b53f31f5a4a69e7a91ad130902fb359 +F autoconf/tea/doc/sqlite3.n e268faa1691c33663d3a7faf9fa30673d14bd879 +F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523 +F autoconf/tea/pkgIndex.tcl.in 3ef61715cf1c7bdcff56947ffadb26bc991ca39d +F autoconf/tea/tclconfig/install-sh b087e5c4b92820c60bffb74acc1d9c2d40d80b8f +F autoconf/tea/tclconfig/tcl.m4 a68179d7cc45524fa59db428a36610e20bdba808 +F autoconf/tea/win/makefile.vc f89d0184d0eee5f7e356ea407964dcd139939928 +F autoconf/tea/win/nmakehlp.c 2070e086f39866b353a482d3a14dedaf26196506 +F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 @@ -1066,7 +1089,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 61a10452399db28cd5ea4ba9d416b87a34c2eddb -R 5b2b7d523083ab3d77d86c0cce4d267d +P 3cd2da42e9403b1e6243ad53f3f2bbf89c0fb9b0 +R 36bfb90ebfbfa2dc4a4f5f2d201ce940 +T *branch * autoconf-package +T *sym-autoconf-package * +T -sym-trunk * U dan -Z 5b590f475035536f2f371b845c79a1e4 +Z b353aa1f8164c124057d033967eb5644 diff --git a/manifest.uuid b/manifest.uuid index cd1334fa37..80a8d1c459 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3cd2da42e9403b1e6243ad53f3f2bbf89c0fb9b0 \ No newline at end of file +048865e8fdd2bef6b43b6cebd45fae94c8a1ab20 \ No newline at end of file From 88da644f2cf2f5991e1875c3c41494e82360e057 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 27 May 2013 17:59:37 +0000 Subject: [PATCH 031/144] Update the NGQP to record which loops need be run in reverse order to satisfy ORDER BY clauses. FossilOrigin-Name: 211f7a5374fe20a02535edc8b799a8a7136ff6b3 --- manifest | 14 ++++----- manifest.uuid | 2 +- src/sqliteInt.h | 1 + src/where.c | 82 +++++++++++++++++++++++-------------------------- 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/manifest b/manifest index 010739cba8..8b6a0ac134 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Record\sin\sthe\sWhereLoop\sobject\sthe\sset\sof\svirtual\stable\sconstraints\sthat\nneed\snot\sbe\sseparately\schecked. -D 2013-05-24T14:52:03.958 +C Update\sthe\sNGQP\sto\srecord\swhich\sloops\sneed\sbe\srun\sin\sreverse\sorder\sto\nsatisfy\sORDER\sBY\sclauses. +D 2013-05-27T17:59:37.917 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -196,7 +196,7 @@ F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 0b0ba16c1449d0e7ef6ff78039ffef38f58f585a +F src/sqliteInt.h 9e12a56e05420b5c7aa40aca4d44ee4d9535b68a F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -265,7 +265,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 2fd11c00ffc37a65b762c8b2bbf5710723eefdd7 +F src/where.c 3f4f25df651e8cea5b02d94aeee28838e9c5e2c3 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1066,7 +1066,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7c8f992c04504a132686ad0652efdff19e43480d -R 91429a505370ccdd08f4d1fe64f3bf63 +P b49fa74561f38c945be6149693678fd6518c2de4 +R dbfb376dc6b826c13c37ea187ec4a9c4 U drh -Z 676fd5c7993f5cc12a1abed75be6a4c4 +Z 716f8aec8e11bc86fa358274cd806e0b diff --git a/manifest.uuid b/manifest.uuid index bec1afe37d..a1b72955fd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b49fa74561f38c945be6149693678fd6518c2de4 \ No newline at end of file +211f7a5374fe20a02535edc8b799a8a7136ff6b3 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c1a4f766c8..79f5d23492 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2051,6 +2051,7 @@ struct WhereInfo { SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pDistinct; /* DISTINCT ON values, or NULL */ + Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ diff --git a/src/where.c b/src/where.c index 6416dd9503..b0b953af30 100644 --- a/src/where.c +++ b/src/where.c @@ -5839,8 +5839,9 @@ static int wherePathSatisfiesOrderBy( WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* Mask of WhereLoops to run in reverse order */ ){ - u8 revSet; - u8 rev; + u8 revSet; /* True if rev is known */ + u8 rev; /* Composite sort order */ + u8 revIdx; /* Index sort order */ u8 isUnique; u8 requireUnique = 0; u16 nColumn; @@ -5890,7 +5891,7 @@ static int wherePathSatisfiesOrderBy( ** column reference */ nOrderBy = pOrderBy->nExpr; for(i=0; ia[nUsed].pExpr); + pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); if( pOBExpr->op!=TK_COLUMN ) return 0; } @@ -5902,7 +5903,7 @@ static int wherePathSatisfiesOrderBy( if( (pLoop->wsFlags & WHERE_COLUMN_IN)!=0 ) isUnique = 0; if( pLoop->u.btree.nEq!=1 ) isUnique = 0; pIndex = 0; - nColumn = 1; + nColumn = 0; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ @@ -5921,31 +5922,31 @@ static int wherePathSatisfiesOrderBy( iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; j = 0; revSet = rev = 0; - for(j=0; ja[nUsed].pExpr); assert( pOBExpr->op==TK_COLUMN ); if( pOBExpr->iTable!=iCur ) break; - if( pIndex==0 ){ - if( pOBExpr->iColumn<0 && j==0 ){ - isUnique = 1; - rev = pOrderBy->a[nUsed].sortOrder; - }else if( isUnique ){ - continue; - }else{ - return 0; - } - } if( isUnique ) continue; - iColumn = pIndex->aiColumn[j]; - if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; - if( pOBExpr->iColumn!=iColumn ) return 0; - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[nUsed].pExpr); - if( !pColl ) pColl = db->pDfltColl; - if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) return 0; - if( revSet ){ - if( pIndex->aSortOrder[j]!=rev ) return 0; + if( jaiColumn[j]; + revIdx = pIndex->aSortOrder[j]; + if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; }else{ - rev = pIndex->aSortOrder[j]; + /* The ROWID column at the end */ + iColumn = -1; + revIdx = 0; + } + if( pOBExpr->iColumn!=iColumn ) return 0; + if( iColumn>=0 ){ + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[nUsed].pExpr); + if( !pColl ) pColl = db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) return 0; + } + if( revSet ){ + if( (rev ^ revIdx)!=pOrderBy->a[nUsed].sortOrder ) return 0; + }else{ + rev = revIdx ^ pOrderBy->a[nUsed].sortOrder; revSet = 1; } } @@ -6000,6 +6001,9 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ db = pWInfo->pParse->db; nLoop = pWInfo->nLevel; assert( nLoop<=pWInfo->pTabList->nSrc ); +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace>=2 ) sqlite3DebugPrintf("---- begin solver\n"); +#endif /* Allocate and initialize space for aTo and aFrom */ ii = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; @@ -6020,28 +6024,14 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ /* Precompute the cost of sorting the final result set, if the caller ** to sqlite3WhereBegin() was concerned about sorting */ rSortCost = (double)0; - if( pWInfo->pOrderBy==0 || nRowEst<0.0 ){ + if( pWInfo->pOrderBy==0 || nRowEst<=0.0 ){ aFrom[0].isOrderedValid = 1; }else{ /* Compute an estimate on the cost to sort the entire result set */ -#if 0 - rSortCost = (double)1; - for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pNext){ - pNext = pWLoop->pNextLoop; - rCost = pWLoop->nOut; - while( pNext && pNext->iTab==pWLoop->iTab ){ - if( pNext->nOutnOut; - pNext = pNext->pNextLoop; - } - rSortCost *= rCost; - } - rSortCost *= estLog(rSortCost); -#else rSortCost = nRowEst*estLog(nRowEst); -#endif #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace>=2 ){ - sqlite3DebugPrintf("--solver sort cost=%-7.2g\n", rSortCost); + sqlite3DebugPrintf("---- sort cost=%-7.2g\n", rSortCost); } #endif } @@ -6162,9 +6152,14 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ if( sqlite3WhereTrace>=2 ){ sqlite3DebugPrintf("---- after round %d ----\n", iLoop); for(ii=0, pTo=aTo; iirCost, pTo->nRow, pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + if( pTo->isOrderedValid && pTo->isOrdered ){ + sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop); + }else{ + sqlite3DebugPrintf("\n"); + } } } #endif @@ -6192,6 +6187,7 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ } if( pFrom->isOrdered ){ pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; + pWInfo->revMask = pFrom->revLoop; } pWInfo->nRowOut = pFrom->nRow; @@ -6468,9 +6464,9 @@ WhereInfo *sqlite3WhereBegin( #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ int ii; - sqlite3DebugPrintf("------------ Solution -------------"); + sqlite3DebugPrintf("---- Solution"); if( pWInfo->nOBSat ){ - sqlite3DebugPrintf(" ORDER BY omitted\n"); + sqlite3DebugPrintf(" ORDER BY omitted rev=0x%llx\n", pWInfo->revMask); }else{ sqlite3DebugPrintf("\n"); } From 555c939dc7d12e806a88a00fe22cca52585e7d2f Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 27 May 2013 18:37:33 +0000 Subject: [PATCH 032/144] Add the "dist" target to main.mk. For building the amalgamation autoconf package. FossilOrigin-Name: 3fdc8b56493350fc4854fb1eaefe29ac87784f91 --- main.mk | 5 +++ manifest | 16 +++++----- manifest.uuid | 2 +- tool/mkautoconfamal.sh | 70 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 tool/mkautoconfamal.sh diff --git a/main.mk b/main.mk index 912ebb4045..ba73edd711 100644 --- a/main.mk +++ b/main.mk @@ -620,6 +620,11 @@ extensiontest: testfixture$(EXE) $(TEST_EXTENSION) checksymbols: sqlite3.o nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0 +# Build the amalgamation-autoconf package. +# +dist: sqlite3.c + TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh + # Standard install and cleanup targets # diff --git a/manifest b/manifest index 233b7d48c5..1107994056 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sfiles\sused\sto\sbuild\sthe\samalgamation-autoconf\spackage. -D 2013-05-27T17:19:58.423 +C Add\sthe\s"dist"\starget\sto\smain.mk.\sFor\sbuilding\sthe\samalgamation\sautoconf\spackage. +D 2013-05-27T18:37:33.110 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -137,7 +137,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d -F main.mk a8ebdf910e2cc10db1f9f54ec316f637458e8001 +F main.mk 2a3cd58acfd1ecc656027afdd60ed1eefb07380f F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -1056,6 +1056,7 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/lemon.c 680980c7935bfa1edec20c804c9e5ba4b1dd96f5 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc +F tool/mkautoconfamal.sh 9ef9ad69bc3021a6fd2dac53a2e8cf5b97e0df05 F tool/mkkeywordhash.c bb52064aa614e1426445e4b2b9b00eeecd23cc79 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -1089,10 +1090,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 3cd2da42e9403b1e6243ad53f3f2bbf89c0fb9b0 -R 36bfb90ebfbfa2dc4a4f5f2d201ce940 -T *branch * autoconf-package -T *sym-autoconf-package * -T -sym-trunk * +P 048865e8fdd2bef6b43b6cebd45fae94c8a1ab20 +R 5f01d70f556992e077a0b0dc7f686941 U dan -Z b353aa1f8164c124057d033967eb5644 +Z a0aa8f1a377f5d4aff1fe20419c0f786 diff --git a/manifest.uuid b/manifest.uuid index 80a8d1c459..1235935ef2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -048865e8fdd2bef6b43b6cebd45fae94c8a1ab20 \ No newline at end of file +3fdc8b56493350fc4854fb1eaefe29ac87784f91 \ No newline at end of file diff --git a/tool/mkautoconfamal.sh b/tool/mkautoconfamal.sh new file mode 100644 index 0000000000..ddc705848d --- /dev/null +++ b/tool/mkautoconfamal.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# This script is used to build the amalgamation autoconf package. +# It assumes the following: +# +# 1. The files "sqlite3.c", "sqlite3.h" and "sqlite3ext.h" +# are available in the current directory. +# +# 2. Variable $TOP is set to the full path of the root directory +# of the SQLite source tree. +# +# 3. There is nothing of value in the ./mkpkg_tmp_dir directory. +# This is important, as the script executes "rm -rf ./mkpkg_tmp_dir". +# + + +# Bail out of the script if any command returns a non-zero exit +# status. Or if the script tries to use an unset variable. These +# may fail for old /bin/sh interpreters. +# +set -e +set -u + +TMPSPACE=./mkpkg_tmp_dir +VERSION=`cat $TOP/VERSION` + +rm -rf $TMPSPACE +cp -R $TOP/autoconf $TMPSPACE + +cp sqlite3.c $TMPSPACE +cp sqlite3.h $TMPSPACE +cp sqlite3ext.h $TMPSPACE +cp $TOP/sqlite3.1 $TMPSPACE +cp $TOP/sqlite3.pc.in $TMPSPACE +cp $TOP/src/shell.c $TMPSPACE + +chmod 755 $TMPSPACE/install-sh +chmod 755 $TMPSPACE/missing +chmod 755 $TMPSPACE/depcomp +chmod 755 $TMPSPACE/config.sub +chmod 755 $TMPSPACE/config.guess + +cat $TMPSPACE/configure.ac | +sed "s/AC_INIT(sqlite, .*, http:\/\/www.sqlite.org)/AC_INIT(sqlite, $VERSION, http:\/\/www.sqlite.org)/" > $TMPSPACE/tmp +mv $TMPSPACE/tmp $TMPSPACE/configure.ac + +cd $TMPSPACE +aclocal +autoconf +automake + +mkdir -p tea/generic +echo "#ifdef USE_SYSTEM_SQLITE" > tea/generic/tclsqlite3.c +echo "# include " >> tea/generic/tclsqlite3.c +echo "#else" >> tea/generic/tclsqlite3.c +echo "#include \"../../sqlite3.c\"" >> tea/generic/tclsqlite3.c +echo "#endif" >> tea/generic/tclsqlite3.c +cat $TOP/src/tclsqlite.c >> tea/generic/tclsqlite3.c + +cat tea/configure.in | + sed "s/AC_INIT(\[sqlite\], .*)/AC_INIT([sqlite], [$VERSION])/" > tmp +mv tmp tea/configure.in + +cd tea +autoconf +rm -rf autom4te.cache + +cd ../ +./configure && make dist +mv sqlite-$VERSION.tar.gz ../sqlite-amalgamation-$VERSION.tar.gz + From f7b5496e8e5516ed8727679af54a26711c8776e5 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 28 May 2013 12:11:54 +0000 Subject: [PATCH 033/144] Many small harmless comment changes. Removal of obsolete comments and fixing misspelled words. No changes to code. FossilOrigin-Name: a0d5cc9315dc6e9ef7dee4c3dfabf4e562d64376 --- ext/icu/icu.c | 2 +- manifest | 50 ++++++++++++++++++++++++------------------------- manifest.uuid | 2 +- src/analyze.c | 2 +- src/btree.c | 4 ++-- src/expr.c | 2 +- src/func.c | 8 ++------ src/main.c | 4 +--- src/pager.c | 2 +- src/parse.y | 2 +- src/pcache1.c | 2 +- src/pragma.c | 2 +- src/printf.c | 6 ------ src/select.c | 6 +++--- src/sqliteInt.h | 2 +- src/test1.c | 4 ++-- src/trigger.c | 2 +- src/vdbe.c | 4 ++-- src/vdbeapi.c | 7 ------- src/vdbeaux.c | 2 +- src/vdbesort.c | 2 +- 21 files changed, 49 insertions(+), 68 deletions(-) diff --git a/ext/icu/icu.c b/ext/icu/icu.c index ae28d70613..74f4ae77c2 100644 --- a/ext/icu/icu.c +++ b/ext/icu/icu.c @@ -22,7 +22,7 @@ ** * Implementations of the SQL scalar upper() and lower() functions ** for case mapping. ** -** * Integration of ICU and SQLite collation seqences. +** * Integration of ICU and SQLite collation sequences. ** ** * An implementation of the LIKE operator that uses ICU to ** provide case-independent matching. diff --git a/manifest b/manifest index c40ccc25bc..2a0f7b44c9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sautoconf-package\sbranch\swith\strunk. -D 2013-05-28T10:52:22.037 +C Many\ssmall\sharmless\scomment\schanges.\s\sRemoval\sof\sobsolete\scomments\sand\nfixing\smisspelled\swords.\s\sNo\schanges\sto\scode. +D 2013-05-28T12:11:54.059 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -104,7 +104,7 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7 F ext/fts3/unicode/mkunicode.tcl 7a9bc018e2962abb79563c5a39fe581fcbf2f675 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 -F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a +F ext/icu/icu.c 7538f98eab2854cf17fa5f7797bffa6c76e3863b F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c eae8454cd9dcb287b2a3ec2e65a865a4ac5f0d06 F ext/misc/closure.c 40788c54c59190a1f52f6492a260d8894a246fe9 @@ -155,13 +155,13 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168 -F src/analyze.c d5f895810e8ff9737c9ec7b76abc3dcff5860335 +F src/analyze.c 27e541b9b5b48b41eb899b22a49ff42384899151 F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c b266767351ae2d847716c56fcb2a1fea7c761c03 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c fcfbe61a311e54224b23527bbf7586ce320e7b40 +F src/btree.c 7fba377c29573adfc6091832e27ee1fcbefb51d0 F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 F src/build.c 92ef9483189389828966153c5950f2e5a49c1182 @@ -170,10 +170,10 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778 -F src/expr.c e40d198a719aba1d2514f6e1541f9154f976ceb6 +F src/expr.c ac9d259eea3123faa05fabe6dd8717696aca72b1 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179 -F src/func.c d3fdcff9274bc161152e67ed3f626841c247f4b9 +F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 @@ -183,7 +183,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2 -F src/main.c c6419ef57392b1aa0cf6ed9c80dfc06b153fe299 +F src/main.c fa68271882d95bd8a7f7d15f55f9da46d74abda5 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa @@ -202,29 +202,29 @@ F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_unix.c 42c9b8b7c61c9fa3561258f523be5749e52ed0e0 F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b -F src/pager.c 3709c5c9e2eb566fffba6348508b7212c4d06ca3 +F src/pager.c 865a09d9ca2eb1c725b192aeac722019c8083e02 F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 -F src/parse.y 9708365594eea519cdc8504dee425c0a41c79502 +F src/parse.y 9acfcc83ddbf0cf82f0ed9582ccf0ad6c366ff37 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 -F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9 -F src/pragma.c 8bf4bfaef7975abff45e55230ed1033b5f208d11 +F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938 +F src/pragma.c 7528202452b5d6d5ba2538531ac86bfacd8e99ef F src/prepare.c 743e484233c51109666d402f470523553b41797c -F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f +F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c a4641882279becc200f2680f55f3e89d4e7c7f78 +F src/select.c 22ee971346a736ddefdc4497d07c92f2e9978afc F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h ba610d80822135ffbc92ac90710939e548c6a850 +F src/sqliteInt.h e8306784f8d637de29c2e298fbe2b7094ba00abf F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c 2ecec9937e69bc17560ad886da35195daa7261b8 -F src/test1.c 045d45a4f7eeb5d963f8fc150339f1bad279011a +F src/test1.c 43c87e52cb504e8c9928b1e9bad21a6117c695e9 F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -270,19 +270,19 @@ F src/test_vfs.c 8e6087a8b3dcc260282074b0efba14b76311120c F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12 -F src/trigger.c cd95ac64efa60e39faf9b5597443192ff27a22fa +F src/trigger.c 5c0ea9b8755e7c5e1a700f3e27ac4f8d92dd221e F src/update.c 4c0c6864c4349ba292042e984a56d15985b57f4e F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 F src/vacuum.c ddf21cc9577c4cb459d08bee9863a78ec000c5bb -F src/vdbe.c 5f0047130f80c7fd0bc41bc51a653b5542c4fbd5 +F src/vdbe.c 34929e1b5bd95a85b5e1b7767b5cc8da582ad78d F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d F src/vdbeInt.h c1e830268b75f04a2901dd895b51a637a26c7045 -F src/vdbeapi.c 085cf9bf169b859a6c8fa43791702bac805cb7aa -F src/vdbeaux.c ecb43014bcd3019e5aa2b5561e5c3a447f007a08 +F src/vdbeapi.c 0b2c78797058c6c9bfa1687977de039566e22877 +F src/vdbeaux.c af9cd9372c7ab82294b9645723e652c2d4213b95 F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69 F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab -F src/vdbesort.c 4fad64071ae120c25f39dcac572d716b9cadeb7f +F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017 F src/vdbetrace.c 18cc59cb475e6115129bfde224367d13a35a7d13 F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d @@ -1090,7 +1090,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 3cd2da42e9403b1e6243ad53f3f2bbf89c0fb9b0 3fdc8b56493350fc4854fb1eaefe29ac87784f91 -R 5f01d70f556992e077a0b0dc7f686941 -U dan -Z 9cf41dafa5dbcb69eb0f753e10b8143c +P a72f50ef76a5f8a3d5a6a758ec88009c12127f06 +R 6ca5e3287bbaf2adf50d2b284dfdb3eb +U drh +Z 573ed86ebe83cec277b9575597398841 diff --git a/manifest.uuid b/manifest.uuid index 97a88a6194..e0b4fedd9a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a72f50ef76a5f8a3d5a6a758ec88009c12127f06 \ No newline at end of file +a0d5cc9315dc6e9ef7dee4c3dfabf4e562d64376 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 9a3e9597db..78bbf28b47 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -25,7 +25,7 @@ ** The sqlite_stat2 table is not created or used unless the SQLite version ** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled ** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated. -** The sqlite_stat2 table is superceded by sqlite_stat3, which is only +** The sqlite_stat2 table is superseded by sqlite_stat3, which is only ** created and used by SQLite versions 3.7.9 and later and with ** SQLITE_ENABLE_STAT3 defined. The fucntionality of sqlite_stat3 ** is a superset of sqlite_stat2. diff --git a/src/btree.c b/src/btree.c index 3ca60583e3..f6e564628f 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1215,7 +1215,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ }else if( gap+2<=top ){ /* Search the freelist looking for a free slot big enough to satisfy ** the request. The allocation is made from the first free slot in - ** the list that is large enough to accomadate it. + ** the list that is large enough to accommodate it. */ int pc, addr; for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){ @@ -3158,7 +3158,7 @@ int sqlite3BtreeIncrVacuum(Btree *p){ /* ** This routine is called prior to sqlite3PagerCommit when a transaction -** is commited for an auto-vacuum database. +** is committed for an auto-vacuum database. ** ** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages ** the database file should be truncated to during the commit process. diff --git a/src/expr.c b/src/expr.c index 660397e078..c1a27ebf84 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1646,7 +1646,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ ** ** If rMayHaveNull is zero, that means that the subquery is being used ** for membership testing only. There is no need to initialize any -** registers to indicate the presense or absence of NULLs on the RHS. +** registers to indicate the presence or absence of NULLs on the RHS. ** ** For a SELECT or EXISTS operator, return the register that holds the ** result. For IN operators or if an error occurs, the return value is 0. diff --git a/src/func.c b/src/func.c index e40fdad55a..49f6c892be 100644 --- a/src/func.c +++ b/src/func.c @@ -228,7 +228,7 @@ static void instrFunc( ** ** If p1 is negative, then we begin abs(p1) from the end of x[]. ** -** If p2 is negative, return the p2 characters preceeding p1. +** If p2 is negative, return the p2 characters preceding p1. */ static void substrFunc( sqlite3_context *context, @@ -887,10 +887,6 @@ static const char hexdigits[] = { }; /* -** EXPERIMENTAL - This is not an official function. The interface may -** change. This function may disappear. Do not write code that depends -** on this function. -** ** Implementation of the QUOTE() function. This function takes a single ** argument. If the argument is numeric, the return value is the same as ** the argument. If the argument is NULL, the return value is the string @@ -1079,7 +1075,7 @@ static void zeroblobFunc( /* ** The replace() function. Three arguments are all strings: call ** them A, B, and C. The result is also a string which is derived -** from A by replacing every occurance of B with C. The match +** from A by replacing every occurrence of B with C. The match ** must be exact. Collating sequences are not used. */ static void replaceFunc( diff --git a/src/main.c b/src/main.c index 39f60421e6..24cfb4b983 100644 --- a/src/main.c +++ b/src/main.c @@ -701,7 +701,7 @@ static int binCollFunc( /* ** Another built-in collating sequence: NOCASE. ** -** This collating sequence is intended to be used for "case independant +** This collating sequence is intended to be used for "case independent ** comparison". SQLite's knowledge of upper and lower case equivalents ** extends only to the 26 characters used in the English language. ** @@ -2791,8 +2791,6 @@ int sqlite3_global_recover(void){ ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on ** by default. Autocommit is disabled by a BEGIN statement and reenabled ** by the next COMMIT or ROLLBACK. -** -******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** */ int sqlite3_get_autocommit(sqlite3 *db){ return db->autoCommit; diff --git a/src/pager.c b/src/pager.c index 443f5fb740..a9b18273eb 100644 --- a/src/pager.c +++ b/src/pager.c @@ -5180,7 +5180,7 @@ static void pagerUnlockIfUnused(Pager *pPager){ ** page is initialized to all zeros. ** ** If noContent is true, it means that we do not care about the contents -** of the page. This occurs in two seperate scenarios: +** of the page. This occurs in two scenarios: ** ** a) When reading a free-list leaf page from the database, and ** diff --git a/src/parse.y b/src/parse.y index 8310b26989..d707ee0a82 100644 --- a/src/parse.y +++ b/src/parse.y @@ -213,7 +213,7 @@ id(A) ::= INDEXED(X). {A = X;} . %wildcard ANY. -// Define operator precedence early so that this is the first occurance +// Define operator precedence early so that this is the first occurrence // of the operator tokens in the grammer. Keeping the operators together // causes them to be assigned integer values that are close together, // which keeps parser tables smaller. diff --git a/src/pcache1.c b/src/pcache1.c index 4147d2eff5..e06f5dae69 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -562,7 +562,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ int sz; /* Bytes of memory required to allocate the new cache */ /* - ** The seperateCache variable is true if each PCache has its own private + ** The separateCache variable is true if each PCache has its own private ** PGroup. In other words, separateCache is true for mode (1) where no ** mutexing is required. ** diff --git a/src/pragma.c b/src/pragma.c index cde5fd1c77..c2d2a28064 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1313,7 +1313,7 @@ void sqlite3Pragma( #endif #ifndef SQLITE_OMIT_INTEGRITY_CHECK - /* Pragma "quick_check" is an experimental reduced version of + /* Pragma "quick_check" is reduced version of ** integrity_check designed to detect most database corruption ** without most of the overhead of a full integrity-check. */ diff --git a/src/printf.c b/src/printf.c index 9f68d204ff..8d37d633b2 100644 --- a/src/printf.c +++ b/src/printf.c @@ -413,13 +413,7 @@ void sqlite3VXPrintf( else prefix = 0; } if( xtype==etGENERIC && precision>0 ) precision--; -#if 0 - /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ - for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); -#else - /* It makes more sense to use 0.5 */ for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){} -#endif if( xtype==etFLOAT ) realvalue += rounder; /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; diff --git a/src/select.c b/src/select.c index f3f1490963..9705c19058 100644 --- a/src/select.c +++ b/src/select.c @@ -109,7 +109,7 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){ } /* -** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the +** Given 1 to 3 identifiers preceding the JOIN keyword, determine the ** type of join. Return an integer constant that expresses that type ** in terms of the following bit values: ** @@ -1523,7 +1523,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ /* ** "LIMIT -1" always shows all rows. There is some - ** contraversy about what the correct behavior should be. + ** controversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ @@ -4046,7 +4046,7 @@ int sqlite3Select( } /* Increment Parse.nHeight by the height of the largest expression - ** tree refered to by this, the parent select. The child select + ** tree referred to by this, the parent select. The child select ** may contain expression trees of at most ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit ** more conservative than necessary, but much easier than enforcing diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d735a145ae..713933c7aa 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -114,7 +114,7 @@ ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never ** threadsafe. 1 means the library is serialized which is the highest -** level of threadsafety. 2 means the libary is multithreaded - multiple +** level of threadsafety. 2 means the library is multithreaded - multiple ** threads can use SQLite as long as no two threads try to use the same ** database connection at the same time. ** diff --git a/src/test1.c b/src/test1.c index a638e480ad..d95274b0d5 100644 --- a/src/test1.c +++ b/src/test1.c @@ -2469,7 +2469,7 @@ static int sqlite_static_bind_nbyte = 0; /* ** Usage: sqlite3_bind VM IDX VALUE FLAGS ** -** Sets the value of the IDX-th occurance of "?" in the original SQL +** Sets the value of the IDX-th occurrence of "?" in the original SQL ** string. VALUE is the new value. If FLAGS=="null" then VALUE is ** ignored and the value is set to NULL. If FLAGS=="static" then ** the value is set to the value of a static variable named @@ -5563,7 +5563,7 @@ static int test_wal_checkpoint( ** ** Otherwise, this command returns a list of three integers. The first integer ** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers -** are the values returned via the output paramaters by wal_checkpoint_v2() - +** are the values returned via the output parameters by wal_checkpoint_v2() - ** the number of frames in the log and the number of frames in the log ** that have been checkpointed. */ diff --git a/src/trigger.c b/src/trigger.c index f1ff766e20..b901d07678 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -1002,7 +1002,7 @@ void sqlite3CodeRowTriggerDirect( /* ** This is called to code the required FOR EACH ROW triggers for an operation ** on table pTab. The operation to code triggers for (INSERT, UPDATE or DELETE) -** is given by the op paramater. The tr_tm parameter determines whether the +** is given by the op parameter. The tr_tm parameter determines whether the ** BEFORE or AFTER triggers are coded. If the operation is an UPDATE, then ** parameter pChanges is passed the list of columns being modified. ** diff --git a/src/vdbe.c b/src/vdbe.c index f343e13d4e..7abc2889df 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2914,8 +2914,8 @@ case OP_AutoCommit: { ** other process can start another write transaction while this transaction is ** underway. Starting a write transaction also creates a rollback journal. A ** write transaction must be started before any changes can be made to the -** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained -** on the file. +** database. If P2 is greater than or equal to 2 then an EXCLUSIVE lock is +** also obtained on the file. ** ** If a write-transaction is started and the Vdbe.usesStmtJournal flag is ** true (this flag is set if the Vdbe may modify more than one row and may diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 7c861e2d47..426b72c5cc 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -813,13 +813,6 @@ int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ return iType; } -/* The following function is experimental and subject to change or -** removal */ -/*int sqlite3_column_numeric_type(sqlite3_stmt *pStmt, int i){ -** return sqlite3_value_numeric_type( columnMem(pStmt,i) ); -**} -*/ - /* ** Convert the N-th element of pStmt->pColName[] into a string using ** xFunc() then return that string. If N is out of range, return 0. diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 2c4269a59e..e32f2db064 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1996,7 +1996,7 @@ static void checkActiveVdbeCnt(sqlite3 *db){ ** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or ** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement ** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the -** statement transaction is commtted. +** statement transaction is committed. ** ** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. ** Otherwise SQLITE_OK. diff --git a/src/vdbesort.c b/src/vdbesort.c index fdfc4a79dd..c8709bdafd 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -54,7 +54,7 @@ typedef struct FileWriter FileWriter; ** other key value. If the keys are equal (only possible with two EOF ** values), it doesn't matter which index is stored. ** -** The (N/4) elements of aTree[] that preceed the final (N/2) described +** The (N/4) elements of aTree[] that precede the final (N/2) described ** above contains the index of the smallest of each block of 4 iterators. ** And so on. So that aTree[1] contains the index of the iterator that ** currently points to the smallest key value. aTree[0] is unused. From 4580d759fba8bbed2adf8c89dd8b11eb50b792fc Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 28 May 2013 17:25:48 +0000 Subject: [PATCH 034/144] Remove the obsolete and unused sqlite3.inTrans field. FossilOrigin-Name: c3381cd4957013d46075996c3b865177c888d2a8 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/main.c | 2 +- src/sqliteInt.h | 1 - 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 2a0f7b44c9..95092b7d62 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Many\ssmall\sharmless\scomment\schanges.\s\sRemoval\sof\sobsolete\scomments\sand\nfixing\smisspelled\swords.\s\sNo\schanges\sto\scode. -D 2013-05-28T12:11:54.059 +C Remove\sthe\sobsolete\sand\sunused\ssqlite3.inTrans\sfield. +D 2013-05-28T17:25:48.228 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -183,7 +183,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2 -F src/main.c fa68271882d95bd8a7f7d15f55f9da46d74abda5 +F src/main.c cc952f324f648966a5252c0d7f14848c027921d9 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa @@ -219,7 +219,7 @@ F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h e8306784f8d637de29c2e298fbe2b7094ba00abf +F src/sqliteInt.h 46fb17f604ce941551fe64c342dbeb4dbed3edaa F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -1090,7 +1090,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P a72f50ef76a5f8a3d5a6a758ec88009c12127f06 -R 6ca5e3287bbaf2adf50d2b284dfdb3eb +P a0d5cc9315dc6e9ef7dee4c3dfabf4e562d64376 +R c49ad2144df2af701b43a13836fb7ffd U drh -Z 573ed86ebe83cec277b9575597398841 +Z a2a3fdfb6c263f907a8472ce368de001 diff --git a/manifest.uuid b/manifest.uuid index e0b4fedd9a..d3fd1176ca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a0d5cc9315dc6e9ef7dee4c3dfabf4e562d64376 \ No newline at end of file +c3381cd4957013d46075996c3b865177c888d2a8 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 24cfb4b983..9fa2defb14 100644 --- a/src/main.c +++ b/src/main.c @@ -1024,7 +1024,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ inTrans = 1; } sqlite3BtreeRollback(p, tripCode); - db->aDb[i].inTrans = 0; +// db->aDb[i].inTrans = 0; } } sqlite3VtabRollback(db); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 713933c7aa..4482ed69a8 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -748,7 +748,6 @@ typedef struct WhereLevel WhereLevel; struct Db { char *zName; /* Name of this database */ Btree *pBt; /* The B*Tree structure for this database file */ - u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ u8 safety_level; /* How aggressive at syncing data to disk */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; From cda73feaa2792e0ce030d972d8a3b9978ff54364 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 28 May 2013 17:30:52 +0000 Subject: [PATCH 035/144] Finish removing the sqlite3.inTrans field. In the previous check-in, it was merely commented out because I failed to select File->Save on my text editor. FossilOrigin-Name: 2f97e38a6611cb17c24d74332d3ac3777dc0dd3e --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/main.c | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 95092b7d62..588d892738 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sobsolete\sand\sunused\ssqlite3.inTrans\sfield. -D 2013-05-28T17:25:48.228 +C Finish\sremoving\sthe\ssqlite3.inTrans\sfield.\s\sIn\sthe\sprevious\scheck-in,\sit\swas\nmerely\scommented\sout\sbecause\sI\sfailed\sto\sselect\sFile->Save\son\smy\stext\seditor. +D 2013-05-28T17:30:52.422 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -183,7 +183,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2 -F src/main.c cc952f324f648966a5252c0d7f14848c027921d9 +F src/main.c f33742ab539602cf18becc6a85ecef164706c86a F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa @@ -1090,7 +1090,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P a0d5cc9315dc6e9ef7dee4c3dfabf4e562d64376 -R c49ad2144df2af701b43a13836fb7ffd +P c3381cd4957013d46075996c3b865177c888d2a8 +R b4b6c4d83a50772ea0d179f36ddb400e U drh -Z a2a3fdfb6c263f907a8472ce368de001 +Z a65b38b6ed5056fa8821564d4893ee8d diff --git a/manifest.uuid b/manifest.uuid index d3fd1176ca..d4c6edd558 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c3381cd4957013d46075996c3b865177c888d2a8 \ No newline at end of file +2f97e38a6611cb17c24d74332d3ac3777dc0dd3e \ No newline at end of file diff --git a/src/main.c b/src/main.c index 9fa2defb14..aa26043629 100644 --- a/src/main.c +++ b/src/main.c @@ -1024,7 +1024,6 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ inTrans = 1; } sqlite3BtreeRollback(p, tripCode); -// db->aDb[i].inTrans = 0; } } sqlite3VtabRollback(db); From def3367e50e58ba359a76f3aaa164b3ca6bbe49a Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 28 May 2013 20:25:54 +0000 Subject: [PATCH 036/144] Add the percentile() SQL function as a loadable extension in the ext/misc directory. FossilOrigin-Name: a64d760d9290b1be78cdda7ae66d4f02c3b3fa53 --- Makefile.in | 1 + Makefile.msc | 1 + ext/misc/percentile.c | 219 ++++++++++++++++++++++++++++++++++++++++++ main.mk | 1 + manifest | 20 ++-- manifest.uuid | 2 +- src/test1.c | 2 + test/percentile.test | 207 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 443 insertions(+), 10 deletions(-) create mode 100644 ext/misc/percentile.c create mode 100644 test/percentile.test diff --git a/Makefile.in b/Makefile.in index 052fd8fa6d..a82f4d2e15 100644 --- a/Makefile.in +++ b/Makefile.in @@ -393,6 +393,7 @@ TESTSRC += \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ + $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/wholenumber.c diff --git a/Makefile.msc b/Makefile.msc index 57d7065b07..206f1680d4 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -713,6 +713,7 @@ TESTEXT = \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\nextchar.c \ + $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\wholenumber.c diff --git a/ext/misc/percentile.c b/ext/misc/percentile.c new file mode 100644 index 0000000000..40ef151f60 --- /dev/null +++ b/ext/misc/percentile.c @@ -0,0 +1,219 @@ +/* +** 2013-05-28 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code to implement the percentile(Y,P) SQL function +** as described below: +** +** (1) The percentile(Y,P) function is an aggregate function taking +** exactly two arguments. +** +** (2) If the P argument to percentile(Y,P) is not the same for every +** row in the aggregate then an error is thrown. The word "same" +** in the previous sentence means that the value differ by less +** than 0.001. +** +** (3) If the P argument to percentile(Y,P) evaluates to anything other +** than a number in the range of 0.0 to 100.0 inclusive then an +** error is thrown. +** +** (4) If any Y argument to percentile(Y,P) evaluates to a value that +** is not NULL and is not numeric then an error is thrown. +** +** (5) If any Y argument to percentile(Y,P) evaluates to plus or minus +** infinity then an error is thrown. (SQLite always interprets NaN +** values as NULL.) +** +** (6) Both Y and P in percentile(Y,P) can be arbitrary expressions, +** including CASE WHEN expressions. +** +** (7) The percentile(Y,P) aggregate is able to handle inputs of at least +** one million (1,000,000) rows. +** +** (8) If there are no non-NULL values for Y, then percentile(Y,P) +** returns NULL. +** +** (9) If there is exactly one non-NULL value for Y, the percentile(Y,P) +** returns the one Y value. +** +** (10) If there N non-NULL values of Y where N is two or more and +** the Y values are ordered from least to greatest and a graph is +** drawn from 0 to N-1 such that the height of the graph at J is +** the J-th Y value and such that straight lines are drawn between +** adjacent Y values, then the percentile(Y,P) function returns +** the height of the graph at P*(N-1)/100. +** +** (11) The percentile(Y,P) function always returns either a floating +** point number or NULL. +** +** (12) The percentile(Y,P) is implemented as a single C99 source-code +** file that compiles into a shared-library or DLL that can be loaded +** into SQLite using the sqlite3_load_extension() interface. +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include +#include +#include + +/* The following object is the session context for a single percentile() +** function. We have to remember all input Y values until the very end. +** Those values are accumulated in the Percentile.a[] array. +*/ +typedef struct Percentile Percentile; +struct Percentile { + unsigned nAlloc; /* Number of slots allocated for a[] */ + unsigned nUsed; /* Number of slots actually used in a[] */ + double rPct; /* 1.0 more than the value for P */ + double *a; /* Array of Y values */ +}; + +/* +** Return TRUE if the input floating-point number is an infinity. +*/ +static int isInfinity(double r){ + sqlite3_uint64 u; + assert( sizeof(u)==sizeof(r) ); + memcpy(&u, &r, sizeof(u)); + return ((u>>52)&0x7ff)==0x7ff; +} + +/* +** Return TRUE if two doubles differ by 0.001 or less +*/ +static int sameValue(double a, double b){ + a -= b; + return a>=-0.001 && a<=0.001; +} + +/* +** The "step" function for percentile(Y,P) is called once for each +** input row. +*/ +static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){ + Percentile *p; + double rPct; + int eType; + double y; + assert( argc==2 ); + + /* Requirement 3: P must be a number between 0 and 100 */ + eType = sqlite3_value_numeric_type(argv[1]); + rPct = sqlite3_value_double(argv[1]); + if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT) || + ((rPct = sqlite3_value_double(argv[1]))<0.0 || rPct>100.0) ){ + sqlite3_result_error(pCtx, "2nd argument to percentile() is not " + "a number between 0.0 and 100.0", -1); + return; + } + + /* Allocate the session context. */ + p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p==0 ) return; + + /* Remember the P value. Throw an error if the P value is different + ** from any prior row, per Requirement (2). */ + if( p->rPct==0.0 ){ + p->rPct = rPct+1.0; + }else if( !sameValue(p->rPct,rPct+1.0) ){ + sqlite3_result_error(pCtx, "2nd argument to percentile() is not the " + "same for all input rows", -1); + return; + } + + /* Ignore rows for which Y is NULL */ + eType = sqlite3_value_type(argv[0]); + if( eType==SQLITE_NULL ) return; + + /* If not NULL, then Y must be numeric. Otherwise throw an error. + ** Requirement 4 */ + if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){ + sqlite3_result_error(pCtx, "1st argument to percentile() is not " + "numeric", -1); + return; + } + + /* Throw an error if the Y value is infinity or NaN */ + y = sqlite3_value_double(argv[0]); + if( isInfinity(y) ){ + sqlite3_result_error(pCtx, "Inf input to percentile()", -1); + return; + } + + /* Allocate and store the Y */ + if( p->nUsed>=p->nAlloc ){ + unsigned n = p->nAlloc*2 + 250; + double *a = sqlite3_realloc(p->a, sizeof(double)*n); + if( a==0 ){ + sqlite3_free(p->a); + memset(p, 0, sizeof(*p)); + sqlite3_result_error_nomem(pCtx); + return; + } + p->nAlloc = n; + p->a = a; + } + p->a[p->nUsed++] = y; +} + +/* +** Compare to doubles for sorting using qsort() +*/ +static int doubleCmp(const void *pA, const void *pB){ + double a = *(double*)pA; + double b = *(double*)pB; + if( a==b ) return 0; + if( aa==0 ) return; + if( p->nUsed ){ + qsort(p->a, p->nUsed, sizeof(double), doubleCmp); + ix = (p->rPct-1.0)*(p->nUsed-1)*0.01; + i1 = ix; + i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1; + v1 = p->a[i1]; + v2 = p->a[i2]; + vx = v1 + (v2-v1)*(ix-i1); + sqlite3_result_double(pCtx, vx); + } + sqlite3_free(p->a); + memset(p, 0, sizeof(*p)); +} + + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_percentile_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0, + 0, percentStep, percentFinal); + return rc; +} diff --git a/main.mk b/main.mk index ba73edd711..845df4beaa 100644 --- a/main.mk +++ b/main.mk @@ -275,6 +275,7 @@ TESTSRC += \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ + $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/wholenumber.c diff --git a/manifest b/manifest index 588d892738..6cd3474131 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Finish\sremoving\sthe\ssqlite3.inTrans\sfield.\s\sIn\sthe\sprevious\scheck-in,\sit\swas\nmerely\scommented\sout\sbecause\sI\sfailed\sto\sselect\sFile->Save\son\smy\stext\seditor. -D 2013-05-28T17:30:52.422 +C Add\sthe\spercentile()\sSQL\sfunction\sas\sa\sloadable\s\nextension\sin\sthe\sext/misc\sdirectory. +D 2013-05-28T20:25:54.766 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in f6b58b7bdf6535f0f0620c486dd59aa4662c0b4f +F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 5dc042f51187414d5886ac6d8308630d484690c4 +F Makefile.msc 7d226394826f060f232c0a02a468e8651819b7c2 F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 F VERSION 05c7bd63b96f31cfdef5c766ed91307ac121f5aa @@ -111,6 +111,7 @@ F ext/misc/closure.c 40788c54c59190a1f52f6492a260d8894a246fe9 F ext/misc/fuzzer.c 51bd96960b6b077d41d6f3cedefbcb57f29efaa2 F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556 F ext/misc/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e +F ext/misc/percentile.c 4fb5e46c4312b0be74e8e497ac18f805f0e3e6c5 F ext/misc/regexp.c c25c65fe775f5d9801fb8573e36ebe73f2c0c2e0 F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a F ext/misc/spellfix.c 6d7ce6105a4b7729f6c44ccdf1ab7e80d9707c02 @@ -137,7 +138,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d -F main.mk 2a3cd58acfd1ecc656027afdd60ed1eefb07380f +F main.mk e536751ac719806209c51f5dc63022a5dd40c631 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -224,7 +225,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c 2ecec9937e69bc17560ad886da35195daa7261b8 -F src/test1.c 43c87e52cb504e8c9928b1e9bad21a6117c695e9 +F src/test1.c 6d2a340eea1d866bf7059894491652a69a7ee802 F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -703,6 +704,7 @@ F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6 F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 +F test/percentile.test 4614301e38398df7fdd5f28f4ed8f272b328251b F test/permutations.test d997a947ab8aabb15f763d50a030b3c11e8ef1b6 F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 @@ -1090,7 +1092,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P c3381cd4957013d46075996c3b865177c888d2a8 -R b4b6c4d83a50772ea0d179f36ddb400e +P 2f97e38a6611cb17c24d74332d3ac3777dc0dd3e +R 339888db3396051923023dfe123ab06e U drh -Z a65b38b6ed5056fa8821564d4893ee8d +Z 1117fca47d6619d98ed20043a3bd4774 diff --git a/manifest.uuid b/manifest.uuid index d4c6edd558..c471926f30 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f97e38a6611cb17c24d74332d3ac3777dc0dd3e \ No newline at end of file +a64d760d9290b1be78cdda7ae66d4f02c3b3fa53 \ No newline at end of file diff --git a/src/test1.c b/src/test1.c index d95274b0d5..bd6d4a4cfd 100644 --- a/src/test1.c +++ b/src/test1.c @@ -6012,6 +6012,7 @@ static int tclLoadStaticExtensionCmd( extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); + extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); @@ -6024,6 +6025,7 @@ static int tclLoadStaticExtensionCmd( { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, + { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, { "spellfix", sqlite3_spellfix_init }, { "wholenumber", sqlite3_wholenumber_init }, diff --git a/test/percentile.test b/test/percentile.test new file mode 100644 index 0000000000..29947b9dee --- /dev/null +++ b/test/percentile.test @@ -0,0 +1,207 @@ +# 2013-05-28 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is percentile.c extension +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Basic test of the percentile() function. +# +do_test percentile-1.0 { + load_static_extension db percentile + execsql { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1),(4),(6),(7),(8),(9),(11),(11),(11); + } + execsql {SELECT percentile(x,0) FROM t1} +} {1.0} +foreach {in out} { + 100 11.0 + 50 8.0 + 12.5 4.0 + 15 4.4 + 20 5.2 + 80 11.0 + 89 11.0 +} { + do_test percentile-1.1.$in { + execsql {SELECT percentile(x,$in) FROM t1} + } $out +} + +# Add some NULL values. +# +do_test percentile-1.2 { + execsql {INSERT INTO t1 VALUES(NULL),(NULL);} +} {} +foreach {in out} { + 100 11.0 + 50 8.0 + 12.5 4.0 + 15 4.4 + 20 5.2 + 80 11.0 + 89 11.0 +} { + do_test percentile-1.3.$in { + execsql {SELECT percentile(x,$in) FROM t1} + } $out +} + +# The second argument to percentile can change some, but not much. +# +do_test percentile-1.4 { + catchsql {SELECT round(percentile(x, 15+0.000001*rowid),1) FROM t1} +} {0 4.4} +do_test percentile-1.5 { + catchsql {SELECT round(percentile(x, 15+0.1*rowid),1) FROM t1} +} {1 {2nd argument to percentile() is not the same for all input rows}} + +# Input values in a random order +# +do_test percentile-1.6 { + execsql { + CREATE TABLE t2(x); + INSERT INTO t2 SELECT x+0.0 FROM t1 ORDER BY random(); + } +} {} +foreach {in out} { + 100 11.0 + 50 8.0 + 12.5 4.0 + 15 4.4 + 20 5.2 + 80 11.0 + 89 11.0 +} { + do_test percentile-1.7.$in { + execsql {SELECT percentile(x,$in) FROM t2} + } $out +} + +# Wrong number of arguments +# +do_test percentile-1.8 { + catchsql {SELECT percentile(x,0,1) FROM t1} +} {1 {wrong number of arguments to function percentile()}} +do_test percentile-1.9 { + catchsql {SELECT percentile(x) FROM t1} +} {1 {wrong number of arguments to function percentile()}} + +# Second argument must be numeric +# +do_test percentile-1.10 { + catchsql {SELECT percentile(x,null) FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} +do_test percentile-1.11 { + catchsql {SELECT percentile(x,'fifty') FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} +do_test percentile-1.12 { + catchsql {SELECT percentile(x,x'3530') FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} + +# Second argument is out of range +# +do_test percentile-1.13 { + catchsql {SELECT percentile(x,-0.0000001) FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} +do_test percentile-1.14 { + catchsql {SELECT percentile(x,100.0000001) FROM t1} +} {1 {2nd argument to percentile() is not a number between 0.0 and 100.0}} + +# First argument is not NULL and is not NUMERIC +# +do_test percentile-1.15 { + catchsql { + BEGIN; + UPDATE t1 SET x='50' WHERE x IS NULL; + SELECT percentile(x, 50) FROM t1; + } +} {1 {1st argument to percentile() is not numeric}} +do_test percentile-1.16 { + catchsql { + ROLLBACK; + BEGIN; + UPDATE t1 SET x=x'3530' WHERE x IS NULL; + SELECT percentile(x, 50) FROM t1; + } +} {1 {1st argument to percentile() is not numeric}} +do_test percentile-1.17 { + catchsql { + ROLLBACK; + SELECT percentile(x, 50) FROM t1; + } +} {0 8.0} + +# No non-NULL entries. +# +do_test percentile-1.18 { + execsql { + UPDATE t1 SET x=NULL; + SELECT ifnull(percentile(x, 50),'NULL') FROM t1 + } +} {NULL} + +# Exactly one non-NULL entry +# +do_test percentile-1.19 { + execsql { + UPDATE t1 SET x=12345 WHERE rowid=5; + SELECT percentile(x, 0), percentile(x, 50), percentile(x,100) FROM t1 + } +} {12345.0 12345.0 12345.0} + +# Infinity as an input +# +do_test percentile-1.20 { + catchsql { + DELETE FROM t1; + INSERT INTO t1 SELECT x+0.0 FROM t2; + UPDATE t1 SET x=1.0e300*1.0e300 WHERE rowid=5; + SELECT percentile(x,50) from t1; + } +} {1 {Inf input to percentile()}} +do_test percentile-1.21 { + catchsql { + UPDATE t1 SET x=-1.0e300*1.0e300 WHERE rowid=5; + SELECT percentile(x,50) from t1; + } +} {1 {Inf input to percentile()}} + +# Million-row Inputs +# +do_test percentile-2.0 { + load_static_extension db wholenumber + execsql { + CREATE VIRTUAL TABLE nums USING wholenumber; + CREATE TABLE t3(x); + INSERT INTO t3 SELECT value-1 FROM nums WHERE value BETWEEN 1 AND 500000; + INSERT INTO t3 SELECT value*10 FROM nums + WHERE value BETWEEN 500000 AND 999999; + SELECT count(*) FROM t3; + } +} {1000000} +foreach {in out} { + 0 0.0 + 100 9999990.0 + 50 2749999.5 + 10 99999.9 +} { + do_test percentile-2.1.$in { + execsql { + SELECT percentile(x, $in) from t3; + } + } $out +} + +finish_test From ba4f01edb39ce20634dc909678d77eb41362019e Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 29 May 2013 14:22:19 +0000 Subject: [PATCH 037/144] Add tests for running FTS 'merge' and 'optimize' commands in shared cache mode. FossilOrigin-Name: 09e5a7ad85dc592fce868a2d0f8719c6915ccb47 --- manifest | 13 +++++----- manifest.uuid | 2 +- test/fts4merge4.test | 58 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 test/fts4merge4.test diff --git a/manifest b/manifest index 6cd3474131..41b7348ead 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\spercentile()\sSQL\sfunction\sas\sa\sloadable\s\nextension\sin\sthe\sext/misc\sdirectory. -D 2013-05-28T20:25:54.766 +C Add\stests\sfor\srunning\sFTS\s'merge'\sand\s'optimize'\scommands\sin\sshared\scache\smode. +D 2013-05-29T14:22:19.357 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -549,6 +549,7 @@ F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 +F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584 F test/fts4unicode.test 25ccad45896f8e50f6a694cff738a35f798cdb40 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/func.test b0fc34fdc36897769651975a2b0a606312753643 @@ -1092,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 2f97e38a6611cb17c24d74332d3ac3777dc0dd3e -R 339888db3396051923023dfe123ab06e -U drh -Z 1117fca47d6619d98ed20043a3bd4774 +P a64d760d9290b1be78cdda7ae66d4f02c3b3fa53 +R 397c6acb8d54cefb71664fb2c7388de6 +U dan +Z 3291738ca16dd9e62c0c52ca9c9e0ddb diff --git a/manifest.uuid b/manifest.uuid index c471926f30..3a46c9e9d2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a64d760d9290b1be78cdda7ae66d4f02c3b3fa53 \ No newline at end of file +09e5a7ad85dc592fce868a2d0f8719c6915ccb47 \ No newline at end of file diff --git a/test/fts4merge4.test b/test/fts4merge4.test new file mode 100644 index 0000000000..8e2119de2b --- /dev/null +++ b/test/fts4merge4.test @@ -0,0 +1,58 @@ +# 2013 May 29 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/fts3_common.tcl +set ::testprefix fts4merge4 + +ifcapable !fts3 { + finish_test + return +} + +set ::enable_shared_cache [sqlite3_enable_shared_cache 1] + +do_execsql_test 1.1 { CREATE VIRTUAL TABLE t1 USING fts4 } + +do_test 1.2 { + for {set i 0} {$i < 2000} {incr i} { + execsql {INSERT INTO t1 VALUES('a b c d e f g h i j k l');} + } +} {} + +do_test 1.3 { + execsql BEGIN + for {set i 0} {$i < 2000} {incr i} { + execsql {INSERT INTO t1 VALUES('a b c d e f g h i j k l');} + } + execsql { + INSERT INTO t1(t1) VALUES('merge=8,50'); + COMMIT + } +} {} + +reset_db +do_execsql_test 2.0 { CREATE VIRTUAL TABLE t1 USING fts4 } +do_test 2.1 { + for {set i 0} {$i < 2000} {incr i} { + execsql {INSERT INTO t1 VALUES('a b c d e f g h i j k l');} + } +} {} +do_execsql_test 2.2 { SELECT count(*) FROM t1_segdir; } 35 +do_execsql_test 2.3 { INSERT INTO t1(t1) VALUES('optimize') } {} +do_execsql_test 2.4 { SELECT count(*) FROM t1_segdir; } 1 + + +sqlite3_enable_shared_cache $::enable_shared_cache +finish_test From ee0231ef525bfd25f5f3e237a3f6a3786e56796e Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 May 2013 17:48:28 +0000 Subject: [PATCH 038/144] Updates to the Codec interface to support codecs on attached databases and to allow rekeying in the middle of a transaction. These changes are only applicable if SQLite is compiled with SQLITE_HAS_CODEC. FossilOrigin-Name: d5b084e9d8cfe9c0c339aca076d472bb50aa764c --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/pager.c | 37 +++++++++++++++++++++---------------- src/pragma.c | 8 ++++---- src/sqlite.h.in | 10 ++++++++++ 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index 41b7348ead..ad8661af94 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stests\sfor\srunning\sFTS\s'merge'\sand\s'optimize'\scommands\sin\sshared\scache\smode. -D 2013-05-29T14:22:19.357 +C Updates\sto\sthe\sCodec\sinterface\sto\ssupport\scodecs\son\sattached\sdatabases\sand\nto\sallow\srekeying\sin\sthe\smiddle\sof\sa\stransaction.\s\sThese\schanges\sare\sonly\s\napplicable\sif\sSQLite\sis\scompiled\swith\sSQLITE_HAS_CODEC. +D 2013-05-29T17:48:28.829 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -203,13 +203,13 @@ F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_unix.c 42c9b8b7c61c9fa3561258f523be5749e52ed0e0 F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b -F src/pager.c 865a09d9ca2eb1c725b192aeac722019c8083e02 +F src/pager.c 79df56da9dd49aceaa4cac207484a9a82cba40ae F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 F src/parse.y 9acfcc83ddbf0cf82f0ed9582ccf0ad6c366ff37 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938 -F src/pragma.c 7528202452b5d6d5ba2538531ac86bfacd8e99ef +F src/pragma.c 67a611bd4be0754f27ee13eb87932c3b14415862 F src/prepare.c 743e484233c51109666d402f470523553b41797c F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -217,7 +217,7 @@ F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 22ee971346a736ddefdc4497d07c92f2e9978afc F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 -F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 +F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 F src/sqliteInt.h 46fb17f604ce941551fe64c342dbeb4dbed3edaa @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P a64d760d9290b1be78cdda7ae66d4f02c3b3fa53 -R 397c6acb8d54cefb71664fb2c7388de6 -U dan -Z 3291738ca16dd9e62c0c52ca9c9e0ddb +P 09e5a7ad85dc592fce868a2d0f8719c6915ccb47 +R 20090ed5100bc7738631061b2f74235f +U drh +Z caf68d1d5a539a495dd90cbaf5a54682 diff --git a/manifest.uuid b/manifest.uuid index 3a46c9e9d2..e0da117f05 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -09e5a7ad85dc592fce868a2d0f8719c6915ccb47 \ No newline at end of file +d5b084e9d8cfe9c0c339aca076d472bb50aa764c \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index a9b18273eb..645cc3d9a0 100644 --- a/src/pager.c +++ b/src/pager.c @@ -6590,7 +6590,27 @@ void sqlite3PagerSetCodec( void *sqlite3PagerGetCodec(Pager *pPager){ return pPager->pCodec; } -#endif + +/* +** This function is called by the wal module when writing page content +** into the log file. +** +** This function returns a pointer to a buffer containing the encrypted +** page content. If a malloc fails, this function may return NULL. +*/ +void *sqlite3PagerCodec(PgHdr *pPg){ + void *aData = 0; + CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); + return aData; +} + +/* +** Return the current pager state +*/ +int sqlite3PagerState(Pager *pPager){ + return pPager->eState; +} +#endif /* SQLITE_HAS_CODEC */ #ifndef SQLITE_OMIT_AUTOVACUUM /* @@ -7145,19 +7165,4 @@ int sqlite3PagerWalFramesize(Pager *pPager){ } #endif -#ifdef SQLITE_HAS_CODEC -/* -** This function is called by the wal module when writing page content -** into the log file. -** -** This function returns a pointer to a buffer containing the encrypted -** page content. If a malloc fails, this function may return NULL. -*/ -void *sqlite3PagerCodec(PgHdr *pPg){ - void *aData = 0; - CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); - return aData; -} -#endif /* SQLITE_HAS_CODEC */ - #endif /* SQLITE_OMIT_DISKIO */ diff --git a/src/pragma.c b/src/pragma.c index c2d2a28064..5803f6c4a5 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1771,10 +1771,10 @@ void sqlite3Pragma( #ifdef SQLITE_HAS_CODEC if( sqlite3StrICmp(zLeft, "key")==0 && zRight ){ - sqlite3_key(db, zRight, sqlite3Strlen30(zRight)); + sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); }else if( sqlite3StrICmp(zLeft, "rekey")==0 && zRight ){ - sqlite3_rekey(db, zRight, sqlite3Strlen30(zRight)); + sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); }else if( zRight && (sqlite3StrICmp(zLeft, "hexkey")==0 || sqlite3StrICmp(zLeft, "hexrekey")==0) ){ @@ -1786,9 +1786,9 @@ void sqlite3Pragma( zKey[i/2] = (h2 & 0x0f) | ((h1 & 0xf)<<4); } if( (zLeft[3] & 0xf)==0xb ){ - sqlite3_key(db, zKey, i/2); + sqlite3_key_v2(db, zDb, zKey, i/2); }else{ - sqlite3_rekey(db, zKey, i/2); + sqlite3_rekey_v2(db, zDb, zKey, i/2); } }else #endif diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 6608823175..0d23f38944 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4513,6 +4513,11 @@ int sqlite3_key( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The key */ ); +int sqlite3_key_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The key */ +); /* ** Change the key on an open database. If the current database is not @@ -4526,6 +4531,11 @@ int sqlite3_rekey( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The new key */ ); +int sqlite3_rekey_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The new key */ +); /* ** Specify the activation key for a SEE database. Unless From 7ba39a921a326294e679c755aab2172a700e695b Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 May 2013 17:43:19 +0000 Subject: [PATCH 039/144] Cut over the NGQP query planner. Remove lots of legacy code. This check-in compiles but does not work. The test suite gets incorrect answers and crashes. FossilOrigin-Name: 001539df4b74dc1cbceb010a91407003ab4d8735 --- manifest | 14 +- manifest.uuid | 2 +- src/sqliteInt.h | 12 +- src/where.c | 1847 ++++------------------------------------------- 4 files changed, 135 insertions(+), 1740 deletions(-) diff --git a/manifest b/manifest index 39a8c39490..7344d1b38d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\srecent\strunk\schanges\sinto\sthe\sNGQP\sbranch. -D 2013-05-30T11:48:36.654 +C Cut\sover\sthe\sNGQP\squery\splanner.\s\sRemove\slots\sof\slegacy\scode.\s\s\nThis\scheck-in\scompiles\sbut\sdoes\snot\swork.\s\sThe\stest\ssuite\sgets\sincorrect\nanswers\sand\scrashes. +D 2013-05-30T17:43:19.293 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,7 @@ F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 55f43f10f165c8c17334e33a11b2d58a557b4a2c +F src/sqliteInt.h c386fb7c61c03a0a65d78e326016449767be5b93 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 3f4f25df651e8cea5b02d94aeee28838e9c5e2c3 +F src/where.c 296baae1cbfd99527d8c87f9773a6c98116f6b8a F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 211f7a5374fe20a02535edc8b799a8a7136ff6b3 d5b084e9d8cfe9c0c339aca076d472bb50aa764c -R 6c4c190a12a33f58ef606f4f8676d338 +P aebe1f2603ee04d792af73aaf59625bda99d5cd1 +R cdb9a6b0104d69931bfa04869e682c85 U drh -Z e692c34c627e293c83ac7dc20bf238bc +Z 36d07876c5b50e19bee990a15e1431a7 diff --git a/manifest.uuid b/manifest.uuid index eeb2053b55..ea56fcb1ab 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aebe1f2603ee04d792af73aaf59625bda99d5cd1 \ No newline at end of file +001539df4b74dc1cbceb010a91407003ab4d8735 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 45a587780b..a0e7bba7d6 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1989,7 +1989,6 @@ struct WherePlan { ** after FROM clause ordering. */ struct WhereLevel { - WherePlan plan; /* query plan for this element of the FROM clause */ int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ int iTabCur; /* The VDBE cursor used to access the table */ int iIdxCur; /* The VDBE cursor used to access pIdx */ @@ -1997,7 +1996,7 @@ struct WhereLevel { int addrNxt; /* Jump here to start the next IN combination */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ - u8 iFrom; /* Which entry in the FROM clause */ + u8 iFrom; /* FIXME: Which entry in the FROM clause */ u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to ends the loop */ union { /* Information that depends on plan.wsFlags */ @@ -2011,16 +2010,7 @@ struct WhereLevel { } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; - double rOptCost; /* "Optimal" cost for this level */ struct WhereLoop *pWLoop; /* The selected WhereLoop object */ - - /* The following field is really not part of the current level. But - ** we need a place to cache virtual table index information for each - ** virtual table in the FROM clause and the WhereLevel structure is - ** a convenient place since there is one WhereLevel for each FROM clause - ** element. - */ - sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */ }; /* diff --git a/src/where.c b/src/where.c index b0b953af30..a9a431ba9a 100644 --- a/src/where.c +++ b/src/where.c @@ -60,7 +60,7 @@ struct WhereLoop { #ifdef SQLITE_DEBUG char cId; /* Symbolic ID of this loop for debugging use */ #endif - u8 iTab; /* Position in FROM clause of table coded by this loop */ + u8 iTab; /* Position in FROM clause of table for this loop */ u8 iSortIdx; /* Sorting index number. 0==None */ u16 nTerm; /* Number of entries in aTerm[] */ u32 wsFlags; /* WHERE_* flags describing the plan */ @@ -190,7 +190,7 @@ struct WhereScan { WhereTerm *pCurrent; /* Most recent match */ WhereClause *pOrigWC; /* Original, innermost WhereClause */ WhereClause *pWC; /* WhereClause currently being scanned */ - char *zCollName; /* Must have this collating sequence, if not NULL */ + char *zCollName; /* Required collating sequence, if not NULL */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ unsigned char nEquiv; /* Number of entries in aEquiv[] */ unsigned char iEquiv; /* Next unused slot in aEquiv[] */ @@ -376,17 +376,6 @@ struct WhereBestIdx { WhereCost cost; /* Lowest cost query plan */ }; -/* -** Return TRUE if the probe cost is less than the baseline cost -*/ -static int compareCost(const WhereCost *pProbe, const WhereCost *pBaseline){ - if( pProbe->rCostrCost ) return 1; - if( pProbe->rCost>pBaseline->rCost ) return 0; - if( pProbe->plan.nOBSat>pBaseline->plan.nOBSat ) return 1; - if( pProbe->plan.nRowplan.nRow ) return 1; - return 0; -} - /* ** Initialize a preallocated WhereClause structure. */ @@ -1691,66 +1680,6 @@ static int findIndexCol( return -1; } -/* -** This routine determines if pIdx can be used to assist in processing a -** DISTINCT qualifier. In other words, it tests whether or not using this -** index for the outer loop guarantees that rows with equal values for -** all expressions in the pDistinct list are delivered grouped together. -** -** For example, the query -** -** SELECT DISTINCT a, b, c FROM tbl WHERE a = ? -** -** can benefit from any index on columns "b" and "c". -*/ -static int isDistinctIndex( - Parse *pParse, /* Parsing context */ - WhereClause *pWC, /* The WHERE clause */ - Index *pIdx, /* The index being considered */ - int base, /* Cursor number for the table pIdx is on */ - ExprList *pDistinct, /* The DISTINCT expressions */ - int nEqCol /* Number of index columns with == */ -){ - Bitmask mask = 0; /* Mask of unaccounted for pDistinct exprs */ - int i; /* Iterator variable */ - - assert( pDistinct!=0 ); - if( pIdx->zName==0 || pDistinct->nExpr>=BMS ) return 0; - testcase( pDistinct->nExpr==BMS-1 ); - - /* Loop through all the expressions in the distinct list. If any of them - ** are not simple column references, return early. Otherwise, test if the - ** WHERE clause contains a "col=X" clause. If it does, the expression - ** can be ignored. If it does not, and the column does not belong to the - ** same table as index pIdx, return early. Finally, if there is no - ** matching "col=X" expression and the column is on the same table as pIdx, - ** set the corresponding bit in variable mask. - */ - for(i=0; inExpr; i++){ - WhereTerm *pTerm; - Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr); - if( p->op!=TK_COLUMN ) return 0; - pTerm = findTerm(pWC, p->iTable, p->iColumn, ~(Bitmask)0, WO_EQ, 0); - if( pTerm ){ - Expr *pX = pTerm->pExpr; - CollSeq *p1 = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); - CollSeq *p2 = sqlite3ExprCollSeq(pParse, p); - if( p1==p2 ) continue; - } - if( p->iTable!=base ) return 0; - mask |= (((Bitmask)1) << i); - } - - for(i=nEqCol; mask && inColumn; i++){ - int iExpr = findIndexCol(pParse, pDistinct, base, pIdx, i); - if( iExpr<0 ) break; - mask &= ~(((Bitmask)1) << iExpr); - } - - return (mask==0); -} - - /* ** Return true if the DISTINCT expression-list passed as the third argument ** is redundant. A DISTINCT list is redundant if the database contains a @@ -1878,106 +1807,6 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){ #define TRACE_IDX_OUTPUTS(A) #endif -/* -** Required because bestIndex() is called by bestOrClauseIndex() -*/ -static void bestIndex(WhereBestIdx*); - -/* -** This routine attempts to find an scanning strategy that can be used -** to optimize an 'OR' expression that is part of a WHERE clause. -** -** The table associated with FROM clause term pSrc may be either a -** regular B-Tree table or a virtual table. -*/ -static void bestOrClauseIndex(WhereBestIdx *p){ -#ifndef SQLITE_OMIT_OR_OPTIMIZATION - WhereClause *pWC = p->pWC; /* The WHERE clause */ - struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ - const int iCur = pSrc->iCursor; /* The cursor of the table */ - const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur); /* Bitmask for pSrc */ - WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */ - WhereTerm *pTerm; /* A single term of the WHERE clause */ - - /* The OR-clause optimization is disallowed if the INDEXED BY or - ** NOT INDEXED clauses are used or if the WHERE_AND_ONLY bit is set. */ - if( pSrc->notIndexed || pSrc->pIndex!=0 ){ - return; - } - if( pWC->wctrlFlags & WHERE_AND_ONLY ){ - return; - } - - /* Search the WHERE clause terms for a usable WO_OR term. */ - for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 - && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0 - && (pTerm->u.pOrInfo->indexable & maskSrc)!=0 - ){ - WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; - WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; - WhereTerm *pOrTerm; - double rTotal = 0; - double nRow = 0; - Bitmask used = 0; - WhereBestIdx sBOI; - - sBOI = *p; - sBOI.pOrderBy = 0; - sBOI.pDistinct = 0; - sBOI.ppIdxInfo = 0; - for(pOrTerm=pOrWC->a; pOrTerma), (pTerm - pWC->a) - ));*/ - if( (pOrTerm->eOperator& WO_AND)!=0 ){ - sBOI.pWC = &pOrTerm->u.pAndInfo->wc; - bestIndex(&sBOI); - }else if( pOrTerm->leftCursor==iCur ){ - WhereClause tempWC; - tempWC.pParse = pWC->pParse; - tempWC.pMaskSet = pWC->pMaskSet; - tempWC.pOuter = pWC; - tempWC.op = TK_AND; - tempWC.a = pOrTerm; - tempWC.wctrlFlags = 0; - tempWC.nTerm = 1; - sBOI.pWC = &tempWC; - bestIndex(&sBOI); - }else{ - continue; - } - rTotal += sBOI.cost.rCost; - nRow += sBOI.cost.plan.nRow; - used |= sBOI.cost.used; - if( rTotal>=p->cost.rCost ) break; - } - - /* If there is an ORDER BY clause, increase the scan cost to account - ** for the cost of the sort. */ - if( p->pOrderBy!=0 ){ - /*WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n", - rTotal, rTotal+nRow*estLog(nRow)));*/ - rTotal += nRow*estLog(nRow); - } - - /* If the cost of scanning using this OR term for optimization is - ** less than the current cost stored in pCost, replace the contents - ** of pCost. */ - /*WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));*/ - if( rTotalcost.rCost ){ - p->cost.rCost = rTotal; - p->cost.used = used; - p->cost.plan.nRow = nRow; - p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0; - p->cost.plan.wsFlags = WHERE_MULTI_OR; - p->cost.plan.u.pTerm = pTerm; - } - } - } -#endif /* SQLITE_OMIT_OR_OPTIMIZATION */ -} - #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* ** Return TRUE if the WHERE clause term pTerm is of a form where it @@ -2000,82 +1829,6 @@ static int termCanDriveIndex( } #endif -#ifndef SQLITE_OMIT_AUTOMATIC_INDEX -/* -** If the query plan for pSrc specified in pCost is a full table scan -** and indexing is allows (if there is no NOT INDEXED clause) and it -** possible to construct a transient index that would perform better -** than a full table scan even when the cost of constructing the index -** is taken into account, then alter the query plan to use the -** transient index. -*/ -static void bestAutomaticIndex(WhereBestIdx *p){ - Parse *pParse = p->pParse; /* The parsing context */ - WhereClause *pWC = p->pWC; /* The WHERE clause */ - struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ - double nTableRow; /* Rows in the input table */ - double logN; /* log(nTableRow) */ - double costTempIdx; /* per-query cost of the transient index */ - WhereTerm *pTerm; /* A single term of the WHERE clause */ - WhereTerm *pWCEnd; /* End of pWC->a[] */ - Table *pTable; /* Table tht might be indexed */ - - if( pParse->nQueryLoop<=(double)1 ){ - /* There is no point in building an automatic index for a single scan */ - return; - } - if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){ - /* Automatic indices are disabled at run-time */ - return; - } - if( (p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 - && (p->cost.plan.wsFlags & WHERE_COVER_SCAN)==0 - ){ - /* We already have some kind of index in use for this query. */ - return; - } - if( pSrc->viaCoroutine ){ - /* Cannot index a co-routine */ - return; - } - if( pSrc->notIndexed ){ - /* The NOT INDEXED clause appears in the SQL. */ - return; - } - if( pSrc->isCorrelated ){ - /* The source is a correlated sub-query. No point in indexing it. */ - return; - } - - assert( pParse->nQueryLoop >= (double)1 ); - pTable = pSrc->pTab; - nTableRow = pTable->nRowEst; - logN = estLog(nTableRow); - costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1); - if( costTempIdx>=p->cost.rCost ){ - /* The cost of creating the transient table would be greater than - ** doing the full table scan */ - return; - } - - /* Search for any equality comparison term */ - pWCEnd = &pWC->a[pWC->nTerm]; - for(pTerm=pWC->a; pTermnotReady) ){ - /*WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n", - p->cost.rCost, costTempIdx));*/ - p->cost.rCost = costTempIdx; - p->cost.plan.nRow = logN + 1; - p->cost.plan.wsFlags = WHERE_TEMP_INDEX; - p->cost.used = pTerm->prereqRight; - break; - } - } -} -#else -# define bestAutomaticIndex(A) /* no-op */ -#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ - #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* @@ -2105,6 +1858,7 @@ static void constructAutomaticIndex( int i; /* Loop counter */ int mxBitCol; /* Maximum column in pSrc->colUsed */ CollSeq *pColl; /* Collating sequence to on a column */ + WhereLoop *pLoop; /* The Loop object */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ @@ -2119,6 +1873,7 @@ static void constructAutomaticIndex( nColumn = 0; pTable = pSrc->pTab; pWCEnd = &pWC->a[pWC->nTerm]; + pLoop = pLevel->pWLoop; idxCols = 0; for(pTerm=pWC->a; pTerm0 ); - pLevel->plan.nEq = nColumn; + pLoop->u.btree.nEq = nColumn; /* Count the number of additional columns needed to create a ** covering index. A "covering index" is an index that contains all @@ -2153,7 +1908,7 @@ static void constructAutomaticIndex( if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){ nColumn += pTable->nCol - BMS + 1; } - pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY; + pLoop->wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY; /* Construct the Index object to describe this index */ nByte = sizeof(Index); @@ -2162,7 +1917,7 @@ static void constructAutomaticIndex( nByte += nColumn; /* Index.aSortOrder */ pIdx = sqlite3DbMallocZero(pParse->db, nByte); if( pIdx==0 ) return; - pLevel->plan.u.pIdx = pIdx; + pLoop->u.btree.pIndex = pIdx; pIdx->azColl = (char**)&pIdx[1]; pIdx->aiColumn = (int*)&pIdx->azColl[nColumn]; pIdx->aSortOrder = (u8*)&pIdx->aiColumn[nColumn]; @@ -2185,7 +1940,7 @@ static void constructAutomaticIndex( } } } - assert( (u32)n==pLevel->plan.nEq ); + assert( (u32)n==pLoop->u.btree.nEq ); /* Add additional columns needed to make the automatic index into ** a covering index */ @@ -2384,208 +2139,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ return pParse->nErr; } +#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ -/* -** Compute the best index for a virtual table. -** -** The best index is computed by the xBestIndex method of the virtual -** table module. This routine is really just a wrapper that sets up -** the sqlite3_index_info structure that is used to communicate with -** xBestIndex. -** -** In a join, this routine might be called multiple times for the -** same virtual table. The sqlite3_index_info structure is created -** and initialized on the first invocation and reused on all subsequent -** invocations. The sqlite3_index_info structure is also used when -** code is generated to access the virtual table. The whereInfoDelete() -** routine takes care of freeing the sqlite3_index_info structure after -** everybody has finished with it. -*/ -static void bestVirtualIndex(WhereBestIdx *p){ - Parse *pParse = p->pParse; /* The parsing context */ - WhereClause *pWC = p->pWC; /* The WHERE clause */ - struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ - Table *pTab = pSrc->pTab; - sqlite3_index_info *pIdxInfo; - struct sqlite3_index_constraint *pIdxCons; - struct sqlite3_index_constraint_usage *pUsage; - WhereTerm *pTerm; - int i, j; - int nOrderBy; - int bAllowIN; /* Allow IN optimizations */ - double rCost; - - /* Make sure wsFlags is initialized to some sane value. Otherwise, if the - ** malloc in allocateIndexInfo() fails and this function returns leaving - ** wsFlags in an uninitialized state, the caller may behave unpredictably. - */ - memset(&p->cost, 0, sizeof(p->cost)); - p->cost.plan.wsFlags = WHERE_VIRTUALTABLE; - - /* If the sqlite3_index_info structure has not been previously - ** allocated and initialized, then allocate and initialize it now. - */ - pIdxInfo = *p->ppIdxInfo; - if( pIdxInfo==0 ){ - *p->ppIdxInfo = pIdxInfo = allocateIndexInfo(pParse,pWC,pSrc,p->pOrderBy); - } - if( pIdxInfo==0 ){ - return; - } - - /* At this point, the sqlite3_index_info structure that pIdxInfo points - ** to will have been initialized, either during the current invocation or - ** during some prior invocation. Now we just have to customize the - ** details of pIdxInfo for the current invocation and pass it to - ** xBestIndex. - */ - - /* The module name must be defined. Also, by this point there must - ** be a pointer to an sqlite3_vtab structure. Otherwise - ** sqlite3ViewGetColumnNames() would have picked up the error. - */ - assert( pTab->azModuleArg && pTab->azModuleArg[0] ); - assert( sqlite3GetVTable(pParse->db, pTab) ); - - /* Try once or twice. On the first attempt, allow IN optimizations. - ** If an IN optimization is accepted by the virtual table xBestIndex - ** method, but the pInfo->aConstrainUsage.omit flag is not set, then - ** the query will not work because it might allow duplicate rows in - ** output. In that case, run the xBestIndex method a second time - ** without the IN constraints. Usually this loop only runs once. - ** The loop will exit using a "break" statement. - */ - for(bAllowIN=1; 1; bAllowIN--){ - assert( bAllowIN==0 || bAllowIN==1 ); - - /* Set the aConstraint[].usable fields and initialize all - ** output variables to zero. - ** - ** aConstraint[].usable is true for constraints where the right-hand - ** side contains only references to tables to the left of the current - ** table. In other words, if the constraint is of the form: - ** - ** column = expr - ** - ** and we are evaluating a join, then the constraint on column is - ** only valid if all tables referenced in expr occur to the left - ** of the table containing column. - ** - ** The aConstraints[] array contains entries for all constraints - ** on the current table. That way we only have to compute it once - ** even though we might try to pick the best index multiple times. - ** For each attempt at picking an index, the order of tables in the - ** join might be different so we have to recompute the usable flag - ** each time. - */ - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - pUsage = pIdxInfo->aConstraintUsage; - for(i=0; inConstraint; i++, pIdxCons++){ - j = pIdxCons->iTermOffset; - pTerm = &pWC->a[j]; - if( (pTerm->prereqRight&p->notReady)==0 - && (bAllowIN || (pTerm->eOperator & WO_IN)==0) - ){ - pIdxCons->usable = 1; - }else{ - pIdxCons->usable = 0; - } - } - memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); - if( pIdxInfo->needToFreeIdxStr ){ - sqlite3_free(pIdxInfo->idxStr); - } - pIdxInfo->idxStr = 0; - pIdxInfo->idxNum = 0; - pIdxInfo->needToFreeIdxStr = 0; - pIdxInfo->orderByConsumed = 0; - /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ - pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); - nOrderBy = pIdxInfo->nOrderBy; - if( !p->pOrderBy ){ - pIdxInfo->nOrderBy = 0; - } - - if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ - return; - } - - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pIdxCons++){ - if( pUsage[i].argvIndex>0 ){ - j = pIdxCons->iTermOffset; - pTerm = &pWC->a[j]; - p->cost.used |= pTerm->prereqRight; - if( (pTerm->eOperator & WO_IN)!=0 ){ - if( pUsage[i].omit==0 ){ - /* Do not attempt to use an IN constraint if the virtual table - ** says that the equivalent EQ constraint cannot be safely omitted. - ** If we do attempt to use such a constraint, some rows might be - ** repeated in the output. */ - break; - } - /* A virtual table that is constrained by an IN clause may not - ** consume the ORDER BY clause because (1) the order of IN terms - ** 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; - } - } - } - if( i>=pIdxInfo->nConstraint ) break; - } - - /* The orderByConsumed signal is only valid if all outer loops collectively - ** generate just a single row of output. - */ - if( pIdxInfo->orderByConsumed ){ - for(i=0; ii; i++){ - if( (p->aLevel[i].plan.wsFlags & WHERE_UNIQUE)==0 ){ - pIdxInfo->orderByConsumed = 0; - } - } - } - - /* If there is an ORDER BY clause, and the selected virtual table index - ** does not satisfy it, increase the cost of the scan accordingly. This - ** matches the processing for non-virtual tables in bestBtreeIndex(). - */ - rCost = pIdxInfo->estimatedCost; - if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){ - rCost += estLog(rCost)*rCost; - } - - /* The cost is not allowed to be larger than SQLITE_BIG_DBL (the - ** inital value of lowestCost in this loop. If it is, then the - ** (costcost.rCost = (SQLITE_BIG_DBL/((double)2)); - }else{ - p->cost.rCost = rCost; - } - p->cost.plan.u.pVtabIdx = pIdxInfo; - if( pIdxInfo->orderByConsumed ){ - p->cost.plan.wsFlags |= WHERE_ORDERED; - p->cost.plan.nOBSat = nOrderBy; - }else{ - p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0; - } - p->cost.plan.nEq = 0; - pIdxInfo->nOrderBy = nOrderBy; - - /* Try to find a more efficient access pattern by using multiple indexes - ** to optimize an OR expression within the WHERE clause. - */ - bestOrClauseIndex(p); -} -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - #ifdef SQLITE_ENABLE_STAT3 /* ** Estimate the location of a particular key among all keys in an @@ -2979,879 +2535,6 @@ static int whereInScanEst( } #endif /* defined(SQLITE_ENABLE_STAT3) */ -/* -** Check to see if column iCol of the table with cursor iTab will appear -** in sorted order according to the current query plan. -** -** Return values: -** -** 0 iCol is not ordered -** 1 iCol has only a single value -** 2 iCol is in ASC order -** 3 iCol is in DESC order -*/ -static int isOrderedColumn( - WhereBestIdx *p, - int iTab, - int iCol -){ - int i, j; - WhereLevel *pLevel = &p->aLevel[p->i-1]; - Index *pIdx; - u8 sortOrder; - for(i=p->i-1; i>=0; i--, pLevel--){ - if( pLevel->iTabCur!=iTab ) continue; - if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){ - return 1; - } - assert( (pLevel->plan.wsFlags & WHERE_ORDERED)!=0 ); - if( (pIdx = pLevel->plan.u.pIdx)!=0 ){ - if( iCol<0 ){ - sortOrder = 0; - testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ); - }else{ - int n = pIdx->nColumn; - for(j=0; jaiColumn[j] ) break; - } - if( j>=n ) return 0; - sortOrder = pIdx->aSortOrder[j]; - testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ); - } - }else{ - if( iCol!=(-1) ) return 0; - sortOrder = 0; - testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ); - } - if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){ - assert( sortOrder==0 || sortOrder==1 ); - testcase( sortOrder==1 ); - sortOrder = 1 - sortOrder; - } - return sortOrder+2; - } - return 0; -} - -/* -** This routine decides if pIdx can be used to satisfy the ORDER BY -** clause, either in whole or in part. The return value is the -** cumulative number of terms in the ORDER BY clause that are satisfied -** by the index pIdx and other indices in outer loops. -** -** The table being queried has a cursor number of "base". pIdx is the -** index that is postulated for use to access the table. -** -** The *pbRev value is set to 0 order 1 depending on whether or not -** pIdx should be run in the forward order or in reverse order. -*/ -static int isSortingIndex( - WhereBestIdx *p, /* Best index search context */ - Index *pIdx, /* The index we are testing */ - int base, /* Cursor number for the table to be sorted */ - int *pbRev, /* Set to 1 for reverse-order scan of pIdx */ - int *pbObUnique /* ORDER BY column values will different in every row */ -){ - int i; /* Number of pIdx terms used */ - int j; /* Number of ORDER BY terms satisfied */ - int sortOrder = 2; /* 0: forward. 1: backward. 2: unknown */ - int nTerm; /* Number of ORDER BY terms */ - struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */ - Table *pTab = pIdx->pTable; /* Table that owns index pIdx */ - ExprList *pOrderBy; /* The ORDER BY clause */ - Parse *pParse = p->pParse; /* Parser context */ - sqlite3 *db = pParse->db; /* Database connection */ - int nPriorSat; /* ORDER BY terms satisfied by outer loops */ - int seenRowid = 0; /* True if an ORDER BY rowid term is seen */ - int uniqueNotNull; /* pIdx is UNIQUE with all terms are NOT NULL */ - int outerObUnique; /* Outer loops generate different values in - ** every row for the ORDER BY columns */ - - if( p->i==0 ){ - nPriorSat = 0; - outerObUnique = 1; - }else{ - u32 wsFlags = p->aLevel[p->i-1].plan.wsFlags; - nPriorSat = p->aLevel[p->i-1].plan.nOBSat; - if( (wsFlags & WHERE_ORDERED)==0 ){ - /* This loop cannot be ordered unless the next outer loop is - ** also ordered */ - return nPriorSat; - } - if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){ - /* Only look at the outer-most loop if the OrderByIdxJoin - ** optimization is disabled */ - return nPriorSat; - } - testcase( wsFlags & WHERE_OB_UNIQUE ); - testcase( wsFlags & WHERE_ALL_UNIQUE ); - outerObUnique = (wsFlags & (WHERE_OB_UNIQUE|WHERE_ALL_UNIQUE))!=0; - } - pOrderBy = p->pOrderBy; - assert( pOrderBy!=0 ); - if( pIdx->bUnordered ){ - /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot - ** be used for sorting */ - return nPriorSat; - } - nTerm = pOrderBy->nExpr; - uniqueNotNull = pIdx->onError!=OE_None; - assert( nTerm>0 ); - - /* Argument pIdx must either point to a 'real' named index structure, - ** or an index structure allocated on the stack by bestBtreeIndex() to - ** represent the rowid index that is part of every table. */ - assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) ); - - /* Match terms of the ORDER BY clause against columns of - ** the index. - ** - ** Note that indices have pIdx->nColumn regular columns plus - ** one additional column containing the rowid. The rowid column - ** of the index is also allowed to match against the ORDER BY - ** clause. - */ - j = nPriorSat; - for(i=0,pOBItem=&pOrderBy->a[j]; jnColumn; i++){ - Expr *pOBExpr; /* The expression of the ORDER BY pOBItem */ - CollSeq *pColl; /* The collating sequence of pOBExpr */ - int termSortOrder; /* Sort order for this term */ - int iColumn; /* The i-th column of the index. -1 for rowid */ - int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */ - int isEq; /* Subject to an == or IS NULL constraint */ - int isMatch; /* ORDER BY term matches the index term */ - const char *zColl; /* Name of collating sequence for i-th index term */ - WhereTerm *pConstraint; /* A constraint in the WHERE clause */ - - /* If the next term of the ORDER BY clause refers to anything other than - ** a column in the "base" table, then this index will not be of any - ** further use in handling the ORDER BY. */ - pOBExpr = sqlite3ExprSkipCollate(pOBItem->pExpr); - if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){ - break; - } - - /* Find column number and collating sequence for the next entry - ** in the index */ - if( pIdx->zName && inColumn ){ - iColumn = pIdx->aiColumn[i]; - if( iColumn==pIdx->pTable->iPKey ){ - iColumn = -1; - } - iSortOrder = pIdx->aSortOrder[i]; - zColl = pIdx->azColl[i]; - assert( zColl!=0 ); - }else{ - iColumn = -1; - iSortOrder = 0; - zColl = 0; - } - - /* Check to see if the column number and collating sequence of the - ** index match the column number and collating sequence of the ORDER BY - ** clause entry. Set isMatch to 1 if they both match. */ - if( pOBExpr->iColumn==iColumn ){ - if( zColl ){ - pColl = sqlite3ExprCollSeq(pParse, pOBItem->pExpr); - if( !pColl ) pColl = db->pDfltColl; - isMatch = sqlite3StrICmp(pColl->zName, zColl)==0; - }else{ - isMatch = 1; - } - }else{ - isMatch = 0; - } - - /* termSortOrder is 0 or 1 for whether or not the access loop should - ** run forward or backwards (respectively) in order to satisfy this - ** term of the ORDER BY clause. */ - assert( pOBItem->sortOrder==0 || pOBItem->sortOrder==1 ); - assert( iSortOrder==0 || iSortOrder==1 ); - termSortOrder = iSortOrder ^ pOBItem->sortOrder; - - /* If X is the column in the index and ORDER BY clause, check to see - ** if there are any X= or X IS NULL constraints in the WHERE clause. */ - pConstraint = findTerm(p->pWC, base, iColumn, p->notReady, - WO_EQ|WO_ISNULL|WO_IN, pIdx); - if( pConstraint==0 ){ - isEq = 0; - }else if( (pConstraint->eOperator & WO_IN)!=0 ){ - isEq = 0; - }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){ - uniqueNotNull = 0; - isEq = 1; /* "X IS NULL" means X has only a single value */ - }else if( pConstraint->prereqRight==0 ){ - isEq = 1; /* Constraint "X=constant" means X has only a single value */ - }else{ - Expr *pRight = pConstraint->pExpr->pRight; - if( pRight->op==TK_COLUMN ){ - /*WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)", - pRight->iTable, pRight->iColumn));*/ - isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn); - /*WHERETRACE((" -> isEq=%d\n", isEq));*/ - - /* If the constraint is of the form X=Y where Y is an ordered value - ** in an outer loop, then make sure the sort order of Y matches the - ** sort order required for X. */ - if( isMatch && isEq>=2 && isEq!=pOBItem->sortOrder+2 ){ - testcase( isEq==2 ); - testcase( isEq==3 ); - break; - } - }else{ - isEq = 0; /* "X=expr" places no ordering constraints on X */ - } - } - if( !isMatch ){ - if( isEq==0 ){ - break; - }else{ - continue; - } - }else if( isEq!=1 ){ - if( sortOrder==2 ){ - sortOrder = termSortOrder; - }else if( termSortOrder!=sortOrder ){ - break; - } - } - j++; - pOBItem++; - if( iColumn<0 ){ - seenRowid = 1; - break; - }else if( pTab->aCol[iColumn].notNull==0 && isEq!=1 ){ - testcase( isEq==0 ); - testcase( isEq==2 ); - testcase( isEq==3 ); - uniqueNotNull = 0; - } - } - if( seenRowid ){ - uniqueNotNull = 1; - }else if( uniqueNotNull==0 || inColumn ){ - uniqueNotNull = 0; - } - - /* If we have not found at least one ORDER BY term that matches the - ** index, then show no progress. */ - if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat; - - /* Either the outer queries must generate rows where there are no two - ** rows with the same values in all ORDER BY columns, or else this - ** loop must generate just a single row of output. Example: Suppose - ** the outer loops generate A=1 and A=1, and this loop generates B=3 - ** and B=4. Then without the following test, ORDER BY A,B would - ** generate the wrong order output: 1,3 1,4 1,3 1,4 - */ - if( outerObUnique==0 && uniqueNotNull==0 ) return nPriorSat; - *pbObUnique = uniqueNotNull; - - /* Return the necessary scan order back to the caller */ - *pbRev = sortOrder & 1; - - /* If there was an "ORDER BY rowid" term that matched, or it is only - ** possible for a single row from this table to match, then skip over - ** any additional ORDER BY terms dealing with this table. - */ - if( uniqueNotNull ){ - /* Advance j over additional ORDER BY terms associated with base */ - WhereMaskSet *pMS = p->pWC->pMaskSet; - Bitmask m = ~getMask(pMS, base); - while( ja[j].pExpr)&m)==0 ){ - j++; - } - } - return j; -} - -/* -** Find the best query plan for accessing a particular table. Write the -** best query plan and its cost into the p->cost. -** -** The lowest cost plan wins. The cost is an estimate of the amount of -** CPU and disk I/O needed to process the requested result. -** Factors that influence cost include: -** -** * The estimated number of rows that will be retrieved. (The -** fewer the better.) -** -** * Whether or not sorting must occur. -** -** * Whether or not there must be separate lookups in the -** index and in the main table. -** -** If there was an INDEXED BY clause (pSrc->pIndex) attached to the table in -** the SQL statement, then this function only considers plans using the -** named index. If no such plan is found, then the returned cost is -** SQLITE_BIG_DBL. If a plan is found that uses the named index, -** then the cost is calculated in the usual way. -** -** If a NOT INDEXED clause was attached to the table -** in the SELECT statement, then no indexes are considered. However, the -** selected plan may still take advantage of the built-in rowid primary key -** index. -*/ -static void bestBtreeIndex(WhereBestIdx *p){ - Parse *pParse = p->pParse; /* The parsing context */ - WhereClause *pWC = p->pWC; /* The WHERE clause */ - struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ - int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ - Index *pProbe; /* An index we are evaluating */ - Index *pIdx; /* Copy of pProbe, or zero for IPK index */ - int eqTermMask; /* Current mask of valid equality operators */ - int idxEqTermMask; /* Index mask of valid equality operators */ - Index sPk; /* A fake index object for the primary key */ - tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ - int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ - int wsFlagMask; /* Allowed flags in p->cost.plan.wsFlag */ - int nPriorSat; /* ORDER BY terms satisfied by outer loops */ - int nOrderBy; /* Number of ORDER BY terms */ - char bSortInit; /* Initializer for bSort in inner loop */ - char bDistInit; /* Initializer for bDist in inner loop */ - - - /* Initialize the cost to a worst-case value */ - memset(&p->cost, 0, sizeof(p->cost)); - p->cost.rCost = SQLITE_BIG_DBL; - - /* If the pSrc table is the right table of a LEFT JOIN then we may not - ** use an index to satisfy IS NULL constraints on that table. This is - ** because columns might end up being NULL if the table does not match - - ** a circumstance which the index cannot help us discover. Ticket #2177. - */ - if( pSrc->jointype & JT_LEFT ){ - idxEqTermMask = WO_EQ|WO_IN; - }else{ - idxEqTermMask = WO_EQ|WO_IN|WO_ISNULL; - } - - if( pSrc->pIndex ){ - /* An INDEXED BY clause specifies a particular index to use */ - pIdx = pProbe = pSrc->pIndex; - wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE); - eqTermMask = idxEqTermMask; - }else{ - /* There is no INDEXED BY clause. Create a fake Index object in local - ** variable sPk to represent the rowid primary key index. Make this - ** fake index the first in a chain of Index objects with all of the real - ** indices to follow */ - Index *pFirst; /* First of real indices on the table */ - memset(&sPk, 0, sizeof(Index)); - sPk.nColumn = 1; - sPk.aiColumn = &aiColumnPk; - sPk.aiRowEst = aiRowEstPk; - sPk.onError = OE_Replace; - sPk.pTable = pSrc->pTab; - aiRowEstPk[0] = pSrc->pTab->nRowEst; - aiRowEstPk[1] = 1; - pFirst = pSrc->pTab->pIndex; - if( pSrc->notIndexed==0 ){ - /* The real indices of the table are only considered if the - ** NOT INDEXED qualifier is omitted from the FROM clause */ - sPk.pNext = pFirst; - } - pProbe = &sPk; - wsFlagMask = ~( - WHERE_COLUMN_IN|WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_RANGE - ); - eqTermMask = WO_EQ|WO_IN; - pIdx = 0; - } - - nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0; - if( p->i ){ - nPriorSat = p->aLevel[p->i-1].plan.nOBSat; - bSortInit = nPriorSat0; - bDistInit = p->pDistinct!=0; - } - - /* Loop over all indices looking for the best one to use - */ - for(; pProbe; pIdx=pProbe=pProbe->pNext){ - const tRowcnt * const aiRowEst = pProbe->aiRowEst; - WhereCost pc; /* Cost of using pProbe */ - double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */ - - /* The following variables are populated based on the properties of - ** index being evaluated. They are then used to determine the expected - ** cost and number of rows returned. - ** - ** pc.plan.nEq: - ** Number of equality terms that can be implemented using the index. - ** In other words, the number of initial fields in the index that - ** are used in == or IN or NOT NULL constraints of the WHERE clause. - ** - ** nInMul: - ** The "in-multiplier". This is an estimate of how many seek operations - ** SQLite must perform on the index in question. For example, if the - ** WHERE clause is: - ** - ** WHERE a IN (1, 2, 3) AND b IN (4, 5, 6) - ** - ** SQLite must perform 9 lookups on an index on (a, b), so nInMul is - ** set to 9. Given the same schema and either of the following WHERE - ** clauses: - ** - ** WHERE a = 1 - ** WHERE a >= 2 - ** - ** nInMul is set to 1. - ** - ** If there exists a WHERE term of the form "x IN (SELECT ...)", then - ** the sub-select is assumed to return 25 rows for the purposes of - ** determining nInMul. - ** - ** bInEst: - ** Set to true if there was at least one "x IN (SELECT ...)" term used - ** in determining the value of nInMul. Note that the RHS of the - ** IN operator must be a SELECT, not a value list, for this variable - ** to be true. - ** - ** rangeDiv: - ** An estimate of a divisor by which to reduce the search space due - ** to inequality constraints. In the absence of sqlite_stat3 ANALYZE - ** data, a single inequality reduces the search space to 1/4rd its - ** original size (rangeDiv==4). Two inequalities reduce the search - ** space to 1/16th of its original size (rangeDiv==16). - ** - ** bSort: - ** Boolean. True if there is an ORDER BY clause that will require an - ** external sort (i.e. scanning the index being evaluated will not - ** correctly order records). - ** - ** bDist: - ** Boolean. True if there is a DISTINCT clause that will require an - ** external btree. - ** - ** bLookup: - ** Boolean. True if a table lookup is required for each index entry - ** visited. In other words, true if this is not a covering index. - ** This is always false for the rowid primary key index of a table. - ** For other indexes, it is true unless all the columns of the table - ** used by the SELECT statement are present in the index (such an - ** index is sometimes described as a covering index). - ** For example, given the index on (a, b), the second of the following - ** two queries requires table b-tree lookups in order to find the value - ** of column c, but the first does not because columns a and b are - ** both available in the index. - ** - ** SELECT a, b FROM tbl WHERE a = 1; - ** SELECT a, b, c FROM tbl WHERE a = 1; - */ - int bInEst = 0; /* True if "x IN (SELECT...)" seen */ - int nInMul = 1; /* Number of distinct equalities to lookup */ - double rangeDiv = (double)1; /* Estimated reduction in search space */ - int nBound = 0; /* Number of range constraints seen */ - char bSort = bSortInit; /* True if external sort required */ - char bDist = bDistInit; /* True if index cannot help with DISTINCT */ - char bLookup = 0; /* True if not a covering index */ - WhereTerm *pTerm; /* A single term of the WHERE clause */ -#ifdef SQLITE_ENABLE_STAT3 - WhereTerm *pFirstTerm = 0; /* First term matching the index */ -#endif - - /*WHERETRACE(( - " %s(%s):\n", - pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk") - ));*/ - memset(&pc, 0, sizeof(pc)); - pc.plan.nOBSat = nPriorSat; - - /* Determine the values of pc.plan.nEq and nInMul */ - for(pc.plan.nEq=0; pc.plan.nEqnColumn; pc.plan.nEq++){ - int j = pProbe->aiColumn[pc.plan.nEq]; - pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx); - if( pTerm==0 ) break; - pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ); - testcase( pTerm->pWC!=pWC ); - if( pTerm->eOperator & WO_IN ){ - Expr *pExpr = pTerm->pExpr; - pc.plan.wsFlags |= WHERE_COLUMN_IN; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */ - nInMul *= 25; - bInEst = 1; - }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ - /* "x IN (value, value, ...)" */ - nInMul *= pExpr->x.pList->nExpr; - } - }else if( pTerm->eOperator & WO_ISNULL ){ - pc.plan.wsFlags |= WHERE_COLUMN_NULL; - } -#ifdef SQLITE_ENABLE_STAT3 - if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm; -#endif - pc.used |= pTerm->prereqRight; - } - - /* If the index being considered is UNIQUE, and there is an equality - ** constraint for all columns in the index, then this search will find - ** at most a single row. In this case set the WHERE_UNIQUE flag to - ** indicate this to the caller. - ** - ** Otherwise, if the search may find more than one row, test to see if - ** there is a range constraint on indexed column (pc.plan.nEq+1) that - ** can be optimized using the index. - */ - if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){ - testcase( pc.plan.wsFlags & WHERE_COLUMN_IN ); - testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL ); - if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){ - pc.plan.wsFlags |= WHERE_UNIQUE; - if( p->i==0 || (p->aLevel[p->i-1].plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){ - pc.plan.wsFlags |= WHERE_ALL_UNIQUE; - } - } - }else if( pProbe->bUnordered==0 ){ - int j; - j = (pc.plan.nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[pc.plan.nEq]); - if( findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ - WhereTerm *pTop, *pBtm; - pTop = findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE, pIdx); - pBtm = findTerm(pWC, iCur, j, p->notReady, WO_GT|WO_GE, pIdx); - whereRangeScanEst(pParse, pProbe, pc.plan.nEq, pBtm, pTop, &rangeDiv); - if( pTop ){ - nBound = 1; - pc.plan.wsFlags |= WHERE_TOP_LIMIT; - pc.used |= pTop->prereqRight; - testcase( pTop->pWC!=pWC ); - } - if( pBtm ){ - nBound++; - pc.plan.wsFlags |= WHERE_BTM_LIMIT; - pc.used |= pBtm->prereqRight; - testcase( pBtm->pWC!=pWC ); - } - pc.plan.wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE); - } - } - - /* If there is an ORDER BY clause and the index being considered will - ** naturally scan rows in the required order, set the appropriate flags - ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but - ** the index will scan rows in a different order, set the bSort - ** variable. */ - if( bSort && (pSrc->jointype & JT_LEFT)==0 ){ - int bRev = 2; - int bObUnique = 0; - /*WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat));*/ - pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev, &bObUnique); - /*WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n", - bRev, bObUnique, pc.plan.nOBSat));*/ - if( nPriorSatpDistinct, pc.plan.nEq) - && (pc.plan.wsFlags & WHERE_COLUMN_IN)==0 - ){ - bDist = 0; - pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT; - } - - /* If currently calculating the cost of using an index (not the IPK - ** index), determine if all required column data may be obtained without - ** using the main table (i.e. if the index is a covering - ** index for this query). If it is, set the WHERE_IDX_ONLY flag in - ** pc.plan.wsFlags. Otherwise, set the bLookup variable to true. */ - if( pIdx ){ - Bitmask m = pSrc->colUsed; - int j; - for(j=0; jnColumn; j++){ - int x = pIdx->aiColumn[j]; - if( xaiRowEst[0] ){ - pc.plan.nRow = aiRowEst[0]/2; - nInMul = (int)(pc.plan.nRow / aiRowEst[pc.plan.nEq]); - } - -#ifdef SQLITE_ENABLE_STAT3 - /* If the constraint is of the form x=VALUE or x IN (E1,E2,...) - ** and we do not think that values of x are unique and if histogram - ** data is available for column x, then it might be possible - ** to get a better estimate on the number of rows based on - ** VALUE and how common that value is according to the histogram. - */ - if( pc.plan.nRow>(double)1 && pc.plan.nEq==1 - && pFirstTerm!=0 && aiRowEst[1]>1 ){ - assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 ); - if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ - testcase( pFirstTerm->eOperator & WO_EQ ); - testcase( pFirstTerm->eOperator & WO_EQUIV ); - testcase( pFirstTerm->eOperator & WO_ISNULL ); - whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, - &pc.plan.nRow); - }else if( bInEst==0 ){ - assert( pFirstTerm->eOperator & WO_IN ); - whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, - &pc.plan.nRow); - } - } -#endif /* SQLITE_ENABLE_STAT3 */ - - /* Adjust the number of output rows and downward to reflect rows - ** that are excluded by range constraints. - */ - pc.plan.nRow = pc.plan.nRow/rangeDiv; - if( pc.plan.nRow<1 ) pc.plan.nRow = 1; - - /* Experiments run on real SQLite databases show that the time needed - ** to do a binary search to locate a row in a table or index is roughly - ** log10(N) times the time to move from one row to the next row within - ** a table or index. The actual times can vary, with the size of - ** records being an important factor. Both moves and searches are - ** slower with larger records, presumably because fewer records fit - ** on one page and hence more pages have to be fetched. - ** - ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do - ** not give us data on the relative sizes of table and index records. - ** So this computation assumes table records are about twice as big - ** as index records - */ - if( (pc.plan.wsFlags&~(WHERE_REVERSE|WHERE_ORDERED|WHERE_OB_UNIQUE)) - ==WHERE_IDX_ONLY - && (pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 - && sqlite3GlobalConfig.bUseCis - && OptimizationEnabled(pParse->db, SQLITE_CoverIdxScan) - ){ - /* This index is not useful for indexing, but it is a covering index. - ** A full-scan of the index might be a little faster than a full-scan - ** of the table, so give this case a cost slightly less than a table - ** scan. */ - pc.rCost = aiRowEst[0]*3 + pProbe->nColumn; - pc.plan.wsFlags |= WHERE_COVER_SCAN|WHERE_COLUMN_RANGE; - }else if( (pc.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ - /* The cost of a full table scan is a number of move operations equal - ** to the number of rows in the table. - ** - ** We add an additional 4x penalty to full table scans. This causes - ** the cost function to err on the side of choosing an index over - ** choosing a full scan. This 4x full-scan penalty is an arguable - ** decision and one which we expect to revisit in the future. But - ** it seems to be working well enough at the moment. - */ - pc.rCost = aiRowEst[0]*4; - pc.plan.wsFlags &= ~WHERE_IDX_ONLY; - if( pIdx ){ - pc.plan.wsFlags &= ~WHERE_ORDERED; - pc.plan.nOBSat = nPriorSat; - } - }else{ - log10N = estLog(aiRowEst[0]); - pc.rCost = pc.plan.nRow; - if( pIdx ){ - if( bLookup ){ - /* For an index lookup followed by a table lookup: - ** nInMul index searches to find the start of each index range - ** + nRow steps through the index - ** + nRow table searches to lookup the table entry using the rowid - */ - pc.rCost += (nInMul + pc.plan.nRow)*log10N; - }else{ - /* For a covering index: - ** nInMul index searches to find the initial entry - ** + nRow steps through the index - */ - pc.rCost += nInMul*log10N; - } - }else{ - /* For a rowid primary key lookup: - ** nInMult table searches to find the initial entry for each range - ** + nRow steps through the table - */ - pc.rCost += nInMul*log10N; - } - } - - /* Add in the estimated cost of sorting the result. Actual experimental - ** measurements of sorting performance in SQLite show that sorting time - ** adds C*N*log10(N) to the cost, where N is the number of rows to be - ** sorted and C is a factor between 1.95 and 4.3. We will split the - ** difference and select C of 3.0. - */ - if( bSort ){ - double m = estLog(pc.plan.nRow*(nOrderBy - pc.plan.nOBSat)/nOrderBy); - m *= (double)(pc.plan.nOBSat ? 2 : 3); - pc.rCost += pc.plan.nRow*m; - } - if( bDist ){ - pc.rCost += pc.plan.nRow*estLog(pc.plan.nRow)*3; - } - - /**** Cost of using this index has now been computed ****/ - - /* If there are additional constraints on this table that cannot - ** be used with the current index, but which might lower the number - ** of output rows, adjust the nRow value accordingly. This only - ** matters if the current index is the least costly, so do not bother - ** with this step if we already know this index will not be chosen. - ** Also, never reduce the output row count below 2 using this step. - ** - ** It is critical that the notValid mask be used here instead of - ** the notReady mask. When computing an "optimal" index, the notReady - ** mask will only have one bit set - the bit for the current table. - ** The notValid mask, on the other hand, always has all bits set for - ** tables that are not in outer loops. If notReady is used here instead - ** of notValid, then a optimal index that depends on inner joins loops - ** might be selected even when there exists an optimal index that has - ** no such dependency. - */ - if( pc.plan.nRow>2 && pc.rCost<=p->cost.rCost ){ - int k; /* Loop counter */ - int nSkipEq = pc.plan.nEq; /* Number of == constraints to skip */ - int nSkipRange = nBound; /* Number of < constraints to skip */ - Bitmask thisTab; /* Bitmap for pSrc */ - - thisTab = getMask(pWC->pMaskSet, iCur); - for(pTerm=pWC->a, k=pWC->nTerm; pc.plan.nRow>2 && k; k--, pTerm++){ - if( pTerm->wtFlags & TERM_VIRTUAL ) continue; - if( (pTerm->prereqAll & p->notValid)!=thisTab ) continue; - if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){ - if( nSkipEq ){ - /* Ignore the first pc.plan.nEq equality matches since the index - ** has already accounted for these */ - nSkipEq--; - }else{ - /* Assume each additional equality match reduces the result - ** set size by a factor of 10 */ - pc.plan.nRow /= 10; - } - }else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){ - if( nSkipRange ){ - /* Ignore the first nSkipRange range constraints since the index - ** has already accounted for these */ - nSkipRange--; - }else{ - /* Assume each additional range constraint reduces the result - ** set size by a factor of 3. Indexed range constraints reduce - ** the search space by a larger factor: 4. We make indexed range - ** more selective intentionally because of the subjective - ** observation that indexed range constraints really are more - ** selective in practice, on average. */ - pc.plan.nRow /= 3; - } - }else if( (pTerm->eOperator & WO_NOOP)==0 ){ - /* Any other expression lowers the output row count by half */ - pc.plan.nRow /= 2; - } - } - if( pc.plan.nRow<2 ) pc.plan.nRow = 2; - } - - - /*WHERETRACE(( - " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n" - " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n" - " used=0x%llx nOBSat=%d\n", - pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags, - p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used, - pc.plan.nOBSat - ));*/ - - /* If this index is the best we have seen so far, then record this - ** index and its cost in the p->cost structure. - */ - if( (!pIdx || pc.plan.wsFlags) && compareCost(&pc, &p->cost) ){ - p->cost = pc; - p->cost.plan.wsFlags &= wsFlagMask; - p->cost.plan.u.pIdx = pIdx; - } - - /* If there was an INDEXED BY clause, then only that one index is - ** considered. */ - if( pSrc->pIndex ) break; - - /* Reset masks for the next index in the loop */ - wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE); - eqTermMask = idxEqTermMask; - } - - /* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag - ** is set, then reverse the order that the index will be scanned - ** in. This is used for application testing, to help find cases - ** where application behavior depends on the (undefined) order that - ** SQLite outputs rows in in the absence of an ORDER BY clause. */ - if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){ - p->cost.plan.wsFlags |= WHERE_REVERSE; - } - - assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 ); - assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 ); - assert( pSrc->pIndex==0 - || p->cost.plan.u.pIdx==0 - || p->cost.plan.u.pIdx==pSrc->pIndex - ); - - /*WHERETRACE((" best index is %s cost=%.1f\n", - p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk", - p->cost.rCost));*/ - - bestOrClauseIndex(p); - bestAutomaticIndex(p); - if( eqTermMask & WO_ISNULL ) p->cost.plan.wsFlags |= WHERE_NULL_OK; -} - -/* -** Find the query plan for accessing table pSrc->pTab. Write the -** best query plan and its cost into the WhereCost object supplied -** as the last parameter. This function may calculate the cost of -** both real and virtual table scans. -** -** This function does not take ORDER BY or DISTINCT into account. Nor -** does it remember the virtual table query plan. All it does is compute -** the cost while determining if an OR optimization is applicable. The -** details will be reconsidered later if the optimization is found to be -** applicable. -*/ -static void bestIndex(WhereBestIdx *p){ -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(p->pSrc->pTab) ){ - sqlite3_index_info *pIdxInfo = 0; - p->ppIdxInfo = &pIdxInfo; - bestVirtualIndex(p); - assert( pIdxInfo!=0 || p->pParse->db->mallocFailed ); - if( pIdxInfo && pIdxInfo->needToFreeIdxStr ){ - sqlite3_free(pIdxInfo->idxStr); - } - sqlite3DbFree(p->pParse->db, pIdxInfo); - }else -#endif - { - bestBtreeIndex(p); - } -} - /* ** Disable a term in the WHERE clause. Except, do not disable the term ** if it controls a LEFT OUTER JOIN and it did not originate in the ON @@ -3949,6 +2632,7 @@ static int codeEqualityTerm( WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ WhereLevel *pLevel, /* The level of the FROM clause we are working on */ int iEq, /* Index of the equality term within this level */ + int bRev, /* True for reverse-order IN operations */ int iTarget /* Attempt to leave results in this register */ ){ Expr *pX = pTerm->pExpr; @@ -3966,10 +2650,11 @@ static int codeEqualityTerm( int eType; int iTab; struct InLoop *pIn; - u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; + WhereLoop *pLoop = pLevel->pWLoop; - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 - && pLevel->plan.u.pIdx->aSortOrder[iEq] + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 + && pLoop->u.btree.pIndex!=0 + && pLoop->u.btree.pIndex->aSortOrder[iEq] ){ testcase( iEq==0 ); testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 ); @@ -3986,7 +2671,7 @@ static int codeEqualityTerm( } iTab = pX->iTable; sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); - assert( pLevel->plan.wsFlags & WHERE_IN_ABLE ); + assert( pLoop->wsFlags & WHERE_IN_ABLE ); if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } @@ -4058,28 +2743,31 @@ static int codeAllEqualityTerms( WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ WhereClause *pWC, /* The WHERE clause */ Bitmask notReady, /* Which parts of FROM have not yet been coded */ + int bRev, /* Reverse the order of IN operators */ int nExtraReg, /* Number of extra registers to allocate */ char **pzAff /* OUT: Set to point to affinity string */ ){ - int nEq = pLevel->plan.nEq; /* The number of == or IN constraints to code */ + int nEq; /* The number of == or IN constraints to code */ Vdbe *v = pParse->pVdbe; /* The vm under construction */ Index *pIdx; /* The index being used for this loop */ - int iCur = pLevel->iTabCur; /* The cursor of the table */ WhereTerm *pTerm; /* A single constraint term */ + WhereLoop *pLoop; /* The WhereLoop object */ int j; /* Loop counter */ int regBase; /* Base register */ int nReg; /* Number of registers to allocate */ char *zAff; /* Affinity string to return */ - int eqFlags; /* WO_EQ|WO_IN and maybe also WO_ISNULL */ /* This module is only called on query plans that use an index. */ - assert( pLevel->plan.wsFlags & WHERE_INDEXED ); - pIdx = pLevel->plan.u.pIdx; + pLoop = pLevel->pWLoop; + assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); + nEq = pLoop->u.btree.nEq; + pIdx = pLoop->u.btree.pIndex; + assert( pIdx!=0 ); /* Figure out how many memory cells we will need then allocate them. */ regBase = pParse->nMem + 1; - nReg = pLevel->plan.nEq + nExtraReg; + nReg = pLoop->u.btree.nEq + nExtraReg; pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db, sqlite3IndexAffinityStr(v, pIdx)); @@ -4090,18 +2778,15 @@ static int codeAllEqualityTerms( /* Evaluate the equality constraints */ assert( pIdx->nColumn>=nEq ); - eqFlags = (pLevel->plan.wsFlags&WHERE_NULL_OK) ? (WO_EQ|WO_IN|WO_ISNULL) - : (WO_EQ|WO_IN); for(j=0; jaiColumn[j]; - pTerm = findTerm(pWC, iCur, k, notReady, eqFlags, pIdx); - if( pTerm==0 ) break; + pTerm = pLoop->aTerm[j]; + assert( pTerm!=0 ); /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ - r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j); + r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); if( r1!=regBase+j ){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, regBase); @@ -4306,6 +2991,7 @@ static Bitmask codeOneLoopStart( int omitTable; /* True if we use the index only */ int bRev; /* True if we need to scan in reverse order */ WhereLevel *pLevel; /* The where level to be coded */ + WhereLoop *pLoop; /* The WhereLoop object being coded */ WhereClause *pWC; /* Decomposition of the entire WHERE clause */ WhereTerm *pTerm; /* A WHERE clause term */ Parse *pParse; /* Parsing context */ @@ -4321,10 +3007,11 @@ static Bitmask codeOneLoopStart( v = pParse->pVdbe; pWC = pWInfo->pWC; pLevel = &pWInfo->a[iLevel]; + pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; - bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; - omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0 + bRev = (pWInfo->revMask>>iLevel)&1; + omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 && (wctrlFlags & WHERE_FORCE_TABLE)==0; VdbeNoopComment((v, "Begin Join Loop %d", iLevel)); @@ -4362,47 +3049,36 @@ static Bitmask codeOneLoopStart( }else #ifndef SQLITE_OMIT_VIRTUALTABLE - if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){ - /* Case 0: The table is a virtual-table. Use the VFilter and VNext + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ + /* Case 1: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; - sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx; - int nConstraint = pVtabIdx->nConstraint; - struct sqlite3_index_constraint_usage *aUsage = - pVtabIdx->aConstraintUsage; - const struct sqlite3_index_constraint *aConstraint = - pVtabIdx->aConstraint; + int nConstraint = pLoop->nTerm; sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; - for(j=1; j<=nConstraint; j++){ - for(k=0; ka[aConstraint[k].iTermOffset]; - if( pTerm->eOperator & WO_IN ){ - codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget); - addrNotFound = pLevel->addrNxt; - }else{ - sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); - } - break; - } - } - if( k==nConstraint ) break; - } - sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg); - sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); - sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pVtabIdx->idxStr, - pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); - pVtabIdx->needToFreeIdxStr = 0; for(j=0; ja[iTerm]); + int iTarget = iReg+j+1; + pTerm = pLoop->aTerm[j]; + if( pTerm->eOperator & WO_IN ){ + codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); + addrNotFound = pLevel->addrNxt; + }else{ + sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); + } + } + sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); + sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); + sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, + pLoop->u.vtab.idxStr, + pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC); + pLoop->u.vtab.needFree = 0; + for(j=0; ju.vtab.omitMask>>j)&1 ){ + disableTerm(pLevel, pLoop->aTerm[j]); } } pLevel->op = OP_VNext; @@ -4413,19 +3089,22 @@ static Bitmask codeOneLoopStart( }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ - if( pLevel->plan.wsFlags & WHERE_ROWID_EQ ){ - /* Case 1: We can directly reference a single row using an + if( (pLoop->wsFlags & WHERE_IPK)!=0 + && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0 + ){ + /* Case 2: We can directly reference a single row using an ** equality comparison against the ROWID field. Or ** we reference multiple rows using a "rowid IN (...)" ** construct. */ + assert( pLoop->u.btree.nEq==1 ); iReleaseReg = sqlite3GetTempReg(pParse); - pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); + pTerm = pLoop->aTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ - iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg); + iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); @@ -4433,8 +3112,10 @@ static Bitmask codeOneLoopStart( sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; - }else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){ - /* Case 2: We have an inequality comparison against the ROWID field. + }else if( (pLoop->wsFlags & WHERE_IPK)!=0 + && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 + ){ + /* Case 3: We have an inequality comparison against the ROWID field. */ int testOp = OP_Noop; int start; @@ -4442,8 +3123,10 @@ static Bitmask codeOneLoopStart( WhereTerm *pStart, *pEnd; assert( omitTable==0 ); - pStart = findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0); - pEnd = findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0); + j = 0; + pStart = pEnd = 0; + if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aTerm[j++]; + if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aTerm[j++]; if( bRev ){ pTerm = pStart; pStart = pEnd; @@ -4510,8 +3193,8 @@ static Bitmask codeOneLoopStart( sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); } - }else if( pLevel->plan.wsFlags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){ - /* Case 3: A scan using an index. + }else if( pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ|WHERE_IDX_ONLY) ){ + /* Case 4: A scan using an index. ** ** The WHERE clause may contain zero or more equality ** terms ("==" or "IN" operators) that refer to the N @@ -4557,8 +3240,8 @@ static Bitmask codeOneLoopStart( OP_IdxGE, /* 1: (end_constraints && !bRev) */ OP_IdxLT /* 2: (end_constraints && bRev) */ }; - int nEq = pLevel->plan.nEq; /* Number of == or IN terms */ - int isMinQuery = 0; /* If this is an optimized SELECT min(x).. */ + int nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */ + int isMinQuery = 0; /* If this is an optimized SELECT min(x).. */ int regBase; /* Base register holding constraint values */ int r1; /* Temp register */ WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */ @@ -4574,7 +3257,7 @@ static Bitmask codeOneLoopStart( char *zStartAff; /* Affinity for start of range constraint */ char *zEndAff; /* Affinity for end of range constraint */ - pIdx = pLevel->plan.u.pIdx; + pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; k = (nEq==pIdx->nColumn ? -1 : pIdx->aiColumn[nEq]); @@ -4587,7 +3270,7 @@ static Bitmask codeOneLoopStart( ** this requires some special handling. */ if( (wctrlFlags&WHERE_ORDERBY_MIN)!=0 - && (pLevel->plan.wsFlags&WHERE_ORDERED) + && (pWInfo->nOBSat>0) && (pIdx->nColumn>nEq) ){ /* assert( pOrderBy->nExpr==1 ); */ @@ -4599,12 +3282,13 @@ static Bitmask codeOneLoopStart( /* Find any inequality constraint terms for the start and end ** of the range. */ - if( pLevel->plan.wsFlags & WHERE_TOP_LIMIT ){ - pRangeEnd = findTerm(pWC, iCur, k, notReady, (WO_LT|WO_LE), pIdx); + j = nEq; + if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ + pRangeStart = pLoop->aTerm[j++]; nExtraReg = 1; } - if( pLevel->plan.wsFlags & WHERE_BTM_LIMIT ){ - pRangeStart = findTerm(pWC, iCur, k, notReady, (WO_GT|WO_GE), pIdx); + if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ + pRangeEnd = pLoop->aTerm[j++]; nExtraReg = 1; } @@ -4613,7 +3297,7 @@ static Bitmask codeOneLoopStart( ** starting at regBase. */ regBase = codeAllEqualityTerms( - pParse, pLevel, pWC, notReady, nExtraReg, &zStartAff + pParse, pLevel, pWC, notReady, bRev, nExtraReg, &zStartAff ); zEndAff = sqlite3DbStrDup(pParse->db, zStartAff); addrNxt = pLevel->addrNxt; @@ -4723,7 +3407,7 @@ static Bitmask codeOneLoopStart( r1 = sqlite3GetTempReg(pParse); testcase( pLevel->plan.wsFlags & WHERE_BTM_LIMIT ); testcase( pLevel->plan.wsFlags & WHERE_TOP_LIMIT ); - if( (pLevel->plan.wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 ){ + if( (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 ){ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1); sqlite3VdbeAddOp2(v, OP_IsNull, r1, addrCont); } @@ -4742,7 +3426,7 @@ static Bitmask codeOneLoopStart( /* Record the instruction used to terminate the loop. Disable ** WHERE clause terms made redundant by the index range scan. */ - if( pLevel->plan.wsFlags & WHERE_UNIQUE ){ + if( pLoop->wsFlags & WHERE_UNIQUE ){ pLevel->op = OP_Noop; }else if( bRev ){ pLevel->op = OP_Prev; @@ -4750,7 +3434,7 @@ static Bitmask codeOneLoopStart( pLevel->op = OP_Next; } pLevel->p1 = iIdxCur; - if( pLevel->plan.wsFlags & WHERE_COVER_SCAN ){ + if( pLoop->wsFlags & WHERE_COVER_SCAN ){ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; }else{ assert( pLevel->p5==0 ); @@ -4758,8 +3442,8 @@ static Bitmask codeOneLoopStart( }else #ifndef SQLITE_OMIT_OR_OPTIMIZATION - if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){ - /* Case 4: Two or more separately indexed terms connected by OR + if( pLoop->wsFlags & WHERE_MULTI_OR ){ + /* Case 5: Two or more separately indexed terms connected by OR ** ** Example: ** @@ -4812,7 +3496,7 @@ static Bitmask codeOneLoopStart( int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ - pTerm = pLevel->plan.u.pTerm; + pTerm = pLoop->aTerm[0]; assert( pTerm!=0 ); assert( pTerm->eOperator & WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); @@ -4904,7 +3588,7 @@ static Bitmask codeOneLoopStart( WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur); assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed ); if( pSubWInfo ){ - WhereLevel *pLvl; + WhereLoop *pSubLoop; explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); @@ -4937,13 +3621,13 @@ static Bitmask codeOneLoopStart( ** pCov to NULL to indicate that no candidate covering index will ** be available. */ - pLvl = &pSubWInfo->a[0]; - if( (pLvl->plan.wsFlags & WHERE_INDEXED)!=0 - && (pLvl->plan.wsFlags & WHERE_TEMP_INDEX)==0 - && (ii==0 || pLvl->plan.u.pIdx==pCov) + pSubLoop = pSubWInfo->a[0].pWLoop; + if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 + && (pSubLoop->wsFlags & WHERE_TEMP_INDEX)==0 + && (ii==0 || pSubLoop->u.btree.pIndex==pCov) ){ - assert( pLvl->iIdxCur==iCovCur ); - pCov = pLvl->plan.u.pIdx; + assert( pSubWInfo->a[0].iIdxCur==iCovCur ); + pCov = pLoop->u.btree.pIndex; }else{ pCov = 0; } @@ -4969,13 +3653,12 @@ static Bitmask codeOneLoopStart( #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ { - /* Case 5: There is no usable index. We must do a complete + /* Case 6: There is no usable index. We must do a complete ** scan of the entire table. */ static const u8 aStep[] = { OP_Next, OP_Prev }; static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); - assert( omitTable==0 ); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); @@ -5145,16 +3828,8 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ if( ALWAYS(pWInfo) ){ int i; for(i=0; inLevel; i++){ - sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo; - if( pInfo ){ - /* assert( pInfo->needToFreeIdxStr==0 || db->mallocFailed ); */ - if( pInfo->needToFreeIdxStr ){ - sqlite3_free(pInfo->idxStr); - } - sqlite3DbFree(db, pInfo); - } - if( pWInfo->a[i].plan.wsFlags & WHERE_TEMP_INDEX ){ - Index *pIdx = pWInfo->a[i].plan.u.pIdx; + if( pWInfo->a[i].pWLoop->wsFlags & WHERE_TEMP_INDEX ){ + Index *pIdx = pWInfo->a[i].pWLoop->u.btree.pIndex; if( pIdx ){ sqlite3DbFree(db, pIdx->zColAff); sqlite3DbFree(db, pIdx); @@ -5333,6 +4008,7 @@ static int whereLoopAddBtreeIndex( rLogSize = estLog(pProbe->aiRowEst[0]); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ int nIn = 1; + pNew->wsFlags = savedLoop.wsFlags; pNew->u.btree.nEq = savedLoop.u.btree.nEq; pNew->nTerm = savedLoop.nTerm; if( pNew->nTerm>=pBuilder->mxTerm ) break; /* Repeated column in index */ @@ -6183,7 +4859,10 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ assert( pWInfo->nLevel==nLoop ); /* Load the lowest cost path into pWInfo */ for(iLoop=0; iLoopa[iLoop].pWLoop = pFrom->aLoop[iLoop]; + WhereLevel *pLevel = pWInfo->a + iLoop; + pLevel->pWLoop = pWLoop = pFrom->aLoop[iLoop]; + pLevel->iFrom = pWLoop->iTab; /* FIXME: Omit the iFrom field */ + pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; } if( pFrom->isOrdered ){ pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; @@ -6302,8 +4981,6 @@ WhereInfo *sqlite3WhereBegin( WhereLoopBuilder sWLB; /* The WhereLoop builder */ WhereMaskSet *pMaskSet; /* The expression mask set */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */ - int iFrom; /* First unused FROM clause element */ - int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */ int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ int rc; /* Return code */ @@ -6476,274 +5153,7 @@ WhereInfo *sqlite3WhereBegin( } #endif - /* Chose the best index to use for each table in the FROM clause. - ** - ** This loop fills in the following fields: - ** - ** pWInfo->a[].pIdx The index to use for this level of the loop. - ** pWInfo->a[].wsFlags WHERE_xxx flags associated with pIdx - ** pWInfo->a[].nEq The number of == and IN constraints - ** pWInfo->a[].iFrom Which term of the FROM clause is being coded - ** pWInfo->a[].iTabCur The VDBE cursor for the database table - ** pWInfo->a[].iIdxCur The VDBE cursor for the index - ** pWInfo->a[].pTerm When wsFlags==WO_OR, the OR-clause term - ** - ** This loop also figures out the nesting order of tables in the FROM - ** clause. - */ - sWBI.notValid = ~(Bitmask)0; - sWBI.pOrderBy = pOrderBy; - sWBI.n = nTabList; - sWBI.pDistinct = pDistinct; - andFlags = ~0; - for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.ia[j]; jiCursor); - if( (m & sWBI.notValid)==0 ){ - if( j==iFrom ) iFrom++; - continue; - } - if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break; - if( ++ckOptimal ) break; - if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; - } - } - assert( ckOptimal==0 || ckOptimal==1 ); - - for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){ - for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; jiFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){ - /* This break and one like it in the ckOptimal computation loop - ** above prevent table reordering across LEFT and CROSS JOINs. - ** The LEFT JOIN case is necessary for correctness. The prohibition - ** against reordering across a CROSS JOIN is an SQLite feature that - ** allows the developer to control table reordering */ - break; - } - m = getMask(pMaskSet, sWBI.pSrc->iCursor); - if( (m & sWBI.notValid)==0 ){ - assert( j>iFrom ); - continue; - } - sWBI.notReady = (isOptimal ? m : sWBI.notValid); - if( sWBI.pSrc->pIndex==0 ) nUnconstrained++; - - /*WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n", - j, sWBI.pSrc->pTab->zName, isOptimal));*/ - assert( sWBI.pSrc->pTab ); -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(sWBI.pSrc->pTab) ){ - sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo; - bestVirtualIndex(&sWBI); - }else -#endif - { - bestBtreeIndex(&sWBI); - } - assert( isOptimal || (sWBI.cost.used&sWBI.notValid)==0 ); - - /* If an INDEXED BY clause is present, then the plan must use that - ** index if it uses any index at all */ - assert( sWBI.pSrc->pIndex==0 - || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 - || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex ); - - if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ - notIndexed |= m; - } - if( isOptimal ){ - pWInfo->a[j].rOptCost = sWBI.cost.rCost; - }else if( ckOptimal ){ - /* If two or more tables have nearly the same outer loop cost, but - ** very different inner loop (optimal) cost, we want to choose - ** for the outer loop that table which benefits the least from - ** being in the inner loop. The following code scales the - ** outer loop cost estimate to accomplish that. */ - /*WHERETRACE((" scaling cost from %.1f to %.1f\n", - sWBI.cost.rCost, - sWBI.cost.rCost/pWInfo->a[j].rOptCost));*/ - sWBI.cost.rCost /= pWInfo->a[j].rOptCost; - } - - /* Conditions under which this table becomes the best so far: - ** - ** (1) The table must not depend on other tables that have not - ** yet run. (In other words, it must not depend on tables - ** in inner loops.) - ** - ** (2) (This rule was removed on 2012-11-09. The scaling of the - ** cost using the optimal scan cost made this rule obsolete.) - ** - ** (3) All tables have an INDEXED BY clause or this table lacks an - ** INDEXED BY clause or this table uses the specific - ** index specified by its INDEXED BY clause. This rule ensures - ** that a best-so-far is always selected even if an impossible - ** combination of INDEXED BY clauses are given. The error - ** will be detected and relayed back to the application later. - ** The NEVER() comes about because rule (2) above prevents - ** An indexable full-table-scan from reaching rule (3). - ** - ** (4) The plan cost must be lower than prior plans, where "cost" - ** is defined by the compareCost() function above. - */ - if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */ - && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */ - || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) - && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */ - ){ - /*WHERETRACE((" === table %d (%s) is best so far\n" - " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n", - j, sWBI.pSrc->pTab->zName, - sWBI.cost.rCost, sWBI.cost.plan.nRow, - sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));*/ - bestPlan = sWBI.cost; - bestJ = j; - } - - /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that - ** table y (and not table z) is always the next inner loop inside - ** of table x. */ - if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; - } - } - assert( bestJ>=0 ); - assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); - assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 ); - testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 ); - testcase( bestJ>iFrom && bestJa[bestJ+1].jointype & JT_LEFT)!=0 ); - /*WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n" - " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n", - bestJ, pTabList->a[bestJ].pTab->zName, - pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow, - bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));*/ - if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){ - assert( pWInfo->eDistinct==0 ); - pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; - } - andFlags &= bestPlan.plan.wsFlags; - pLevel->plan = bestPlan.plan; - pLevel->iTabCur = pTabList->a[bestJ].iCursor; - testcase( bestPlan.plan.wsFlags & WHERE_INDEXED ); - testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX ); - if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){ - if( (wctrlFlags & WHERE_ONETABLE_ONLY) - && (bestPlan.plan.wsFlags & WHERE_TEMP_INDEX)==0 - ){ - pLevel->iIdxCur = iIdxCur; - }else{ - pLevel->iIdxCur = pParse->nTab++; - } - }else{ - pLevel->iIdxCur = -1; - } - sWBI.notValid &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor); - pLevel->iFrom = (u8)bestJ; - if( bestPlan.plan.nRow>=(double)1 ){ - pParse->nQueryLoop *= bestPlan.plan.nRow; - } - - /* Check that if the table scanned by this loop iteration had an - ** INDEXED BY clause attached to it, that the named index is being - ** used for the scan. If not, then query compilation has failed. - ** Return an error. - */ - pIdx = pTabList->a[bestJ].pIndex; - if( pIdx ){ - if( (bestPlan.plan.wsFlags & WHERE_INDEXED)==0 ){ - sqlite3ErrorMsg(pParse, "cannot use index: %s", pIdx->zName); - goto whereBeginError; - }else{ - /* If an INDEXED BY clause is used, the bestIndex() function is - ** guaranteed to find the index specified in the INDEXED BY clause - ** if it find an index at all. */ - assert( bestPlan.plan.u.pIdx==pIdx ); - } - } - } - WHERETRACE(("*** Optimizer Finished ***\n")); - if( pParse->nErr || db->mallocFailed ){ - goto whereBeginError; - } - if( nTabList ){ - pLevel--; - pWInfo->nOBSat = pLevel->plan.nOBSat; - }else{ - pWInfo->nOBSat = 0; - } - - /* If the total query only selects a single row, then the ORDER BY - ** clause is irrelevant. - */ - if( (andFlags & WHERE_UNIQUE)!=0 && pOrderBy ){ - assert( nTabList==0 || (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ); - pWInfo->nOBSat = pOrderBy->nExpr; - } - +#if 0 /* FIXME: Add this back in? */ /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. ** The one-pass algorithm only works if the WHERE clause constraints @@ -6754,16 +5164,6 @@ WhereInfo *sqlite3WhereBegin( pWInfo->okOnePass = 1; pWInfo->a[0].plan.wsFlags &= ~WHERE_IDX_ONLY; } - -#if 1 - /* Scaffolding: Check the new query plan against the old. Report any - ** discrepencies */ - for(ii=0; iia[ii].iFrom!=pWInfo->a[ii].pWLoop->iTab ){ - sqlite3DebugPrintf("(QP-Mismatch)"); - break; - } - } #endif /* Open all tables in the pTabList and any indices selected for @@ -6776,16 +5176,17 @@ WhereInfo *sqlite3WhereBegin( Table *pTab; /* Table to open */ int iDb; /* Index of database containing table/index */ struct SrcList_item *pTabItem; + WhereLoop *pLoop; pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; - pWInfo->nRowOut *= pLevel->plan.nRow; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + pLoop = pLevel->pWLoop; if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){ /* Do nothing */ }else #ifndef SQLITE_OMIT_VIRTUALTABLE - if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){ + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); int iCur = pTabItem->iCursor; sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB); @@ -6793,7 +5194,7 @@ WhereInfo *sqlite3WhereBegin( /* noop */ }else #endif - if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 + if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); @@ -6811,14 +5212,16 @@ WhereInfo *sqlite3WhereBegin( sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX - if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){ + if( (pLoop->wsFlags & WHERE_TEMP_INDEX)!=0 ){ constructAutomaticIndex(pParse, sWBI.pWC, pTabItem, notReady, pLevel); }else #endif - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){ - Index *pIx = pLevel->plan.u.pIdx; + if( pLoop->u.btree.pIndex!=0 ){ + Index *pIx = pLoop->u.btree.pIndex; KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx); - int iIndexCur = pLevel->iIdxCur; + /* FIXME: Might need to be the iIdxCur parameter. As an optimization + ** use pTabItem->iCursor if WHERE_IDX_ONLY */ + int iIndexCur = pLevel->iIdxCur = pParse->nTab++; assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); sqlite3VdbeAddOp4(v, OP_OpenRead, iIndexCur, pIx->tnum, iDb, @@ -6843,7 +5246,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->iContinue = pLevel->addrCont; } -#ifdef SQLITE_TEST /* For testing and debugging use only */ +#if defined(SQLITE_TEST) && 0 /* For testing and debugging use only */ /* Record in the query plan information about the current table ** and the index used to access it (if any). If the table itself ** is not used, its name is just '{}'. If no index is used @@ -6919,6 +5322,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ Vdbe *v = pParse->pVdbe; int i; WhereLevel *pLevel; + WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; @@ -6927,12 +5331,13 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3ExprCacheClear(pParse); for(i=pWInfo->nLevel-1; i>=0; i--){ pLevel = &pWInfo->a[i]; + pLoop = pLevel->pWLoop; sqlite3VdbeResolveLabel(v, pLevel->addrCont); if( pLevel->op!=OP_Noop ){ sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2); sqlite3VdbeChangeP5(v, pLevel->p5); } - if( pLevel->plan.wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ + if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); @@ -6947,9 +5352,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ if( pLevel->iLeftJoin ){ int addr; addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); - assert( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 - || (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ); - if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){ + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 + || (pLoop->wsFlags & WHERE_INDEXED)!=0 ); + if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor); } if( pLevel->iIdxCur>=0 ){ @@ -6977,15 +5382,16 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); + pLoop = pLevel->pWLoop; if( (pTab->tabFlags & TF_Ephemeral)==0 && pTab->pSelect==0 && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ - int ws = pLevel->plan.wsFlags; + int ws = pLoop->wsFlags; if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } - if( (ws & WHERE_INDEXED)!=0 && (ws & WHERE_TEMP_INDEX)==0 ){ + if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_TEMP_INDEX))==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); } } @@ -7003,12 +5409,12 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** that reference the table and converts them into opcodes that ** reference the index. */ - if( pLevel->plan.wsFlags & WHERE_INDEXED ){ - pIdx = pLevel->plan.u.pIdx; - }else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){ + if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ + pIdx = pLoop->u.btree.pIndex; + }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ pIdx = pLevel->u.pCovidx; } - if( pIdx && !db->mallocFailed){ + if( pIdx && !db->mallocFailed ){ int k, j, last; VdbeOp *pOp; @@ -7024,8 +5430,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ break; } } - assert( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 - || jnColumn ); + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || jnColumn ); }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; pOp->opcode = OP_IdxRowid; From 70bdcc738e6cf06cd68bdfdf7322f8412703d325 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 May 2013 19:28:34 +0000 Subject: [PATCH 040/144] The expected result in a test case can be of the form "*glob*" or "~*glob*" to match or not match the GLOB pattern. This is useful for matching EXPLAIN QUERY PLAN output that contains regular expression syntax characters like "?", "(", and ")". FossilOrigin-Name: a3b4e261bd7e278f150872cce7b020af5ad8d2ed --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/tester.tcl | 13 +++++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 7344d1b38d..e5e6cf6db7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Cut\sover\sthe\sNGQP\squery\splanner.\s\sRemove\slots\sof\slegacy\scode.\s\s\nThis\scheck-in\scompiles\sbut\sdoes\snot\swork.\s\sThe\stest\ssuite\sgets\sincorrect\nanswers\sand\scrashes. -D 2013-05-30T17:43:19.293 +C The\sexpected\sresult\sin\sa\stest\scase\scan\sbe\sof\sthe\sform\s"*glob*"\sor\s"~*glob*"\sto\s\nmatch\sor\snot\smatch\sthe\sGLOB\spattern.\s\sThis\sis\suseful\sfor\smatching\nEXPLAIN\sQUERY\sPLAN\soutput\sthat\scontains\sregular\sexpression\ssyntax\scharacters\nlike\s"?",\s"(",\sand\s")". +D 2013-05-30T19:28:34.431 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -806,7 +806,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d -F test/tester.tcl 693700993b7e0a5b7b2171b291a54cdbad1d86ff +F test/tester.tcl 63b24679c75a952c51f924de2802b2b57cddd22d F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P aebe1f2603ee04d792af73aaf59625bda99d5cd1 -R cdb9a6b0104d69931bfa04869e682c85 +P 001539df4b74dc1cbceb010a91407003ab4d8735 +R ae73b581603fe5cb9a5fdce5dbec1c53 U drh -Z 36d07876c5b50e19bee990a15e1431a7 +Z 68529a7f58c35b9a5dca06d2c9973260 diff --git a/manifest.uuid b/manifest.uuid index ea56fcb1ab..08e57409dd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -001539df4b74dc1cbceb010a91407003ab4d8735 \ No newline at end of file +a3b4e261bd7e278f150872cce7b020af5ad8d2ed \ No newline at end of file diff --git a/test/tester.tcl b/test/tester.tcl index cad9807ed7..32dca4cb78 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -551,6 +551,9 @@ proc do_test {name cmd expected} { fail_test $name } else { if {[regexp {^~?/.*/$} $expected]} { + # "expected" is of the form "/PATTERN/" then the result if correct if + # regular expression PATTERN matches the result. "~/PATTERN/" means + # the regular expression must not match. if {[string index $expected 0]=="~"} { set re [string map {# {[-0-9.]+}} [string range $expected 2 end-1]] set ok [expr {![regexp $re $result]}] @@ -558,6 +561,16 @@ proc do_test {name cmd expected} { set re [string map {# {[-0-9.]+}} [string range $expected 1 end-1]] set ok [regexp $re $result] } + } elseif {[regexp {^~?\*.*\*$} $expected]} { + # "expected" is of the form "*GLOB*" then the result if correct if + # glob pattern GLOB matches the result. "~/GLOB/" means + # the glob must not match. + if {[string index $expected 0]=="~"} { + set e [string range $expected 1 end] + set ok [expr {![string match $e $result]}] + } else { + set ok [string match $expected $result] + } } else { set ok [expr {[string compare $result $expected]==0}] } From 6fa978dade88b77ca42657b6b433f1fe55e8f798 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 May 2013 19:29:19 +0000 Subject: [PATCH 041/144] Futher simplifications to the NGQP. Fix some test cases to use EXPLAIN QUERY PLAN rather than the (now obsolete) sqlite_query_plan global variable. FossilOrigin-Name: ae985db4fa08b5efbef5a834e852f0b05101264b --- manifest | 16 +++--- manifest.uuid | 2 +- src/test1.c | 9 +-- src/where.c | 142 +++++++++++------------------------------------- test/where.test | 49 ++++++++--------- 5 files changed, 70 insertions(+), 148 deletions(-) diff --git a/manifest b/manifest index e5e6cf6db7..b536417138 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sexpected\sresult\sin\sa\stest\scase\scan\sbe\sof\sthe\sform\s"*glob*"\sor\s"~*glob*"\sto\s\nmatch\sor\snot\smatch\sthe\sGLOB\spattern.\s\sThis\sis\suseful\sfor\smatching\nEXPLAIN\sQUERY\sPLAN\soutput\sthat\scontains\sregular\sexpression\ssyntax\scharacters\nlike\s"?",\s"(",\sand\s")". -D 2013-05-30T19:28:34.431 +C Futher\ssimplifications\sto\sthe\sNGQP.\s\sFix\ssome\stest\scases\sto\suse\nEXPLAIN\sQUERY\sPLAN\srather\sthan\sthe\s(now\sobsolete)\ssqlite_query_plan\nglobal\svariable. +D 2013-05-30T19:29:19.963 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -225,7 +225,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c 2ecec9937e69bc17560ad886da35195daa7261b8 -F src/test1.c 6d2a340eea1d866bf7059894491652a69a7ee802 +F src/test1.c 5f9837aee1a0708ab2dbf67ce0b9c18e658cd36b F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 296baae1cbfd99527d8c87f9773a6c98116f6b8a +F src/where.c 3e9b7b3323f78ec3056c5e3aa3443661bc590054 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1028,7 +1028,7 @@ F test/walro.test a31deb621033442a76c3a61e44929250d06f81b1 F test/walshared.test 6dda2293880c300baf5d791c307f653094585761 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e -F test/where.test 15ac8611c9439a2c5f4a6ac10cfe4c1ec9854c24 +F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81 F test/where2.test 399b3178289925a0aa976b3d60ef139740540ecd F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 001539df4b74dc1cbceb010a91407003ab4d8735 -R ae73b581603fe5cb9a5fdce5dbec1c53 +P a3b4e261bd7e278f150872cce7b020af5ad8d2ed +R b028bf2657ab598aee5d4698a0488fdc U drh -Z 68529a7f58c35b9a5dca06d2c9973260 +Z 3432943259d0f5aa9c669ba0e80caf85 diff --git a/manifest.uuid b/manifest.uuid index 08e57409dd..bdeb520d01 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a3b4e261bd7e278f150872cce7b020af5ad8d2ed \ No newline at end of file +ae985db4fa08b5efbef5a834e852f0b05101264b \ No newline at end of file diff --git a/src/test1.c b/src/test1.c index bd6d4a4cfd..8edaedab8a 100644 --- a/src/test1.c +++ b/src/test1.c @@ -6302,8 +6302,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3WalTrace; #endif #ifdef SQLITE_TEST - extern char sqlite3_query_plan[]; - static char *query_plan = sqlite3_query_plan; #ifdef SQLITE_ENABLE_FTS3 extern int sqlite3_fts3_enable_parentheses; #endif @@ -6357,8 +6355,11 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ (char*)&sqlite3_os_type, TCL_LINK_INT); #endif #ifdef SQLITE_TEST - Tcl_LinkVar(interp, "sqlite_query_plan", - (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY); + { + static const char *query_plan = "*** OBSOLETE VARIABLE ***"; + Tcl_LinkVar(interp, "sqlite_query_plan", + (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY); + } #endif #ifdef SQLITE_DEBUG Tcl_LinkVar(interp, "sqlite_where_trace", diff --git a/src/where.c b/src/where.c index a9a431ba9a..8ddbd5d72b 100644 --- a/src/where.c +++ b/src/where.c @@ -326,33 +326,22 @@ struct WhereLoopBuilder { ** WhereLevel.wsFlags. These flags determine which search ** strategies are appropriate. */ -#define WHERE_ROWID_EQ 0x00000001 /* rowid=EXPR or rowid IN (...) */ -#define WHERE_ROWID_RANGE 0x00000002 /* rowidEXPR */ -#define WHERE_NULL_OK 0x00000004 /* Ok to use WO_ISNULL */ -#define WHERE_IPK 0x00000008 /* x is the INTEGER PRIMARY KEY */ -#define WHERE_COLUMN_EQ 0x00000010 /* x=EXPR or x IN (...) or x IS NULL */ -#define WHERE_COLUMN_RANGE 0x00000020 /* xEXPR */ -#define WHERE_COLUMN_IN 0x00000040 /* x IN (...) */ -#define WHERE_COLUMN_NULL 0x00000080 /* x IS NULL */ -#define WHERE_INDEXED 0x000000f0 /* Anything that uses an index */ -#define WHERE_NOT_FULLSCAN 0x000200f3 /* Does not do a full table scan */ -#define WHERE_IN_ABLE 0x000100f1 /* Able to support an IN operator */ -#define WHERE_TOP_LIMIT 0x00000100 /* xEXPR or x>=EXPR constraint */ -#define WHERE_BOTH_LIMIT 0x00000300 /* Both x>EXPR and xEXPR */ +#define WHERE_COLUMN_IN 0x00000004 /* x IN (...) */ +#define WHERE_COLUMN_NULL 0x00000008 /* x IS NULL */ +#define WHERE_TOP_LIMIT 0x00000010 /* xEXPR or x>=EXPR constraint */ +#define WHERE_BOTH_LIMIT 0x00000030 /* Both x>EXPR and xiTable; sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); - assert( pLoop->wsFlags & WHERE_IN_ABLE ); + assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } @@ -3193,7 +3183,8 @@ static Bitmask codeOneLoopStart( sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); } - }else if( pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ|WHERE_IDX_ONLY) ){ + }else if( pLoop->wsFlags & (WHERE_COLUMN_RANGE | WHERE_COLUMN_NULL | + WHERE_COLUMN_EQ | WHERE_IDX_ONLY) ){ /* Case 4: A scan using an index. ** ** The WHERE clause may contain zero or more equality @@ -3746,18 +3737,6 @@ static Bitmask codeOneLoopStart( return newNotReady; } -#if defined(SQLITE_TEST) -/* -** The following variable holds a text description of query plan generated -** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin -** overwrites the previous. This information is used for testing and -** analysis only. -*/ -char sqlite3_query_plan[BMS*2*40]; /* Text of the join */ -static int nQPlan = 0; /* Next free slow in _query_plan[] */ - -#endif /* SQLITE_TEST */ - #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes @@ -3793,7 +3772,7 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ sqlite3DebugPrintf(" %-15s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" fg %08x N %d", p->wsFlags, p->nTerm); + sqlite3DebugPrintf(" fg %05x N %d", p->wsFlags, p->nTerm); sqlite3DebugPrintf(" cost %.2g,%.2g,%.2g\n", p->prereq, p->rSetup, p->rRun, p->nOut); } @@ -3810,6 +3789,10 @@ static void whereLoopClear(sqlite3 *db, WhereLoop *p){ if( p->u.vtab.needFree ) sqlite3_free(p->u.vtab.idxStr); p->u.vtab.needFree = 0; p->u.vtab.idxStr = 0; + }else if( (p->wsFlags & WHERE_TEMP_INDEX)!=0 && p->u.btree.pIndex!=0 ){ + sqlite3DbFree(db, p->u.btree.pIndex->zColAff); + sqlite3DbFree(db, p->u.btree.pIndex); + p->u.btree.pIndex = 0; } } @@ -3826,16 +3809,6 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ */ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ if( ALWAYS(pWInfo) ){ - int i; - for(i=0; inLevel; i++){ - if( pWInfo->a[i].pWLoop->wsFlags & WHERE_TEMP_INDEX ){ - Index *pIdx = pWInfo->a[i].pWLoop->u.btree.pIndex; - if( pIdx ){ - sqlite3DbFree(db, pIdx->zColAff); - sqlite3DbFree(db, pIdx); - } - } - } whereClauseClear(pWInfo->pWC); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; @@ -4026,10 +3999,14 @@ static int whereLoopAddBtreeIndex( } pNew->u.btree.nEq++; pNew->nOut = (double)iRowEst * nInMul * nIn; - }else if( pTerm->eOperator & (WO_EQ|WO_ISNULL) ){ + }else if( pTerm->eOperator & (WO_EQ) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; pNew->u.btree.nEq++; pNew->nOut = (double)iRowEst * nInMul; + }else if( pTerm->eOperator & (WO_ISNULL) ){ + pNew->wsFlags |= WHERE_COLUMN_NULL; + pNew->u.btree.nEq++; + pNew->nOut = (double)iRowEst * nInMul; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pNew->nOut = savedLoop.nOut/3; @@ -4197,7 +4174,7 @@ static int whereLoopAddBtree( m &= ~(((Bitmask)1)<wsFlags = (m==0) ? WHERE_IDX_ONLY : 0; + pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; /* Full scan via index */ if( (m==0 || b) && pProbe->bUnordered==0 ){ @@ -5246,62 +5223,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->iContinue = pLevel->addrCont; } -#if defined(SQLITE_TEST) && 0 /* For testing and debugging use only */ - /* Record in the query plan information about the current table - ** and the index used to access it (if any). If the table itself - ** is not used, its name is just '{}'. If no index is used - ** the index is listed as "{}". If the primary key is used the - ** index name is '*'. - */ - for(ii=0; iia[ii]; - w = pLevel->plan.wsFlags; - pTabItem = &pTabList->a[pLevel->iFrom]; - z = pTabItem->zAlias; - if( z==0 ) z = pTabItem->pTab->zName; - n = sqlite3Strlen30(z); - if( n+nQPlan < sizeof(sqlite3_query_plan)-10 ){ - if( (w & WHERE_IDX_ONLY)!=0 && (w & WHERE_COVER_SCAN)==0 ){ - memcpy(&sqlite3_query_plan[nQPlan], "{}", 2); - nQPlan += 2; - }else{ - memcpy(&sqlite3_query_plan[nQPlan], z, n); - nQPlan += n; - } - sqlite3_query_plan[nQPlan++] = ' '; - } - testcase( w & WHERE_ROWID_EQ ); - testcase( w & WHERE_ROWID_RANGE ); - if( w & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){ - memcpy(&sqlite3_query_plan[nQPlan], "* ", 2); - nQPlan += 2; - }else if( (w & WHERE_INDEXED)!=0 && (w & WHERE_COVER_SCAN)==0 ){ - n = sqlite3Strlen30(pLevel->plan.u.pIdx->zName); - if( n+nQPlan < sizeof(sqlite3_query_plan)-2 ){ - memcpy(&sqlite3_query_plan[nQPlan], pLevel->plan.u.pIdx->zName, n); - nQPlan += n; - sqlite3_query_plan[nQPlan++] = ' '; - } - }else{ - memcpy(&sqlite3_query_plan[nQPlan], "{} ", 3); - nQPlan += 3; - } - } - while( nQPlan>0 && sqlite3_query_plan[nQPlan-1]==' ' ){ - sqlite3_query_plan[--nQPlan] = 0; - } - sqlite3_query_plan[nQPlan] = 0; - nQPlan = 0; -#endif /* SQLITE_TEST // Testing and debugging use only */ - - /* Record the continuation address in the WhereInfo structure. Then - ** clean up and return. - */ + /* Done. */ return pWInfo; /* Jump here if malloc fails */ diff --git a/test/where.test b/test/where.test index 2dbc283417..8610fa6f3d 100644 --- a/test/where.test +++ b/test/where.test @@ -65,9 +65,9 @@ proc count sql { do_test where-1.1.1 { count {SELECT x, y, w FROM t1 WHERE w=10} } {3 121 10 3} -do_test where-1.1.2 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.1.2 { + SELECT x, y, w FROM t1 WHERE w=10 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} do_test where-1.1.3 { db status step } {0} @@ -77,15 +77,15 @@ do_test where-1.1.4 { do_test where-1.1.5 { db status step } {99} -do_test where-1.1.6 { - set sqlite_query_plan -} {t1 {}} +do_eqp_test where-1.1.6 { + SELECT x, y, w FROM t1 WHERE +w=10 +} {*SCAN TABLE t1 *} do_test where-1.1.7 { count {SELECT x, y, w AS abc FROM t1 WHERE abc=10} } {3 121 10 3} -do_test where-1.1.8 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.1.8 { + SELECT x, y, w AS abc FROM t1 WHERE abc=10 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} do_test where-1.1.9 { db status step } {0} @@ -104,21 +104,21 @@ do_test where-1.3.2 { do_test where-1.4.1 { count {SELECT w, x, y FROM t1 WHERE 11=w AND x>2} } {11 3 144 3} -do_test where-1.4.2 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.4.2 { + SELECT w, x, y FROM t1 WHERE 11=w AND x>2 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} do_test where-1.4.3 { count {SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2} } {11 3 144 3} -do_test where-1.4.4 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.4.4 { + SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} do_test where-1.5 { count {SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2} } {3 144 3} -do_test where-1.5.2 { - set sqlite_query_plan -} {t1 i1w} +do_eqp_test where-1.5.2 { + SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2 +} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} do_test where-1.6 { count {SELECT x, y FROM t1 WHERE y<200 AND x>2 AND w=11} } {3 144 3} @@ -128,13 +128,12 @@ do_test where-1.7 { do_test where-1.8 { count {SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3} } {3 144 3} -do_test where-1.8.2 { - set sqlite_query_plan -} {t1 i1xy} -do_test where-1.8.3 { - count {SELECT x, y FROM t1 WHERE y=144 AND x=3} - set sqlite_query_plan -} {{} i1xy} +do_eqp_test where-1.8.2 { + SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3 +} {*SEARCH TABLE t1 USING INDEX i1xy (x=? AND y=?) *} +do_eqp_test where-1.8.3 { + SELECT x, y FROM t1 WHERE y=144 AND x=3 +} {*SEARCH TABLE t1 USING COVERING INDEX i1xy (x=? AND y=?) *} do_test where-1.9 { count {SELECT x, y FROM t1 WHERE y=144 AND w>10 AND x=3} } {3 144 3} From 1b0f026dbb0fe56141cb198a2722d42c7be75cb2 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 May 2013 22:27:09 +0000 Subject: [PATCH 042/144] Incremental check-in with various NGQP fixes. Many tests still fail. FossilOrigin-Name: a51d8c92496436488e1a6eabd85785e8fedf2736 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 23 +++++++++++++++++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index b536417138..e2d80171bf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Futher\ssimplifications\sto\sthe\sNGQP.\s\sFix\ssome\stest\scases\sto\suse\nEXPLAIN\sQUERY\sPLAN\srather\sthan\sthe\s(now\sobsolete)\ssqlite_query_plan\nglobal\svariable. -D 2013-05-30T19:29:19.963 +C Incremental\scheck-in\swith\svarious\sNGQP\sfixes.\s\sMany\stests\sstill\sfail. +D 2013-05-30T22:27:09.004 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 3e9b7b3323f78ec3056c5e3aa3443661bc590054 +F src/where.c 28e0cefe34698b6de4e6f5484cd987ae993c49f2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P a3b4e261bd7e278f150872cce7b020af5ad8d2ed -R b028bf2657ab598aee5d4698a0488fdc +P ae985db4fa08b5efbef5a834e852f0b05101264b +R 5e6d0ab71af5f0e6d4eac06636af5d1b U drh -Z 3432943259d0f5aa9c669ba0e80caf85 +Z 130160475bcddf72f5447461f586642a diff --git a/manifest.uuid b/manifest.uuid index bdeb520d01..22be55a88a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ae985db4fa08b5efbef5a834e852f0b05101264b \ No newline at end of file +a51d8c92496436488e1a6eabd85785e8fedf2736 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 8ddbd5d72b..5663e68491 100644 --- a/src/where.c +++ b/src/where.c @@ -3183,8 +3183,7 @@ static Bitmask codeOneLoopStart( sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); } - }else if( pLoop->wsFlags & (WHERE_COLUMN_RANGE | WHERE_COLUMN_NULL | - WHERE_COLUMN_EQ | WHERE_IDX_ONLY) ){ + }else if( pLoop->wsFlags & WHERE_INDEXED ){ /* Case 4: A scan using an index. ** ** The WHERE clause may contain zero or more equality @@ -3425,7 +3424,8 @@ static Bitmask codeOneLoopStart( pLevel->op = OP_Next; } pLevel->p1 = iIdxCur; - if( pLoop->wsFlags & WHERE_COVER_SCAN ){ + if( (pLoop->wsFlags & (WHERE_COLUMN_EQ | WHERE_COLUMN_RANGE | + WHERE_COLUMN_NULL | WHERE_COLUMN_IN))==0 ){ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; }else{ assert( pLevel->p5==0 ); @@ -3875,6 +3875,18 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ */ for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ) continue; + if( p->nTermnTerm + && (p->wsFlags & WHERE_INDEXED)!=0 + && (pTemplate->wsFlags & WHERE_INDEXED)!=0 + && p->u.btree.pIndex==pTemplate->u.btree.pIndex + && p->prereq==pTemplate->prereq + ){ + /* Overwrite an existing WhereLoop with an similar one that uses + ** more terms of the index */ + pNext = p->pNextLoop; + whereLoopClear(db, p); + break; + } if( (p->prereq & pTemplate->prereq)==p->prereq && p->rSetup<=pTemplate->rSetup && p->rRun<=pTemplate->rRun @@ -4590,7 +4602,10 @@ static int wherePathSatisfiesOrderBy( iColumn = -1; revIdx = 0; } - if( pOBExpr->iColumn!=iColumn ) return 0; + if( pOBExpr->iColumn!=iColumn ){ + if( ju.btree.nEq ){ nUsed--; continue; } + return 0; + } if( iColumn>=0 ){ pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[nUsed].pExpr); if( !pColl ) pColl = db->pDfltColl; From dc3cd4b0208efa1f0b2ac78bd417cf511b510e2d Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 May 2013 23:21:20 +0000 Subject: [PATCH 043/144] Improvements to the ORDER BY suppressor in the NGQP. FossilOrigin-Name: 24a2e9ddcecd3926817d77abbb75d068ee7140ad --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 20 +++++++++++++------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index e2d80171bf..f227274658 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Incremental\scheck-in\swith\svarious\sNGQP\sfixes.\s\sMany\stests\sstill\sfail. -D 2013-05-30T22:27:09.004 +C Improvements\sto\sthe\sORDER\sBY\ssuppressor\sin\sthe\sNGQP. +D 2013-05-30T23:21:20.132 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 28e0cefe34698b6de4e6f5484cd987ae993c49f2 +F src/where.c 38beadcfdf477b0f9a07c4d0a479ab522843b14c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ae985db4fa08b5efbef5a834e852f0b05101264b -R 5e6d0ab71af5f0e6d4eac06636af5d1b +P a51d8c92496436488e1a6eabd85785e8fedf2736 +R 405146591851ecbfbac166e3c1b2db18 U drh -Z 130160475bcddf72f5447461f586642a +Z 4964f74ab7b0cf98172fb87fb30a1333 diff --git a/manifest.uuid b/manifest.uuid index 22be55a88a..ee070b19f5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a51d8c92496436488e1a6eabd85785e8fedf2736 \ No newline at end of file +24a2e9ddcecd3926817d77abbb75d068ee7140ad \ No newline at end of file diff --git a/src/where.c b/src/where.c index 5663e68491..9d454bc80c 100644 --- a/src/where.c +++ b/src/where.c @@ -4588,6 +4588,7 @@ static int wherePathSatisfiesOrderBy( j = 0; revSet = rev = 0; for(j=0; j<=nColumn && nUseda[nUsed].pExpr); assert( pOBExpr->op==TK_COLUMN ); if( pOBExpr->iTable!=iCur ) break; @@ -4602,20 +4603,25 @@ static int wherePathSatisfiesOrderBy( iColumn = -1; revIdx = 0; } + skipable = ju.btree.nEq && pLoop->aTerm[j]->eOperator!=WO_IN; if( pOBExpr->iColumn!=iColumn ){ - if( ju.btree.nEq ){ nUsed--; continue; } + if( skipable ){ nUsed--; continue; } return 0; } if( iColumn>=0 ){ pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[nUsed].pExpr); if( !pColl ) pColl = db->pDfltColl; - if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) return 0; + if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ){ + return 0; + } } - if( revSet ){ - if( (rev ^ revIdx)!=pOrderBy->a[nUsed].sortOrder ) return 0; - }else{ - rev = revIdx ^ pOrderBy->a[nUsed].sortOrder; - revSet = 1; + if( !skipable ){ + if( revSet ){ + if( (rev ^ revIdx)!=pOrderBy->a[nUsed].sortOrder ) return 0; + }else{ + rev = revIdx ^ pOrderBy->a[nUsed].sortOrder; + revSet = 1; + } } } if( rev ) revMask |= ((Bitmask)1)< Date: Fri, 31 May 2013 11:57:39 +0000 Subject: [PATCH 044/144] Fix the constructAutomaticIndex() routine so that it works with NGQP. FossilOrigin-Name: 5e1e61399513b4a95fd93df2377a2603f1670063 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 12 +++++++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index f227274658..dbb58ea9b3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\sthe\sORDER\sBY\ssuppressor\sin\sthe\sNGQP. -D 2013-05-30T23:21:20.132 +C Fix\sthe\sconstructAutomaticIndex()\sroutine\sso\sthat\sit\sworks\swith\sNGQP. +D 2013-05-31T11:57:39.405 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 38beadcfdf477b0f9a07c4d0a479ab522843b14c +F src/where.c 530dd22d4f803747e964edcb052d699c4c92e1a1 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P a51d8c92496436488e1a6eabd85785e8fedf2736 -R 405146591851ecbfbac166e3c1b2db18 +P 24a2e9ddcecd3926817d77abbb75d068ee7140ad +R 92deaa75392a3f586cae6bde8f65a470 U drh -Z 4964f74ab7b0cf98172fb87fb30a1333 +Z 293d3cdab228aa747c73a2994c326e63 diff --git a/manifest.uuid b/manifest.uuid index ee070b19f5..57b2c0e51a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -24a2e9ddcecd3926817d77abbb75d068ee7140ad \ No newline at end of file +5e1e61399513b4a95fd93df2377a2603f1670063 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 9d454bc80c..dea0ff2fdd 100644 --- a/src/where.c +++ b/src/where.c @@ -1850,6 +1850,7 @@ static void constructAutomaticIndex( WhereLoop *pLoop; /* The Loop object */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ + const int mxConstraint = 10; /* Maximum number of constraints */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ @@ -1864,20 +1865,25 @@ static void constructAutomaticIndex( pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; - for(pTerm=pWC->a; pTermaTerm = sqlite3DbRealloc(pParse->db, pLoop->aTerm, + mxConstraint*sizeof(pLoop->aTerm[0])); + if( pLoop->aTerm==0 ) return; + for(pTerm=pWC->a; pTermnTermu.leftColumn; Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<aTerm[nColumn++] = pTerm; idxCols |= cMask; } } } assert( nColumn>0 ); - pLoop->u.btree.nEq = nColumn; + pLoop->u.btree.nEq = pLoop->nTerm = nColumn; + pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED + | WHERE_TEMP_INDEX; /* Count the number of additional columns needed to create a ** covering index. A "covering index" is an index that contains all From d044d209f3535e4a514dd9bbad7000e4432e685e Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 12:43:55 +0000 Subject: [PATCH 045/144] Improved detection of unnecessary ORDER BY clauses. FossilOrigin-Name: 58805eb36b9975706e2c4e382689519454e9a504 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 35 ++++++++++++++++++++++------------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index dbb58ea9b3..edf228f872 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sconstructAutomaticIndex()\sroutine\sso\sthat\sit\sworks\swith\sNGQP. -D 2013-05-31T11:57:39.405 +C Improved\sdetection\sof\sunnecessary\sORDER\sBY\sclauses. +D 2013-05-31T12:43:55.143 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 530dd22d4f803747e964edcb052d699c4c92e1a1 +F src/where.c 0e1c41804f89dbfd48fbe8dfa68adc6b6d682a75 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 24a2e9ddcecd3926817d77abbb75d068ee7140ad -R 92deaa75392a3f586cae6bde8f65a470 +P 5e1e61399513b4a95fd93df2377a2603f1670063 +R 17288f799b200fcc6199a08359305634 U drh -Z 293d3cdab228aa747c73a2994c326e63 +Z 9542ccfa5fa5ec11248b1f41f8b389ee diff --git a/manifest.uuid b/manifest.uuid index 57b2c0e51a..ec86401b40 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5e1e61399513b4a95fd93df2377a2603f1670063 \ No newline at end of file +58805eb36b9975706e2c4e382689519454e9a504 \ No newline at end of file diff --git a/src/where.c b/src/where.c index dea0ff2fdd..249cc724b1 100644 --- a/src/where.c +++ b/src/where.c @@ -3832,7 +3832,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** is better and has fewer dependencies. Or the template will be ignored ** and no insert will occur if an existing WhereLoop is faster and has ** fewer dependencies than the template. Otherwise a new WhereLoop is -** added based no the template. +** added based on the template. ** ** If pBuilder->pBest is not NULL then we only care about the very ** best template and that template should be stored in pBuilder->pBest. @@ -3848,6 +3848,8 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** (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, *pToFree = 0; @@ -4100,7 +4102,7 @@ static int whereLoopAddBtree( struct SrcList_item *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ - int iSortIdx = 0; /* Index number */ + int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ double rSize; /* number of rows in the table */ double rLogSize; /* Logarithm of the number of rows in the table */ @@ -4179,6 +4181,7 @@ static int whereLoopAddBtree( pNew->wsFlags = WHERE_IPK; /* Full table scan */ + pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; pNew->rRun = (rSize + rLogSize)*(3+b); /* 4x penalty for a full-scan */ rc = whereLoopInsert(pBuilder, pNew); @@ -4513,8 +4516,9 @@ static int wherePathSatisfiesOrderBy( u8 revSet; /* True if rev is known */ u8 rev; /* Composite sort order */ u8 revIdx; /* Index sort order */ - u8 isUnique; - u8 requireUnique = 0; + u8 isOneRow; /* Current WhereLoop is a one-row loop */ + u8 requireOneRow = 0; /* All subsequent loops must be one-row */ + u8 isUniqueIdx; /* Current WhereLoop uses a unique index */ u16 nColumn; u16 nOrderBy; int i, j; @@ -4547,6 +4551,10 @@ static int wherePathSatisfiesOrderBy( ** of the index. ** ** (4) Index columns past nEq must match ORDER BY terms one-for-one. + ** + ** (5) If all columns of a UNIQUE index have been matched against ORDER BY + ** terms, then any subsequent entries in the ORDER BY clause against the + ** same table can be skipped. */ assert( pOrderBy!=0 ); @@ -4569,10 +4577,10 @@ static int wherePathSatisfiesOrderBy( for(i=0; i<=nLoop && nUsedaLoop[i] : pLast; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); - isUnique = 1; + isOneRow = isUniqueIdx = 1; if( pLoop->wsFlags & WHERE_IPK ){ - if( (pLoop->wsFlags & WHERE_COLUMN_IN)!=0 ) isUnique = 0; - if( pLoop->u.btree.nEq!=1 ) isUnique = 0; + if( (pLoop->wsFlags & WHERE_COLUMN_IN)!=0 ) isOneRow = 0; + if( pLoop->u.btree.nEq!=1 ) isOneRow = 0; pIndex = 0; nColumn = 0; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ @@ -4580,16 +4588,16 @@ static int wherePathSatisfiesOrderBy( }else{ nColumn = pIndex->nColumn; if( pIndex->onError==OE_None ){ - isUnique = 0; + isOneRow = isUniqueIdx = 0; }else if( (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_RANGE |WHERE_COLUMN_NULL))!=0 ){ - isUnique = 0; + isOneRow = 0; }else if( pLoop->u.btree.nEq < pIndex->nColumn ){ - isUnique = 0; + isOneRow = 0; } } - if( !isUnique && requireUnique ) return 0; - requireUnique = !isUnique; + if( !isOneRow && requireOneRow ) return 0; + requireOneRow = !isOneRow; iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; j = 0; revSet = rev = 0; @@ -4598,7 +4606,7 @@ static int wherePathSatisfiesOrderBy( pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[nUsed].pExpr); assert( pOBExpr->op==TK_COLUMN ); if( pOBExpr->iTable!=iCur ) break; - if( isUnique ) continue; + if( isOneRow ){ j--; continue; } if( jaiColumn[j]; @@ -4629,6 +4637,7 @@ static int wherePathSatisfiesOrderBy( revSet = 1; } } + if( j>=nColumn-1 && isUniqueIdx ){ j--; isOneRow = 1; } } if( rev ) revMask |= ((Bitmask)1)< Date: Fri, 31 May 2013 13:36:32 +0000 Subject: [PATCH 046/144] Futher enhancements to the ORDER BY optimizer. FossilOrigin-Name: d8efa5f8b60bc4c8df8bfad077f87f76f7ee9bf6 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 15 +++++++++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index edf228f872..24f702b1fb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sdetection\sof\sunnecessary\sORDER\sBY\sclauses. -D 2013-05-31T12:43:55.143 +C Futher\senhancements\sto\sthe\sORDER\sBY\soptimizer. +D 2013-05-31T13:36:32.993 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 0e1c41804f89dbfd48fbe8dfa68adc6b6d682a75 +F src/where.c 8e9922815b07290982cfc826497d128115ce358c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 5e1e61399513b4a95fd93df2377a2603f1670063 -R 17288f799b200fcc6199a08359305634 +P 58805eb36b9975706e2c4e382689519454e9a504 +R d753e9381f16048231d3d54f23e54ee3 U drh -Z 9542ccfa5fa5ec11248b1f41f8b389ee +Z 2bef9deff008e88de89f5b60b513bb1c diff --git a/manifest.uuid b/manifest.uuid index ec86401b40..0e1ff8e72f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -58805eb36b9975706e2c4e382689519454e9a504 \ No newline at end of file +d8efa5f8b60bc4c8df8bfad077f87f76f7ee9bf6 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 249cc724b1..d4f9a71441 100644 --- a/src/where.c +++ b/src/where.c @@ -4510,6 +4510,7 @@ static int wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ WherePath *pPath, /* The WherePath to check */ int nLoop, /* Number of entries in pPath->aLoop[] */ + int isLastLoop, /* True for the very last loop */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* Mask of WhereLoops to run in reverse order */ ){ @@ -4569,10 +4570,12 @@ static int wherePathSatisfiesOrderBy( /* Sorting is always required if any term of the ORDER BY is not a ** column reference */ nOrderBy = pOrderBy->nExpr; +#if 0 for(i=0; ia[i].pExpr); if( pOBExpr->op!=TK_COLUMN ) return 0; } +#endif for(i=0; i<=nLoop && nUsedaLoop[i] : pLast; @@ -4604,7 +4607,7 @@ static int wherePathSatisfiesOrderBy( for(j=0; j<=nColumn && nUseda[nUsed].pExpr); - assert( pOBExpr->op==TK_COLUMN ); + if( pOBExpr->op!=TK_COLUMN ) return 0; if( pOBExpr->iTable!=iCur ) break; if( isOneRow ){ j--; continue; } if( j=nColumn-1 && isUniqueIdx ){ j--; isOneRow = 1; } + if( j>=nColumn-1 && isUniqueIdx ){ + if( isLastLoop && i==nLoop ) break; + j--; + isOneRow = 1; + } } if( rev ) revMask |= ((Bitmask)1)<rSetup + pWLoop->rRun*pFrom->nRow + pFrom->rCost; maskNew = pFrom->maskLoop | pWLoop->maskSelf; if( !isOrderedValid ){ - switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, + switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, iLoop==nLoop-1, pWLoop, &revMask) ){ case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ isOrdered = 1; From 84f1414b1a5b89e33a31fb988e309f1ae906b0fb Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 14:31:11 +0000 Subject: [PATCH 047/144] Enhance the shell to provide more flexibility when entering numeric arguments on dot-commands. In particular, allow hex arguments to .wheretrace. FossilOrigin-Name: b9578c371ee569dca6a0964019959a93407c8ef9 --- manifest | 12 +++---- manifest.uuid | 2 +- src/shell.c | 88 ++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 73 insertions(+), 29 deletions(-) diff --git a/manifest b/manifest index 24f702b1fb..b3d407069e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Futher\senhancements\sto\sthe\sORDER\sBY\soptimizer. -D 2013-05-31T13:36:32.993 +C Enhance\sthe\sshell\sto\sprovide\smore\sflexibility\swhen\sentering\snumeric\sarguments\non\sdot-commands.\s\sIn\sparticular,\sallow\shex\sarguments\sto\s.wheretrace. +D 2013-05-31T14:31:11.784 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -216,7 +216,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 22ee971346a736ddefdc4497d07c92f2e9978afc -F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 +F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 58805eb36b9975706e2c4e382689519454e9a504 -R d753e9381f16048231d3d54f23e54ee3 +P d8efa5f8b60bc4c8df8bfad077f87f76f7ee9bf6 +R cab66f9edd3249c76db6815f19ee5773 U drh -Z 2bef9deff008e88de89f5b60b513bb1c +Z 93073f371b16237bef628d122f206ede diff --git a/manifest.uuid b/manifest.uuid index 0e1ff8e72f..277db05743 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d8efa5f8b60bc4c8df8bfad077f87f76f7ee9bf6 \ No newline at end of file +b9578c371ee569dca6a0964019959a93407c8ef9 \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index d5fa9c6963..9f2f46bd18 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1523,21 +1523,14 @@ static void resolve_backslashes(char *z){ } /* -** Interpret zArg as a boolean value. Return either 0 or 1. +** Return the value of a hexadecimal digit. Return -1 if the input +** is not a hex digit. */ -static int booleanValue(char *zArg){ - int i; - for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} - if( i>0 && zArg[i]==0 ) return atoi(zArg); - if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ - return 1; - } - if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ - return 0; - } - fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", - zArg); - return 0; +static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; } /* @@ -1564,9 +1557,18 @@ static sqlite3_int64 integerValue(const char *zArg){ }else if( zArg[0]=='+' ){ zArg++; } - while( IsDigit(zArg[0]) ){ - v = v*10 + zArg[0] - '0'; - zArg++; + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + v = (v<<4) + x; + zArg++; + } + }else{ + while( IsDigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } } for(i=0; i=0; i++){} + }else{ + for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} + } + if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff); + if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ + return 1; + } + if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ + return 0; + } + fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", + zArg); + return 0; +} + /* ** Close an output file, assuming it is not stderr or stdout */ @@ -1808,7 +1833,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ - if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc); + if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); rc = 2; }else @@ -2305,6 +2330,25 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else + /* Undocumented commands for internal testing. Subject to change + ** without notice. */ + if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ + if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ + int i, v; + for(i=1; iout, "%s: %d 0x%x\n", azArg[i], v, v); + } + } + if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ + int i; sqlite3_int64 v; + for(i=1; iout, "%s: %lld 0x%llx\n", azArg[i], v, v); + } + } + }else + if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sqlite3_snprintf(sizeof(p->separator), p->separator, "%.*s", (int)sizeof(p->separator)-1, azArg[1]); @@ -2458,7 +2502,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } } } - if( testctrl<0 ) testctrl = atoi(azArg[1]); + if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]); if( (testctrlSQLITE_TESTCTRL_LAST) ){ fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]); }else{ @@ -2505,7 +2549,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ case SQLITE_TESTCTRL_ASSERT: case SQLITE_TESTCTRL_ALWAYS: if( nArg==3 ){ - int opt = atoi(azArg[2]); + int opt = booleanValue(azArg[2]); rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { @@ -2542,7 +2586,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ open_db(p); - sqlite3_busy_timeout(p->db, atoi(azArg[1])); + sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1])); }else if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 @@ -2592,7 +2636,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; jcolWidth); j++){ - p->colWidth[j-1] = atoi(azArg[j]); + p->colWidth[j-1] = (int)integerValue(azArg[j]); } }else From ae70cf1816a537c0bbeee508a3b61accb28a2795 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 15:18:46 +0000 Subject: [PATCH 048/144] Allow tracing of whereLoopInsert() when the 0x8 bit is set on ".wheretrace". Remove the use of sqlite_query_plan from where2.test. Fix a bug in the code generator for OR clause optimizations. FossilOrigin-Name: 707f0323264c35be14847a6adc49a0dc5eaf4ad2 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 50 ++++++++++++++++++++++++++++++++++++------------ test/where2.test | 13 ++++++++++++- 4 files changed, 58 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index b3d407069e..535b2266fe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\sshell\sto\sprovide\smore\sflexibility\swhen\sentering\snumeric\sarguments\non\sdot-commands.\s\sIn\sparticular,\sallow\shex\sarguments\sto\s.wheretrace. -D 2013-05-31T14:31:11.784 +C Allow\stracing\sof\swhereLoopInsert()\swhen\sthe\s0x8\sbit\sis\sset\son\s".wheretrace".\nRemove\sthe\suse\sof\ssqlite_query_plan\sfrom\swhere2.test.\s\sFix\sa\sbug\sin\sthe\ncode\sgenerator\sfor\sOR\sclause\soptimizations. +D 2013-05-31T15:18:46.709 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 8e9922815b07290982cfc826497d128115ce358c +F src/where.c e120e28cb55cea658589ec2eca5764dcfa0396c2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1029,7 +1029,7 @@ F test/walshared.test 6dda2293880c300baf5d791c307f653094585761 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81 -F test/where2.test 399b3178289925a0aa976b3d60ef139740540ecd +F test/where2.test f902f62d60f20b0257dd700f0c4a2945527fca8e F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d8efa5f8b60bc4c8df8bfad077f87f76f7ee9bf6 -R cab66f9edd3249c76db6815f19ee5773 +P b9578c371ee569dca6a0964019959a93407c8ef9 +R 10e84b9c96bf0dc4179bf10aeea4849d U drh -Z 93073f371b16237bef628d122f206ede +Z 1f5041366a1e7c65f32184b30b5b84bc diff --git a/manifest.uuid b/manifest.uuid index 277db05743..f519953e67 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b9578c371ee569dca6a0964019959a93407c8ef9 \ No newline at end of file +707f0323264c35be14847a6adc49a0dc5eaf4ad2 \ No newline at end of file diff --git a/src/where.c b/src/where.c index d4f9a71441..6b4521b40a 100644 --- a/src/where.c +++ b/src/where.c @@ -3758,6 +3758,7 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ if( p->u.btree.pIndex ){ const char *zName = p->u.btree.pIndex->zName; + if( zName==0 ) zName = "ipk"; if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ int i = sqlite3Strlen30(zName) - 1; while( zName[i]!='_' ) i--; @@ -3865,16 +3866,22 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ if( (p = pBuilder->pBest)!=0 ){ if( p->maskSelf!=0 ){ if( p->rRun+p->rSetup < pTemplate->rRun+pTemplate->rSetup ){ - return SQLITE_OK; + goto whereLoopInsert_noop; } if( p->rRun+p->rSetup == pTemplate->rRun+pTemplate->rSetup && p->prereq <= pTemplate->prereq ){ - return SQLITE_OK; + goto whereLoopInsert_noop; } } *p = *pTemplate; p->aTerm = 0; p->u.vtab.needFree = 0; +#if WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf("ins-best: "); + whereLoopPrint(pTemplate, pBuilder->pTabList); + } +#endif return SQLITE_OK; } @@ -3901,7 +3908,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ){ /* Already holding an equal or better WhereLoop. ** Return without changing or adding anything */ - return SQLITE_OK; + goto whereLoopInsert_noop; } if( (p->prereq & pTemplate->prereq)==pTemplate->prereq && p->rSetup>=pTemplate->rSetup @@ -3918,6 +3925,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new ** WhereLoop and insert it. */ +#if WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x8 ){ + if( p!=0 ){ + sqlite3DebugPrintf("ins-del: "); + whereLoopPrint(p, pBuilder->pTabList); + } + sqlite3DebugPrintf("ins-new: "); + whereLoopPrint(pTemplate, pBuilder->pTabList); + } +#endif if( p==0 ){ p = pToFree = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; @@ -3945,6 +3962,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ pTemplate->u.vtab.needFree = 0; } return SQLITE_OK; + + /* Jump here if the insert is a no-op */ +whereLoopInsert_noop: +#if WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf("ins-noop: "); + whereLoopPrint(pTemplate, pBuilder->pTabList); + } +#endif + return SQLITE_OK; } /* @@ -4156,7 +4183,7 @@ static int whereLoopAddBtree( pNew->u.btree.pIndex = 0; pNew->nTerm = 1; pNew->aTerm[0] = pTerm; - pNew->rSetup = 2*rLogSize*pSrc->pTab->nRowEst; + pNew->rSetup = 20*rLogSize*pSrc->pTab->nRowEst; pNew->nOut = (double)10; pNew->rRun = rLogSize + pNew->nOut; pNew->wsFlags = WHERE_TEMP_INDEX; @@ -4773,8 +4800,8 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ } if( jj>=nTo ){ if( nTo>=mxChoice && rCost>=mxCost ){ -#ifdef WHERETRACE_ENABLE - if( sqlite3WhereTrace>=3 ){ +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("Skip %s cost=%-7.2g order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); @@ -4792,7 +4819,7 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ } pTo = &aTo[jj]; #ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace>=3 ){ + if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("New %s cost=%-7.2g order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); @@ -4801,7 +4828,7 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ }else{ if( pTo->rCost<=rCost ){ #ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace>=3 ){ + if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Skip %s cost=%-7.2g order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, @@ -4815,7 +4842,7 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ } /* A new and better score for a previously created equivalent path */ #ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace>=3 ){ + if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Update %s cost=%-7.2g order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, @@ -5239,9 +5266,8 @@ WhereInfo *sqlite3WhereBegin( if( pLoop->u.btree.pIndex!=0 ){ Index *pIx = pLoop->u.btree.pIndex; KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx); - /* FIXME: Might need to be the iIdxCur parameter. As an optimization - ** use pTabItem->iCursor if WHERE_IDX_ONLY */ - int iIndexCur = pLevel->iIdxCur = pParse->nTab++; + /* FIXME: As an optimization use pTabItem->iCursor if WHERE_IDX_ONLY */ + int iIndexCur = pLevel->iIdxCur = iIdxCur ? iIdxCur : pParse->nTab++; assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); sqlite3VdbeAddOp4(v, OP_OpenRead, iIndexCur, pIx->tnum, iDb, diff --git a/test/where2.test b/test/where2.test index e8c2f3613f..60937adcc5 100644 --- a/test/where2.test +++ b/test/where2.test @@ -73,7 +73,18 @@ proc queryplan {sql} { set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + lappend data $tab * + } + } + return $data + # return [concat $data $::sqlite_query_plan] } From 6dc8cbe0d4f3aa39eb744f940fbdcea0ede260d1 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 15:36:07 +0000 Subject: [PATCH 049/144] Improved handling of errors when doing run-time loading of an SQLite shared-library into TCL. FossilOrigin-Name: b3f23d186425d2362b756708cbaf422ba3c751f9 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/tclsqlite.c | 23 +++++++++++------------ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index ad8661af94..197b521b86 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sthe\sCodec\sinterface\sto\ssupport\scodecs\son\sattached\sdatabases\sand\nto\sallow\srekeying\sin\sthe\smiddle\sof\sa\stransaction.\s\sThese\schanges\sare\sonly\s\napplicable\sif\sSQLite\sis\scompiled\swith\sSQLITE_HAS_CODEC. -D 2013-05-29T17:48:28.829 +C Improved\shandling\sof\serrors\swhen\sdoing\srun-time\sloading\sof\san\sSQLite\nshared-library\sinto\sTCL. +D 2013-05-31T15:36:07.208 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -224,7 +224,7 @@ F src/sqliteInt.h 46fb17f604ce941551fe64c342dbeb4dbed3edaa F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c 2ecec9937e69bc17560ad886da35195daa7261b8 +F src/tclsqlite.c b90c5175b080a7d511fb06da0ada0c3d65d20b3b F src/test1.c 6d2a340eea1d866bf7059894491652a69a7ee802 F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 09e5a7ad85dc592fce868a2d0f8719c6915ccb47 -R 20090ed5100bc7738631061b2f74235f +P d5b084e9d8cfe9c0c339aca076d472bb50aa764c +R 2882afbdbc546836259a7beab1bfa1d4 U drh -Z caf68d1d5a539a495dd90cbaf5a54682 +Z ab4690d9d62a96dd945919f7fe2c1c88 diff --git a/manifest.uuid b/manifest.uuid index e0da117f05..74edec22a4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d5b084e9d8cfe9c0c339aca076d472bb50aa764c \ No newline at end of file +b3f23d186425d2362b756708cbaf422ba3c751f9 \ No newline at end of file diff --git a/src/tclsqlite.c b/src/tclsqlite.c index f1bb2921da..325e809fab 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3050,7 +3050,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ */ #ifndef USE_TCL_STUBS # undef Tcl_InitStubs -# define Tcl_InitStubs(a,b,c) +# define Tcl_InitStubs(a,b,c) TCL_OK #endif /* @@ -3074,19 +3074,18 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ ** The EXTERN macros are required by TCL in order to work on windows. */ EXTERN int Sqlite3_Init(Tcl_Interp *interp){ - Tcl_InitStubs(interp, "8.4", 0); - Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); - Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); - + int rc = Tcl_InitStubs(interp, "8.4", 0); + if( rc==TCL_OK ){ + Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); #ifndef SQLITE_3_SUFFIX_ONLY - /* The "sqlite" alias is undocumented. It is here only to support - ** legacy scripts. All new scripts should use only the "sqlite3" - ** command. - */ - Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); + /* The "sqlite" alias is undocumented. It is here only to support + ** legacy scripts. All new scripts should use only the "sqlite3" + ** command. */ + Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); #endif - - return TCL_OK; + rc = Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); + } + return rc; } EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } From 8030dc7b1f36e2f0f56c0ae6fc71596996a5105d Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 15:50:39 +0000 Subject: [PATCH 050/144] Remove the definitions of objects that are no longer used: WhereCost, WherePlan, and WhereBestIdx. FossilOrigin-Name: 816f8add7e60de2ef8df4fdac090c244f8dbda39 --- manifest | 14 ++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 27 ------------------------- src/where.c | 53 ++++++++----------------------------------------- 4 files changed, 16 insertions(+), 80 deletions(-) diff --git a/manifest b/manifest index 535b2266fe..1dc7a47d76 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\stracing\sof\swhereLoopInsert()\swhen\sthe\s0x8\sbit\sis\sset\son\s".wheretrace".\nRemove\sthe\suse\sof\ssqlite_query_plan\sfrom\swhere2.test.\s\sFix\sa\sbug\sin\sthe\ncode\sgenerator\sfor\sOR\sclause\soptimizations. -D 2013-05-31T15:18:46.709 +C Remove\sthe\sdefinitions\sof\sobjects\sthat\sare\sno\slonger\sused:\s\sWhereCost,\s\nWherePlan,\sand\sWhereBestIdx. +D 2013-05-31T15:50:39.999 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,7 @@ F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h c386fb7c61c03a0a65d78e326016449767be5b93 +F src/sqliteInt.h 3ddccdf8ef912119da26945f2d8dff98f59e1d58 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e120e28cb55cea658589ec2eca5764dcfa0396c2 +F src/where.c 586b6c3628b75619542468575706ab3192aad236 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b9578c371ee569dca6a0964019959a93407c8ef9 -R 10e84b9c96bf0dc4179bf10aeea4849d +P 707f0323264c35be14847a6adc49a0dc5eaf4ad2 +R 427cbfc4828d3a50415e243b6cfd8031 U drh -Z 1f5041366a1e7c65f32184b30b5b84bc +Z 69d89052012f1e53f4573be3e4c8c80b diff --git a/manifest.uuid b/manifest.uuid index f519953e67..e1da51f18b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -707f0323264c35be14847a6adc49a0dc5eaf4ad2 \ No newline at end of file +816f8add7e60de2ef8df4fdac090c244f8dbda39 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a0e7bba7d6..e99098cd0a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -720,7 +720,6 @@ typedef struct UnpackedRecord UnpackedRecord; typedef struct VTable VTable; typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; -typedef struct WherePlan WherePlan; typedef struct WhereInfo WhereInfo; typedef struct WhereLevel WhereLevel; @@ -1949,32 +1948,6 @@ struct SrcList { #define JT_ERROR 0x0040 /* unknown or unsupported join type */ -/* -** A WherePlan object holds information that describes a lookup -** strategy. -** -** This object is intended to be opaque outside of the where.c module. -** It is included here only so that that compiler will know how big it -** is. None of the fields in this object should be used outside of -** the where.c module. -** -** Within the union, pIdx is only used when wsFlags&WHERE_INDEXED is true. -** pTerm is only used when wsFlags&WHERE_MULTI_OR is true. And pVtabIdx -** is only used when wsFlags&WHERE_VIRTUALTABLE is true. It is never the -** case that more than one of these conditions is true. -*/ -struct WherePlan { - u32 wsFlags; /* WHERE_* flags that describe the strategy */ - u16 nEq; /* Number of == constraints */ - u16 nOBSat; /* Number of ORDER BY terms satisfied */ - double nRow; /* Estimated number of rows (for EQP) */ - union { - Index *pIdx; /* Index when WHERE_INDEXED is true */ - struct WhereTerm *pTerm; /* WHERE clause term for OR-search */ - sqlite3_index_info *pVtabIdx; /* Virtual table index to use */ - } u; -}; - /* ** For each nested loop in a WHERE clause implementation, the WhereInfo ** structure contains a single instance of this structure. This structure diff --git a/src/where.c b/src/where.c index 6b4521b40a..eaef66cc8e 100644 --- a/src/where.c +++ b/src/where.c @@ -39,7 +39,6 @@ typedef struct WhereClause WhereClause; typedef struct WhereMaskSet WhereMaskSet; typedef struct WhereOrInfo WhereOrInfo; typedef struct WhereAndInfo WhereAndInfo; -typedef struct WhereCost WhereCost; typedef struct WhereLoop WhereLoop; typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; @@ -275,16 +274,6 @@ struct WhereMaskSet { int ix[BMS]; /* Cursor assigned to each bit */ }; -/* -** A WhereCost object records a lookup strategy and the estimated -** cost of pursuing that strategy. -*/ -struct WhereCost { - WherePlan plan; /* The lookup strategy */ - double rCost; /* Overall cost of pursuing this search strategy */ - Bitmask used; /* Bitmask of cursors used by this plan */ -}; - /* ** This object is a factory for WhereLoop objects for a particular query. */ @@ -343,28 +332,6 @@ struct WhereLoopBuilder { #define WHERE_TEMP_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_COVER_SCAN 0x00008000 /* Full scan of a covering index */ -/* -** This module contains many separate subroutines that work together to -** find the best indices to use for accessing a particular table in a query. -** An instance of the following structure holds context information about the -** index search so that it can be more easily passed between the various -** routines. -*/ -typedef struct WhereBestIdx WhereBestIdx; -struct WhereBestIdx { - Parse *pParse; /* Parser context */ - WhereClause *pWC; /* The WHERE clause */ - struct SrcList_item *pSrc; /* The FROM clause term to search */ - Bitmask notReady; /* Mask of cursors not available */ - Bitmask notValid; /* Cursors not available for any purpose */ - ExprList *pOrderBy; /* The ORDER BY clause */ - ExprList *pDistinct; /* The select-list if query is DISTINCT */ - sqlite3_index_info **ppIdxInfo; /* Index information passed to xBestIndex */ - int i, n; /* Which loop is being coded; # of loops */ - WhereLevel *aLevel; /* Info about outer loops */ - WhereCost cost; /* Lowest cost query plan */ -}; - /* ** Initialize a preallocated WhereClause structure. */ @@ -5024,7 +4991,6 @@ WhereInfo *sqlite3WhereBegin( WhereInfo *pWInfo; /* Will become the return value of this function */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */ Bitmask notReady; /* Cursors that are not yet positioned */ - WhereBestIdx sWBI; /* Best index search context */ WhereLoopBuilder sWLB; /* The WhereLoop builder */ WhereMaskSet *pMaskSet; /* The expression mask set */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */ @@ -5034,8 +5000,6 @@ WhereInfo *sqlite3WhereBegin( /* Variable initialization */ - memset(&sWBI, 0, sizeof(sWBI)); - sWBI.pParse = pParse; memset(&sWLB, 0, sizeof(sWLB)); sWLB.pParse = pParse; sWLB.db = pParse->db; @@ -5083,11 +5047,10 @@ WhereInfo *sqlite3WhereBegin( pWInfo->pOrderBy = pOrderBy; pWInfo->pDistinct = pDistinct; pWInfo->iBreak = sqlite3VdbeMakeLabel(v); - pWInfo->pWC = sWBI.pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo]; + pWInfo->pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo]; pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; - pMaskSet = (WhereMaskSet*)&sWBI.pWC[1]; - sWBI.aLevel = pWInfo->a; + pMaskSet = (WhereMaskSet*)&pWInfo->pWC[1]; sWLB.pWInfo = pWInfo; sWLB.pWC = pWInfo->pWC; @@ -5099,9 +5062,9 @@ WhereInfo *sqlite3WhereBegin( ** subexpression is separated by an AND operator. */ initMaskSet(pMaskSet); - whereClauseInit(sWBI.pWC, pParse, pMaskSet, wctrlFlags); + whereClauseInit(pWInfo->pWC, pParse, pMaskSet, wctrlFlags); sqlite3ExprCodeConstants(pParse, pWhere); - whereSplit(sWBI.pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ + whereSplit(pWInfo->pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. @@ -5146,7 +5109,7 @@ WhereInfo *sqlite3WhereBegin( ** want to analyze these virtual terms, so start analyzing at the end ** and work forward so that the added virtual terms are never processed. */ - exprAnalyzeAll(pTabList, sWBI.pWC); + exprAnalyzeAll(pTabList, pWInfo->pWC); if( db->mallocFailed ){ goto whereBeginError; } @@ -5155,7 +5118,7 @@ WhereInfo *sqlite3WhereBegin( ** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to ** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT. */ - if( pDistinct && isDistinctRedundant(pParse, pTabList, sWBI.pWC, pDistinct) ){ + if( pDistinct && isDistinctRedundant(pParse,pTabList,pWInfo->pWC,pDistinct) ){ pDistinct = 0; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } @@ -5260,7 +5223,7 @@ WhereInfo *sqlite3WhereBegin( } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLoop->wsFlags & WHERE_TEMP_INDEX)!=0 ){ - constructAutomaticIndex(pParse, sWBI.pWC, pTabItem, notReady, pLevel); + constructAutomaticIndex(pParse, pWInfo->pWC, pTabItem, notReady, pLevel); }else #endif if( pLoop->u.btree.pIndex!=0 ){ @@ -5275,7 +5238,7 @@ WhereInfo *sqlite3WhereBegin( VdbeComment((v, "%s", pIx->zName)); } sqlite3CodeVerifySchema(pParse, iDb); - notReady &= ~getMask(sWBI.pWC->pMaskSet, pTabItem->iCursor); + notReady &= ~getMask(pWInfo->pWC->pMaskSet, pTabItem->iCursor); } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; From 7e47cb8b7595835f1695aa01645036a25ddc7887 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 17:55:27 +0000 Subject: [PATCH 051/144] Fix problems in the virtual table logic for NGQP. FossilOrigin-Name: 23af28e24b8f7ffacd006978b25bab990a43b8c5 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 1dc7a47d76..dca4b55f11 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sdefinitions\sof\sobjects\sthat\sare\sno\slonger\sused:\s\sWhereCost,\s\nWherePlan,\sand\sWhereBestIdx. -D 2013-05-31T15:50:39.999 +C Fix\sproblems\sin\sthe\svirtual\stable\slogic\sfor\sNGQP. +D 2013-05-31T17:55:27.487 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 586b6c3628b75619542468575706ab3192aad236 +F src/where.c 103ccfa82fa177f755d35f0d48932713857516a1 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 707f0323264c35be14847a6adc49a0dc5eaf4ad2 -R 427cbfc4828d3a50415e243b6cfd8031 +P 816f8add7e60de2ef8df4fdac090c244f8dbda39 +R 876fcc7116fcba2a9fe2cf6848606247 U drh -Z 69d89052012f1e53f4573be3e4c8c80b +Z 5ce875f360b3d8cc74f8b2b339e3e8e8 diff --git a/manifest.uuid b/manifest.uuid index e1da51f18b..3c1f169293 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -816f8add7e60de2ef8df4fdac090c244f8dbda39 \ No newline at end of file +23af28e24b8f7ffacd006978b25bab990a43b8c5 \ No newline at end of file diff --git a/src/where.c b/src/where.c index eaef66cc8e..833077497b 100644 --- a/src/where.c +++ b/src/where.c @@ -3034,7 +3034,7 @@ static Bitmask codeOneLoopStart( } } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); - sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); + sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC); @@ -5226,7 +5226,7 @@ WhereInfo *sqlite3WhereBegin( constructAutomaticIndex(pParse, pWInfo->pWC, pTabItem, notReady, pLevel); }else #endif - if( pLoop->u.btree.pIndex!=0 ){ + if( pLoop->wsFlags & WHERE_INDEXED ){ Index *pIx = pLoop->u.btree.pIndex; KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx); /* FIXME: As an optimization use pTabItem->iCursor if WHERE_IDX_ONLY */ From e22501721f72ed3eb4c3eeaf64abd5e1148ee354 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 18:13:50 +0000 Subject: [PATCH 052/144] Another virtual table fix in NGQP. FossilOrigin-Name: 2f2ce4167728399cc30bef045aab500940af978c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index dca4b55f11..731f7bf161 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sproblems\sin\sthe\svirtual\stable\slogic\sfor\sNGQP. -D 2013-05-31T17:55:27.487 +C Another\svirtual\stable\sfix\sin\sNGQP. +D 2013-05-31T18:13:50.522 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 103ccfa82fa177f755d35f0d48932713857516a1 +F src/where.c e6d80ad378cfdf98b0477248307872dab302bd0b F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 816f8add7e60de2ef8df4fdac090c244f8dbda39 -R 876fcc7116fcba2a9fe2cf6848606247 +P 23af28e24b8f7ffacd006978b25bab990a43b8c5 +R 77968cfca458e219a6b5161f66e2b4eb U drh -Z 5ce875f360b3d8cc74f8b2b339e3e8e8 +Z 390707269c04791307b06380f248a89b diff --git a/manifest.uuid b/manifest.uuid index 3c1f169293..6937c337ca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -23af28e24b8f7ffacd006978b25bab990a43b8c5 \ No newline at end of file +2f2ce4167728399cc30bef045aab500940af978c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 833077497b..a83dbae9dc 100644 --- a/src/where.c +++ b/src/where.c @@ -3024,7 +3024,7 @@ static Bitmask codeOneLoopStart( iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; jaTerm[j]; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); From 76f4cfb2e6098e822cdd7f86557f7211f46f265f Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 18:20:52 +0000 Subject: [PATCH 053/144] Fix a problem with code generation on LEFT JOIN of tables without an index. FossilOrigin-Name: 0b1bee92a0d25f409d5a95f484b05ddf10ae945f --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 731f7bf161..e78a656654 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Another\svirtual\stable\sfix\sin\sNGQP. -D 2013-05-31T18:13:50.522 +C Fix\sa\sproblem\swith\scode\sgeneration\son\sLEFT\sJOIN\sof\stables\swithout\san\sindex. +D 2013-05-31T18:20:52.849 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e6d80ad378cfdf98b0477248307872dab302bd0b +F src/where.c a8bb7f25f61b354bc26fc09df0d1367ba3389f12 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 23af28e24b8f7ffacd006978b25bab990a43b8c5 -R 77968cfca458e219a6b5161f66e2b4eb +P 2f2ce4167728399cc30bef045aab500940af978c +R 0f759a90cbe05948f904b521254c6d0c U drh -Z 390707269c04791307b06380f248a89b +Z 66b770a6b254520a8bdad94186b27ffc diff --git a/manifest.uuid b/manifest.uuid index 6937c337ca..d9b24b220e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f2ce4167728399cc30bef045aab500940af978c \ No newline at end of file +0b1bee92a0d25f409d5a95f484b05ddf10ae945f \ No newline at end of file diff --git a/src/where.c b/src/where.c index a83dbae9dc..4b1d407159 100644 --- a/src/where.c +++ b/src/where.c @@ -5311,7 +5311,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor); } - if( pLevel->iIdxCur>=0 ){ + if( pLoop->wsFlags & WHERE_INDEXED ){ sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } if( pLevel->op==OP_Return ){ From 0edc94dcc71e1f4009b497e42b993387a4ce17e4 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 19:14:56 +0000 Subject: [PATCH 054/144] Do not attempt to generate code in the NGQP if there have been prior errors, since with prior errors some of the expressions might not be fully named resolved. FossilOrigin-Name: 665e4291c6e78f11d7181c18c5f2418d1adfcb1c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index e78a656654..e546c5f58b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\scode\sgeneration\son\sLEFT\sJOIN\sof\stables\swithout\san\sindex. -D 2013-05-31T18:20:52.849 +C Do\snot\sattempt\sto\sgenerate\scode\sin\sthe\sNGQP\sif\sthere\shave\sbeen\sprior\serrors,\nsince\swith\sprior\serrors\ssome\sof\sthe\sexpressions\smight\snot\sbe\sfully\s\nnamed\sresolved. +D 2013-05-31T19:14:56.877 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c a8bb7f25f61b354bc26fc09df0d1367ba3389f12 +F src/where.c 0c1d6feb0c2ffcc3e37b2d0b5ce044773daa3d44 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 2f2ce4167728399cc30bef045aab500940af978c -R 0f759a90cbe05948f904b521254c6d0c +P 0b1bee92a0d25f409d5a95f484b05ddf10ae945f +R 3775b32a7236de56bac48d67633687ab U drh -Z 66b770a6b254520a8bdad94186b27ffc +Z ab504bcb48497c438de08e5ddd0f5c9c diff --git a/manifest.uuid b/manifest.uuid index d9b24b220e..ca22f8fcd8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0b1bee92a0d25f409d5a95f484b05ddf10ae945f \ No newline at end of file +665e4291c6e78f11d7181c18c5f2418d1adfcb1c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4b1d407159..aee574a23a 100644 --- a/src/where.c +++ b/src/where.c @@ -5162,6 +5162,10 @@ WhereInfo *sqlite3WhereBegin( } } #endif + WHERETRACE(("*** Optimizer Finished ***\n")); + if( pParse->nErr || db->mallocFailed ){ + goto whereBeginError; + } #if 0 /* FIXME: Add this back in? */ /* If the caller is an UPDATE or DELETE statement that is requesting From a1f4124cf88a444a5d355d42dbff781dd1fe570f Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 20:00:58 +0000 Subject: [PATCH 055/144] Make sure a unique cursor number is allocated for automatic indices. FossilOrigin-Name: 433d1aecd399590b767ebf07b32023fb718a6574 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index e546c5f58b..b32322793d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sattempt\sto\sgenerate\scode\sin\sthe\sNGQP\sif\sthere\shave\sbeen\sprior\serrors,\nsince\swith\sprior\serrors\ssome\sof\sthe\sexpressions\smight\snot\sbe\sfully\s\nnamed\sresolved. -D 2013-05-31T19:14:56.877 +C Make\ssure\sa\sunique\scursor\snumber\sis\sallocated\sfor\sautomatic\sindices. +D 2013-05-31T20:00:58.768 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 0c1d6feb0c2ffcc3e37b2d0b5ce044773daa3d44 +F src/where.c 3d93b77c4acc97f0dc018d251f2e2833f8df5663 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 0b1bee92a0d25f409d5a95f484b05ddf10ae945f -R 3775b32a7236de56bac48d67633687ab +P 665e4291c6e78f11d7181c18c5f2418d1adfcb1c +R 2b43f41e454a1bbd459d18838a33d5bf U drh -Z ab504bcb48497c438de08e5ddd0f5c9c +Z 9f4cea41d946c49ff071caa4f1da93db diff --git a/manifest.uuid b/manifest.uuid index ca22f8fcd8..9e292ef1c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -665e4291c6e78f11d7181c18c5f2418d1adfcb1c \ No newline at end of file +433d1aecd399590b767ebf07b32023fb718a6574 \ No newline at end of file diff --git a/src/where.c b/src/where.c index aee574a23a..bd0d410cd2 100644 --- a/src/where.c +++ b/src/where.c @@ -1925,6 +1925,7 @@ static void constructAutomaticIndex( /* Create the automatic index */ pKeyinfo = sqlite3IndexKeyinfo(pParse, pIdx); assert( pLevel->iIdxCur>=0 ); + pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp4(v, OP_OpenAutoindex, pLevel->iIdxCur, nColumn+1, 0, (char*)pKeyinfo, P4_KEYINFO_HANDOFF); VdbeComment((v, "for %s", pTable->zName)); From 79a13bfd1eb920f187ee1cacad0406cf97d1bae3 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 20:28:28 +0000 Subject: [PATCH 056/144] Do not search using ON clause constraints of LEFT JOINs to the right of the table. FossilOrigin-Name: 723f901a63313b64a9f10516711fb6136526b79b --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index b32322793d..5aec48fb0e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\sa\sunique\scursor\snumber\sis\sallocated\sfor\sautomatic\sindices. -D 2013-05-31T20:00:58.768 +C Do\snot\ssearch\susing\sON\sclause\sconstraints\sof\sLEFT\sJOINs\sto\sthe\sright\sof\nthe\stable. +D 2013-05-31T20:28:28.662 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 3d93b77c4acc97f0dc018d251f2e2833f8df5663 +F src/where.c 3e4ca21a9b34ab25b2ec13704e8659581d57878d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 665e4291c6e78f11d7181c18c5f2418d1adfcb1c -R 2b43f41e454a1bbd459d18838a33d5bf +P 433d1aecd399590b767ebf07b32023fb718a6574 +R bd0568ec5c6f80c0ba5870a23aeeb2df U drh -Z 9f4cea41d946c49ff071caa4f1da93db +Z 6a19f7c88688bac3b6839a73befa2b33 diff --git a/manifest.uuid b/manifest.uuid index 9e292ef1c6..6cebeafdb2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -433d1aecd399590b767ebf07b32023fb718a6574 \ No newline at end of file +723f901a63313b64a9f10516711fb6136526b79b \ No newline at end of file diff --git a/src/where.c b/src/where.c index bd0d410cd2..c4a8c22243 100644 --- a/src/where.c +++ b/src/where.c @@ -3996,6 +3996,7 @@ static int whereLoopAddBtreeIndex( rLogSize = estLog(pProbe->aiRowEst[0]); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ int nIn = 1; + if( pTerm->prereqRight & pNew->maskSelf ) continue; pNew->wsFlags = savedLoop.wsFlags; pNew->u.btree.nEq = savedLoop.u.btree.nEq; pNew->nTerm = savedLoop.nTerm; @@ -4146,6 +4147,7 @@ static int whereLoopAddBtree( WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; for(pTerm=pWC->a; rc==SQLITE_OK && pTermprereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; pNew->u.btree.pIndex = 0; From 75b9340520fbbd3f7c660537acdba55c42c5e40b Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 May 2013 20:43:57 +0000 Subject: [PATCH 057/144] The NGQP might not find a solution if INDEXED BY constraints on the query are set wrong. If that is the case, print a "no query solution" error and abort before trying to use the non-existant solution. FossilOrigin-Name: 42511a7e12a70cf3436d25e4d069e5d309dfd678 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 14 ++++++++------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 5aec48fb0e..e85a435ce4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\ssearch\susing\sON\sclause\sconstraints\sof\sLEFT\sJOINs\sto\sthe\sright\sof\nthe\stable. -D 2013-05-31T20:28:28.662 +C The\sNGQP\smight\snot\sfind\sa\ssolution\sif\sINDEXED\sBY\sconstraints\son\sthe\squery\nare\sset\swrong.\s\sIf\sthat\sis\sthe\scase,\sprint\sa\s"no\squery\ssolution"\serror\nand\sabort\sbefore\strying\sto\suse\sthe\snon-existant\ssolution. +D 2013-05-31T20:43:57.656 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 3e4ca21a9b34ab25b2ec13704e8659581d57878d +F src/where.c 7c931bf930fcf77d9a446e6d60692ab7a6251d00 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 433d1aecd399590b767ebf07b32023fb718a6574 -R bd0568ec5c6f80c0ba5870a23aeeb2df +P 723f901a63313b64a9f10516711fb6136526b79b +R f0026590576c82bf02c9ed7b1fd9cc97 U drh -Z 6a19f7c88688bac3b6839a73befa2b33 +Z 4e2d6d22eda85e326fefafc64c333d74 diff --git a/manifest.uuid b/manifest.uuid index 6cebeafdb2..1a1fa457c3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -723f901a63313b64a9f10516711fb6136526b79b \ No newline at end of file +42511a7e12a70cf3436d25e4d069e5d309dfd678 \ No newline at end of file diff --git a/src/where.c b/src/where.c index c4a8c22243..4e78f1ebde 100644 --- a/src/where.c +++ b/src/where.c @@ -4864,9 +4864,11 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ nFrom = nTo; } - /* TEMPORARY */ - if( nFrom==0 ){ sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } - assert( nFrom>0 ); + if( nFrom==0 ){ + sqlite3ErrorMsg(pWInfo->pParse, "no query solution"); + sqlite3DbFree(db, pSpace); + return SQLITE_ERROR; + } /* Find the lowest cost path. pFrom will be left pointing to that path */ pFrom = aFrom; @@ -5151,6 +5153,9 @@ WhereInfo *sqlite3WhereBegin( wherePathSolver(pWInfo, pWInfo->nRowOut); if( db->mallocFailed ) goto whereBeginError; } + if( pParse->nErr || db->mallocFailed ){ + goto whereBeginError; + } #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ int ii; @@ -5166,9 +5171,6 @@ WhereInfo *sqlite3WhereBegin( } #endif WHERETRACE(("*** Optimizer Finished ***\n")); - if( pParse->nErr || db->mallocFailed ){ - goto whereBeginError; - } #if 0 /* FIXME: Add this back in? */ /* If the caller is an UPDATE or DELETE statement that is requesting From 0e85ccfca50997ac0543c36b18d0783ed3f56126 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 12:34:46 +0000 Subject: [PATCH 058/144] Further improvements to error handling of the run-time loading of SQLite into TCL. FossilOrigin-Name: 7cc0c4ee11ad250fa848e7da4713d70fc0fa3715 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/tclsqlite.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 197b521b86..e49b5c47ec 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\shandling\sof\serrors\swhen\sdoing\srun-time\sloading\sof\san\sSQLite\nshared-library\sinto\sTCL. -D 2013-05-31T15:36:07.208 +C Further\simprovements\sto\serror\shandling\sof\sthe\srun-time\sloading\sof\sSQLite\ninto\sTCL. +D 2013-06-03T12:34:46.177 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -224,7 +224,7 @@ F src/sqliteInt.h 46fb17f604ce941551fe64c342dbeb4dbed3edaa F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c b90c5175b080a7d511fb06da0ada0c3d65d20b3b +F src/tclsqlite.c b8835978e853a89bf58de88acc943a5ca94d752e F src/test1.c 6d2a340eea1d866bf7059894491652a69a7ee802 F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d5b084e9d8cfe9c0c339aca076d472bb50aa764c -R 2882afbdbc546836259a7beab1bfa1d4 +P b3f23d186425d2362b756708cbaf422ba3c751f9 +R 3d8fd48ca795de4c58516ba1337670b0 U drh -Z ab4690d9d62a96dd945919f7fe2c1c88 +Z 53e0acf52f5e2ddf8d35e0395d7b33fa diff --git a/manifest.uuid b/manifest.uuid index 74edec22a4..af34504f4c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b3f23d186425d2362b756708cbaf422ba3c751f9 \ No newline at end of file +7cc0c4ee11ad250fa848e7da4713d70fc0fa3715 \ No newline at end of file diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 325e809fab..6d2a51e5ab 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3050,7 +3050,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ */ #ifndef USE_TCL_STUBS # undef Tcl_InitStubs -# define Tcl_InitStubs(a,b,c) TCL_OK +# define Tcl_InitStubs(a,b,c) TCL_VERSION #endif /* @@ -3074,7 +3074,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ ** The EXTERN macros are required by TCL in order to work on windows. */ EXTERN int Sqlite3_Init(Tcl_Interp *interp){ - int rc = Tcl_InitStubs(interp, "8.4", 0); + int rc = Tcl_InitStubs(interp, "8.4", 0)==0 ? TCL_ERROR : TCL_OK; if( rc==TCL_OK ){ Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); #ifndef SQLITE_3_SUFFIX_ONLY From 348d19c0c4eaad750fcddd8c20d7d66750fe8fbd Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 12:47:43 +0000 Subject: [PATCH 059/144] Enhance the shell to provide more flexibility when entering numeric arguments on dot-commands. In particular, allow hexadecimal arguments to .wheretrace and .testctrl commands. Cherrypick from [b9578c371ee5]. FossilOrigin-Name: 3bd5ad095b23102dd3379cb62997cbf23cc67b7a --- manifest | 13 ++++---- manifest.uuid | 2 +- src/shell.c | 88 ++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 74 insertions(+), 29 deletions(-) diff --git a/manifest b/manifest index e49b5c47ec..6635065e0c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\simprovements\sto\serror\shandling\sof\sthe\srun-time\sloading\sof\sSQLite\ninto\sTCL. -D 2013-06-03T12:34:46.177 +C Enhance\sthe\sshell\sto\sprovide\smore\sflexibility\swhen\sentering\snumeric\sarguments\non\sdot-commands.\s\sIn\sparticular,\sallow\shexadecimal\sarguments\sto\s.wheretrace\nand\s.testctrl\scommands.\s\sCherrypick\sfrom\s[b9578c371ee5]. +D 2013-06-03T12:47:43.357 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -216,7 +216,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 22ee971346a736ddefdc4497d07c92f2e9978afc -F src/shell.c 9a18124ff209ca308d786c99a466e8e270193ff3 +F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 @@ -1093,7 +1093,8 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b3f23d186425d2362b756708cbaf422ba3c751f9 -R 3d8fd48ca795de4c58516ba1337670b0 +P 7cc0c4ee11ad250fa848e7da4713d70fc0fa3715 +Q +b9578c371ee569dca6a0964019959a93407c8ef9 +R c008097aeb0fb5fb21f8c2495cc9a0d5 U drh -Z 53e0acf52f5e2ddf8d35e0395d7b33fa +Z 3060a4de0d44f47720b8e142580eccbb diff --git a/manifest.uuid b/manifest.uuid index af34504f4c..df3f6e42f9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7cc0c4ee11ad250fa848e7da4713d70fc0fa3715 \ No newline at end of file +3bd5ad095b23102dd3379cb62997cbf23cc67b7a \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index d5fa9c6963..9f2f46bd18 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1523,21 +1523,14 @@ static void resolve_backslashes(char *z){ } /* -** Interpret zArg as a boolean value. Return either 0 or 1. +** Return the value of a hexadecimal digit. Return -1 if the input +** is not a hex digit. */ -static int booleanValue(char *zArg){ - int i; - for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} - if( i>0 && zArg[i]==0 ) return atoi(zArg); - if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ - return 1; - } - if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ - return 0; - } - fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", - zArg); - return 0; +static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; } /* @@ -1564,9 +1557,18 @@ static sqlite3_int64 integerValue(const char *zArg){ }else if( zArg[0]=='+' ){ zArg++; } - while( IsDigit(zArg[0]) ){ - v = v*10 + zArg[0] - '0'; - zArg++; + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + v = (v<<4) + x; + zArg++; + } + }else{ + while( IsDigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } } for(i=0; i=0; i++){} + }else{ + for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} + } + if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff); + if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ + return 1; + } + if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ + return 0; + } + fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", + zArg); + return 0; +} + /* ** Close an output file, assuming it is not stderr or stdout */ @@ -1808,7 +1833,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ - if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc); + if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); rc = 2; }else @@ -2305,6 +2330,25 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else + /* Undocumented commands for internal testing. Subject to change + ** without notice. */ + if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ + if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ + int i, v; + for(i=1; iout, "%s: %d 0x%x\n", azArg[i], v, v); + } + } + if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ + int i; sqlite3_int64 v; + for(i=1; iout, "%s: %lld 0x%llx\n", azArg[i], v, v); + } + } + }else + if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sqlite3_snprintf(sizeof(p->separator), p->separator, "%.*s", (int)sizeof(p->separator)-1, azArg[1]); @@ -2458,7 +2502,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } } } - if( testctrl<0 ) testctrl = atoi(azArg[1]); + if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]); if( (testctrlSQLITE_TESTCTRL_LAST) ){ fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]); }else{ @@ -2505,7 +2549,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ case SQLITE_TESTCTRL_ASSERT: case SQLITE_TESTCTRL_ALWAYS: if( nArg==3 ){ - int opt = atoi(azArg[2]); + int opt = booleanValue(azArg[2]); rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { @@ -2542,7 +2586,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ open_db(p); - sqlite3_busy_timeout(p->db, atoi(azArg[1])); + sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1])); }else if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 @@ -2592,7 +2636,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; jcolWidth); j++){ - p->colWidth[j-1] = atoi(azArg[j]); + p->colWidth[j-1] = (int)integerValue(azArg[j]); } }else From 6186b309019d818bd0946856752fa241d8cc7943 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 14:15:34 +0000 Subject: [PATCH 060/144] Add test cases to verify that ticket [bc1aea7b725f2761] has been fixed in the NGQP. FossilOrigin-Name: 9b97af94ae7b1624ef1f5adee58010593fbb8b1c --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/whereD.test | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index e85a435ce4..fd53c9cffe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sNGQP\smight\snot\sfind\sa\ssolution\sif\sINDEXED\sBY\sconstraints\son\sthe\squery\nare\sset\swrong.\s\sIf\sthat\sis\sthe\scase,\sprint\sa\s"no\squery\ssolution"\serror\nand\sabort\sbefore\strying\sto\suse\sthe\snon-existant\ssolution. -D 2013-05-31T20:43:57.656 +C Add\stest\scases\sto\sverify\sthat\sticket\s[bc1aea7b725f2761]\shas\sbeen\sfixed\sin\nthe\sNGQP. +D 2013-06-03T14:15:34.631 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -1041,7 +1041,7 @@ F test/where9.test 1b4387c6eacc9a32b28b4d837c27f857c785d0d8 F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5 -F test/whereD.test 3f3ee93825c94804f1fc91eef2de0d365981759a +F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62 F test/whereE.test 7bd34945797efef15819368479bacc34215e4e1d F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 723f901a63313b64a9f10516711fb6136526b79b -R f0026590576c82bf02c9ed7b1fd9cc97 +P 42511a7e12a70cf3436d25e4d069e5d309dfd678 +R 9315575e95aec71de6da1203a12a0f54 U drh -Z 4e2d6d22eda85e326fefafc64c333d74 +Z bf9c6fc8107d350958f4a9bdd4f10f03 diff --git a/manifest.uuid b/manifest.uuid index 1a1fa457c3..824fa2dabf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -42511a7e12a70cf3436d25e4d069e5d309dfd678 \ No newline at end of file +9b97af94ae7b1624ef1f5adee58010593fbb8b1c \ No newline at end of file diff --git a/test/whereD.test b/test/whereD.test index 9ac5a68097..eb0f864025 100644 --- a/test/whereD.test +++ b/test/whereD.test @@ -186,4 +186,37 @@ do_test 4.3 { } } {1 2 3 3 6 9 4 5 6 {} {} {}} +# Ticket [bc1aea7b725f276177] +# Incorrect result on LEFT JOIN with OR constraints and an ORDER BY clause. +# +do_execsql_test 4.4 { + CREATE TABLE t44(a INTEGER, b INTEGER); + INSERT INTO t44 VALUES(1,2); + INSERT INTO t44 VALUES(3,4); + SELECT * + FROM t44 AS x + LEFT JOIN (SELECT a AS c, b AS d FROM t44) AS y ON a=c + WHERE d=4 OR d IS NULL; +} {3 4 3 4} +do_execsql_test 4.5 { + SELECT * + FROM t44 AS x + LEFT JOIN (SELECT a AS c, b AS d FROM t44) AS y ON a=c + WHERE d=4 OR d IS NULL + ORDER BY a; +} {3 4 3 4} +do_execsql_test 4.6 { + CREATE TABLE t46(c INTEGER, d INTEGER); + INSERT INTO t46 SELECT a, b FROM t44; + SELECT * FROM t44 LEFT JOIN t46 ON a=c + WHERE d=4 OR d IS NULL; +} {3 4 3 4} +do_execsql_test 4.7 { + SELECT * FROM t44 LEFT JOIN t46 ON a=c + WHERE d=4 OR d IS NULL + ORDER BY a; +} {3 4 3 4} + + + finish_test From 21f7ff7d22ae722ae3955cc61a1020d98b2b959c Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 15:07:23 +0000 Subject: [PATCH 061/144] Set the WHERE_UNIQUE flag on loops that can only run once. FossilOrigin-Name: 510f4d8ecf6eb284f14b91951e7236505bd71203 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index fd53c9cffe..4456115495 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\scases\sto\sverify\sthat\sticket\s[bc1aea7b725f2761]\shas\sbeen\sfixed\sin\nthe\sNGQP. -D 2013-06-03T14:15:34.631 +C Set\sthe\sWHERE_UNIQUE\sflag\son\sloops\sthat\scan\sonly\srun\sonce. +D 2013-06-03T15:07:23.693 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 7c931bf930fcf77d9a446e6d60692ab7a6251d00 +F src/where.c 7e34bb26affb2bf0eee8a8c5ab955cf80e7f9580 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 42511a7e12a70cf3436d25e4d069e5d309dfd678 -R 9315575e95aec71de6da1203a12a0f54 +P 9b97af94ae7b1624ef1f5adee58010593fbb8b1c +R c10d3b1c9e2b7a04d0ad05024b58cd34 U drh -Z bf9c6fc8107d350958f4a9bdd4f10f03 +Z 86153958e4f1f3df668821cb8ff6a748 diff --git a/manifest.uuid b/manifest.uuid index 824fa2dabf..950d83a47f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9b97af94ae7b1624ef1f5adee58010593fbb8b1c \ No newline at end of file +510f4d8ecf6eb284f14b91951e7236505bd71203 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4e78f1ebde..1efa409942 100644 --- a/src/where.c +++ b/src/where.c @@ -4017,6 +4017,12 @@ static int whereLoopAddBtreeIndex( pNew->nOut = (double)iRowEst * nInMul * nIn; }else if( pTerm->eOperator & (WO_EQ) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; + if( iCol<0 + || (pProbe->onError==OE_Abort && nInMul==1 + && pNew->u.btree.nEq==pProbe->nColumn-1) + ){ + pNew->wsFlags |= WHERE_UNIQUE; + } pNew->u.btree.nEq++; pNew->nOut = (double)iRowEst * nInMul; }else if( pTerm->eOperator & (WO_ISNULL) ){ From d108d74d48c9863eddaa01b150a6e802de862261 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 15:24:11 +0000 Subject: [PATCH 062/144] Virtual tables now always report 25 rows instead of 0 rows in the EXPLAIN QUERY PLAN output. Adjust tests accordingly. FossilOrigin-Name: 7d91f688815597ff65ec04b7daa21cb9e5d6bf98 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/fts3aux1.test | 27 +++++++++++++-------------- test/fts3query.test | 5 ++--- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 4456115495..ba3a006024 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Set\sthe\sWHERE_UNIQUE\sflag\son\sloops\sthat\scan\sonly\srun\sonce. -D 2013-06-03T15:07:23.693 +C Virtual\stables\snow\salways\sreport\s25\srows\sinstead\sof\s0\srows\sin\sthe\s\nEXPLAIN\sQUERY\sPLAN\soutput.\s\sAdjust\stests\saccordingly. +D 2013-06-03T15:24:11.404 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -511,7 +511,7 @@ F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 F test/fts3ao.test e7b80272efcced57d1d087a9da5c690dd7c21fd9 F test/fts3atoken.test fb398ab50aa232489e2a17f9b29d7ad3a3885f36 F test/fts3auto.test 74315a7377403a57ba82a652a33704197fe1e4be -F test/fts3aux1.test 03cec2dea379931c219dd4406817485caa69d1d8 +F test/fts3aux1.test 52cc50162e5e0c27fc08d12c8fe41b8df20af555 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c @@ -535,7 +535,7 @@ F test/fts3matchinfo.test ecb08f586d027eb03941bcfcded6cb9d8ccb3a66 F test/fts3near.test 12895557870b0f9af7cc0be81a0171abb2d12f12 F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1 F test/fts3prefix2.test 477ca96e67f60745b7ac931cfa6e9b080c562da5 -F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2 +F test/fts3query.test 00b519001b42ea0bb65314103a395604880dd7cf F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0 F test/fts3shared.test c2f60e152e8554549eb25f0a7593ea01389c5037 F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 9b97af94ae7b1624ef1f5adee58010593fbb8b1c -R c10d3b1c9e2b7a04d0ad05024b58cd34 +P 510f4d8ecf6eb284f14b91951e7236505bd71203 +R b46e673a11585c0adf84b26ffd5c9ca9 U drh -Z 86153958e4f1f3df668821cb8ff6a748 +Z 24bffcc0033c051bdc90970a04c0eaf7 diff --git a/manifest.uuid b/manifest.uuid index 950d83a47f..f196f60bd2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -510f4d8ecf6eb284f14b91951e7236505bd71203 \ No newline at end of file +7d91f688815597ff65ec04b7daa21cb9e5d6bf98 \ No newline at end of file diff --git a/test/fts3aux1.test b/test/fts3aux1.test index ef17949fd9..f421b7f6ef 100644 --- a/test/fts3aux1.test +++ b/test/fts3aux1.test @@ -105,10 +105,10 @@ db func rec rec # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~25 rows)} } do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' -} {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}} +} {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)}} # Now show that using "term='braid'" means the virtual table returns # only 1 row to SQLite, but "+term='braid'" means all 19 are returned. @@ -154,24 +154,24 @@ do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2: (~25 rows)} } do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} } do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4: (~25 rows)} } do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} } do_execsql_test 2.2.1.5 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6: (~25 rows)} } do_execsql_test 2.2.1.6 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} } do_test 2.2.2.1 { set cnt 0 @@ -335,7 +335,7 @@ foreach {tn sort orderby} { 9 1 "ORDER BY occurrences DESC" } { - set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)}] + set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)}] if {$sort} { lappend res 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } set sql "SELECT * FROM terms $orderby" @@ -411,7 +411,7 @@ do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { 0 0 0 {SCAN TABLE x2 (~1000000 rows)} - 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~25 rows)} a b c d e f g h i j k l } @@ -419,14 +419,14 @@ do_plansql_test 4.3 { SELECT y FROM terms, x2 WHERE y = term AND col = '*' } { 0 0 1 {SCAN TABLE x2 (~1000000 rows)} - 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~25 rows)} a b c d e f g h i j k l } do_plansql_test 4.4 { SELECT y FROM x3, terms WHERE y = term AND col = '*' } { - 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} + 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} 0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)} a b c d e f g h i j k l } @@ -434,7 +434,7 @@ do_plansql_test 4.4 { do_plansql_test 4.5 { SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*' } { - 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~0 rows)} + 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} 0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)} a k l } @@ -519,4 +519,3 @@ do_test 8.2 { } {1 {SQL logic error or missing database}} finish_test - diff --git a/test/fts3query.test b/test/fts3query.test index c8f8686bff..51b84be906 100644 --- a/test/fts3query.test +++ b/test/fts3query.test @@ -119,13 +119,13 @@ do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~25 rows)} } do_eqp_test fts3query-4.3 { SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date } { 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~0 rows)} + 0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~25 rows)} } do_eqp_test fts3query-4.4 { SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date @@ -210,4 +210,3 @@ do_select_tests 6.2 { finish_test - From 3a5ba8b1b77e26e4b1a8eb4b538c0b7bf25b6717 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 15:34:48 +0000 Subject: [PATCH 063/144] Fix an issue that was causing ORDER BY DESC to come out in ascending order. FossilOrigin-Name: 029840124022387a8f6d2e1a685a003688d0ef3a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index ba3a006024..34d692d6a5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Virtual\stables\snow\salways\sreport\s25\srows\sinstead\sof\s0\srows\sin\sthe\s\nEXPLAIN\sQUERY\sPLAN\soutput.\s\sAdjust\stests\saccordingly. -D 2013-06-03T15:24:11.404 +C Fix\san\sissue\sthat\swas\scausing\sORDER\sBY\sDESC\sto\scome\sout\sin\sascending\sorder. +D 2013-06-03T15:34:48.695 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 7e34bb26affb2bf0eee8a8c5ab955cf80e7f9580 +F src/where.c 078c3aeafacf8544bdc733bf6b60d087d9e6346c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 510f4d8ecf6eb284f14b91951e7236505bd71203 -R b46e673a11585c0adf84b26ffd5c9ca9 +P 7d91f688815597ff65ec04b7daa21cb9e5d6bf98 +R 47cac5b8ea3311240b582844f809143b U drh -Z 24bffcc0033c051bdc90970a04c0eaf7 +Z d1b03d3fcac2015c05c39b44e5780b67 diff --git a/manifest.uuid b/manifest.uuid index f196f60bd2..fa405a84b7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7d91f688815597ff65ec04b7daa21cb9e5d6bf98 \ No newline at end of file +029840124022387a8f6d2e1a685a003688d0ef3a \ No newline at end of file diff --git a/src/where.c b/src/where.c index 1efa409942..d9e33d6058 100644 --- a/src/where.c +++ b/src/where.c @@ -4767,6 +4767,8 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ default: /* Cannot tell yet. Try again on the next iteration */ break; } + }else{ + revMask = pFrom->revLoop; } /* Check to see if pWLoop should be added to the mxChoice best so far */ for(jj=0, pTo=aTo; jj Date: Mon, 3 Jun 2013 16:03:16 +0000 Subject: [PATCH 064/144] Fix to the logic that disables constraints on virtual tables. FossilOrigin-Name: 62d382406b28c1347e13114f42215939ddfd7a9d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 34d692d6a5..432c1a0ab8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sissue\sthat\swas\scausing\sORDER\sBY\sDESC\sto\scome\sout\sin\sascending\sorder. -D 2013-06-03T15:34:48.695 +C Fix\sto\sthe\slogic\sthat\sdisables\sconstraints\son\svirtual\stables. +D 2013-06-03T16:03:16.168 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 078c3aeafacf8544bdc733bf6b60d087d9e6346c +F src/where.c b8a41bcd6a61e560d9c45e4a066d3858a06657d8 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7d91f688815597ff65ec04b7daa21cb9e5d6bf98 -R 47cac5b8ea3311240b582844f809143b +P 029840124022387a8f6d2e1a685a003688d0ef3a +R 74a79b344cf1d282ed20a762beed972e U drh -Z d1b03d3fcac2015c05c39b44e5780b67 +Z 4d150a08a0845f1055b728ec84c21984 diff --git a/manifest.uuid b/manifest.uuid index fa405a84b7..8704c41e00 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -029840124022387a8f6d2e1a685a003688d0ef3a \ No newline at end of file +62d382406b28c1347e13114f42215939ddfd7a9d \ No newline at end of file diff --git a/src/where.c b/src/where.c index d9e33d6058..3c4b7140cd 100644 --- a/src/where.c +++ b/src/where.c @@ -4326,7 +4326,7 @@ static int whereLoopAddVirtual( pNew->prereq |= pTerm->prereqRight; pNew->aTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; - if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ if( pUsage[i].omit==0 ){ /* Do not attempt to use an IN constraint if the virtual table From 3b1d808fab432b8547ad8d39c36cacb32a30a2b9 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 16:56:37 +0000 Subject: [PATCH 065/144] Honor the orderByConsumed boolean returned from virtual table query planner. FossilOrigin-Name: aaf7f5896d3523531e1a9a1b90c4ad326f0c8fc7 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 432c1a0ab8..3a94412d02 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sto\sthe\slogic\sthat\sdisables\sconstraints\son\svirtual\stables. -D 2013-06-03T16:03:16.168 +C Honor\sthe\sorderByConsumed\sboolean\sreturned\sfrom\svirtual\stable\squery\splanner. +D 2013-06-03T16:56:37.438 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c b8a41bcd6a61e560d9c45e4a066d3858a06657d8 +F src/where.c 82c6fd16a6344108eac33642414958dc8db20d32 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 029840124022387a8f6d2e1a685a003688d0ef3a -R 74a79b344cf1d282ed20a762beed972e +P 62d382406b28c1347e13114f42215939ddfd7a9d +R 6374db7e82d972462ef1160c4988e05a U drh -Z 4d150a08a0845f1055b728ec84c21984 +Z 8802671c91d46932119ceee1b71a0d50 diff --git a/manifest.uuid b/manifest.uuid index 8704c41e00..ee3e9a8cbf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -62d382406b28c1347e13114f42215939ddfd7a9d \ No newline at end of file +aaf7f5896d3523531e1a9a1b90c4ad326f0c8fc7 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 3c4b7140cd..2d416f99d0 100644 --- a/src/where.c +++ b/src/where.c @@ -4350,7 +4350,8 @@ static int whereLoopAddVirtual( pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; - pNew->u.vtab.isOrdered = (u8)(pIdxInfo->nOrderBy!=0); + pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0) + && pIdxInfo->orderByConsumed); pNew->rSetup = (double)0; pNew->rRun = pIdxInfo->estimatedCost; pNew->nOut = (double)25; From 6f2bfad24bb797b12e090b6981fe01dbe5fa3faf Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 17:35:22 +0000 Subject: [PATCH 066/144] Update the NGQP to make use of STAT3 information if it is available. FossilOrigin-Name: ff134e6ee95d41b0e59e03bba7e94bc15b04ff8c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 29 ++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 3a94412d02..3195663c77 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Honor\sthe\sorderByConsumed\sboolean\sreturned\sfrom\svirtual\stable\squery\splanner. -D 2013-06-03T16:56:37.438 +C Update\sthe\sNGQP\sto\smake\suse\sof\sSTAT3\sinformation\sif\sit\sis\savailable. +D 2013-06-03T17:35:22.501 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 82c6fd16a6344108eac33642414958dc8db20d32 +F src/where.c a60b27296226bc073ae87988f7cec222d9523d7d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 62d382406b28c1347e13114f42215939ddfd7a9d -R 6374db7e82d972462ef1160c4988e05a +P aaf7f5896d3523531e1a9a1b90c4ad326f0c8fc7 +R 821d5edba86d3e2ff0b1efea7de5e5d1 U drh -Z 8802671c91d46932119ceee1b71a0d50 +Z 967f742fe27d5833ce434e13ad275aee diff --git a/manifest.uuid b/manifest.uuid index ee3e9a8cbf..f4885e9b76 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aaf7f5896d3523531e1a9a1b90c4ad326f0c8fc7 \ No newline at end of file +ff134e6ee95d41b0e59e03bba7e94bc15b04ff8c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 2d416f99d0..92aa607fc8 100644 --- a/src/where.c +++ b/src/where.c @@ -3965,6 +3965,7 @@ static int whereLoopAddBtreeIndex( int rc = SQLITE_OK; /* Return code */ tRowcnt iRowEst; /* Estimated index selectivity */ double rLogSize; /* Logarithm of table size */ + WhereTerm *pTop, *pBtm; /* Top and bottom range constraints */ db = pBuilder->db; pNew = pBuilder->pNew; @@ -4031,12 +4032,35 @@ static int whereLoopAddBtreeIndex( pNew->nOut = (double)iRowEst * nInMul; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; - pNew->nOut = savedLoop.nOut/3; + pBtm = pTerm; + pTop = 0; }else if( pTerm->eOperator & (WO_LT|WO_LE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; - pNew->nOut = savedLoop.nOut/3; + pTop = pTerm; + pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? + pNew->aTerm[pNew->nTerm-2] : 0; } pNew->rRun = rLogSize*nIn; /* Cost for nIn binary searches */ + if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ + /* Adjust nOut and rRun for STAT3 range values */ + double rDiv; + whereRangeScanEst(pBuilder->pParse, pProbe, pNew->u.btree.nEq, + pBtm, pTop, &rDiv); + pNew->nOut = savedLoop.nOut/rDiv; + } +#ifdef SQLITE_ENABLE_STAT3 + if( pNew->u.btree.nEq==1 && pProbe->nSample ){ + if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ + rc = whereEqualScanEst(pBuilder->pParse, pProbe, pTerm->pExpr->pRight, + &pNew->nOut); + }else if( (pTerm->eOperator & WO_IN) + && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ + rc = whereInScanEst(pBuilder->pParse, pProbe, pTerm->pExpr->x.pList, + &pNew->nOut); + + } + } +#endif if( pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK) ){ pNew->rRun += pNew->nOut; /* Unit step cost to reach each row */ }else{ @@ -4044,7 +4068,6 @@ static int whereLoopAddBtreeIndex( ** the main table */ pNew->rRun += pNew->nOut*(1 + rLogSize); } - /* TBD: Adjust nOut and rRun for STAT3 range values */ /* TBD: Adjust nOut for additional constraints */ rc = whereLoopInsert(pBuilder, pNew); if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 From 44dc8e822b990e477c0d1ff7b50f3f1d478740e8 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 18:14:31 +0000 Subject: [PATCH 067/144] Fix EXPLAIN QUERY PLAN row counts for the rtree virtual table tests. FossilOrigin-Name: 15328987cc876d7a4e34561b6b0e08937aefe4be --- ext/rtree/rtree6.test | 10 +++++----- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/rtree/rtree6.test b/ext/rtree/rtree6.test index 92edc8d104..320b993368 100644 --- a/ext/rtree/rtree6.test +++ b/ext/rtree/rtree6.test @@ -74,35 +74,35 @@ do_test rtree6-1.5 { do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca (~0 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca (~25 rows)} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} } do_eqp_test rtree6.2.2 { SELECT * FROM t1,t2 WHERE k=ii AND x1<10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca (~0 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca (~25 rows)} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} } do_eqp_test rtree6.2.3 { SELECT * FROM t1,t2 WHERE k=ii } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2: (~0 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2: (~25 rows)} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} } do_eqp_test rtree6.2.4 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb (~0 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb (~25 rows)} 0 1 1 {SCAN TABLE t2 (~100000 rows)} } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x1 Date: Mon, 3 Jun 2013 18:50:15 +0000 Subject: [PATCH 068/144] Fix a bug in the transitive_closure virtual table that NGQP exposes. Update between.test module to avoid using sqlite_query_plan. FossilOrigin-Name: aa66b864204b4b8717d845499132b987eb8ef924 --- ext/misc/closure.c | 6 +++++- manifest | 14 +++++++------- manifest.uuid | 2 +- test/between.test | 22 ++++++++++++++++------ 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/ext/misc/closure.c b/ext/misc/closure.c index 213b7633e6..665cc7ce44 100644 --- a/ext/misc/closure.c +++ b/ext/misc/closure.c @@ -828,6 +828,7 @@ static int closureBestIndex( int idx = 1; const struct sqlite3_index_constraint *pConstraint; closure_vtab *pVtab = (closure_vtab*)pTab; + double rCost = 10000000.0; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ @@ -839,6 +840,7 @@ static int closureBestIndex( iPlan |= 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; + rCost /= 100.0; } if( (iPlan & 0x0000f0)==0 && pConstraint->iColumn==CLOSURE_COL_DEPTH @@ -849,6 +851,7 @@ static int closureBestIndex( iPlan |= idx<<4; pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ) iPlan |= 0x000002; + rCost /= 5.0; } if( (iPlan & 0x000f00)==0 && pConstraint->iColumn==CLOSURE_COL_TABLENAME @@ -857,6 +860,7 @@ static int closureBestIndex( iPlan |= idx<<8; pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; pIdxInfo->aConstraintUsage[i].omit = 1; + rCost /= 5.0; } if( (iPlan & 0x00f000)==0 && pConstraint->iColumn==CLOSURE_COL_IDCOLUMN @@ -891,7 +895,7 @@ static int closureBestIndex( ){ pIdxInfo->orderByConsumed = 1; } - pIdxInfo->estimatedCost = (double)10000; + pIdxInfo->estimatedCost = rCost; return SQLITE_OK; } diff --git a/manifest b/manifest index cb6fd82118..78c40ea581 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sEXPLAIN\sQUERY\sPLAN\srow\scounts\sfor\sthe\srtree\svirtual\stable\stests. -D 2013-06-03T18:14:31.081 +C Fix\sa\sbug\sin\sthe\stransitive_closure\svirtual\stable\sthat\sNGQP\sexposes.\nUpdate\sbetween.test\smodule\sto\savoid\susing\ssqlite_query_plan. +D 2013-06-03T18:50:15.467 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -107,7 +107,7 @@ F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 F ext/icu/icu.c 7538f98eab2854cf17fa5f7797bffa6c76e3863b F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c eae8454cd9dcb287b2a3ec2e65a865a4ac5f0d06 -F ext/misc/closure.c 40788c54c59190a1f52f6492a260d8894a246fe9 +F ext/misc/closure.c b88aa95fbe32edc74e16ed5bb6646d249a2bf6ad F ext/misc/fuzzer.c 51bd96960b6b077d41d6f3cedefbcb57f29efaa2 F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556 F ext/misc/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e @@ -335,7 +335,7 @@ F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f F test/bc_common.tcl 5c8689cc6d2fb44b7c0968ae4f85eb26d50022fa -F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070 +F test/between.test bec144cd75698402bbda8ad8e23bd8588e426145 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 7c79f1ef0c6c2c2bc1e7bd895596fab32bfb4796 F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ff134e6ee95d41b0e59e03bba7e94bc15b04ff8c -R e905d61d613190200a15251273731837 +P 15328987cc876d7a4e34561b6b0e08937aefe4be +R 0bfbc2c20668c92dcdb991d487aaa95a U drh -Z 152c7a47705b2201e9c25505c9ef2b93 +Z d205bcca63c72f2d174184c36108bd89 diff --git a/manifest.uuid b/manifest.uuid index c02031bee7..3a34f12991 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -15328987cc876d7a4e34561b6b0e08937aefe4be \ No newline at end of file +aa66b864204b4b8717d845499132b987eb8ef924 \ No newline at end of file diff --git a/test/between.test b/test/between.test index 45436756aa..98be29aea7 100644 --- a/test/between.test +++ b/test/between.test @@ -55,7 +55,17 @@ proc queryplan {sql} { set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + lappend data $tab * + } + } + return $data } do_test between-1.1.1 { @@ -67,7 +77,7 @@ do_test between-1.1.2 { queryplan { SELECT * FROM t1 WHERE +w BETWEEN 5 AND 6 ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.2.1 { queryplan { SELECT * FROM t1 WHERE w BETWEEN 5 AND 65-y ORDER BY +w @@ -77,7 +87,7 @@ do_test between-1.2.2 { queryplan { SELECT * FROM t1 WHERE +w BETWEEN 5 AND 65-y ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.3.1 { queryplan { SELECT * FROM t1 WHERE w BETWEEN 41-y AND 6 ORDER BY +w @@ -87,12 +97,12 @@ do_test between-1.3.2 { queryplan { SELECT * FROM t1 WHERE +w BETWEEN 41-y AND 6 ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.4 { queryplan { SELECT * FROM t1 WHERE w BETWEEN 41-y AND 65-y ORDER BY +w } -} {5 2 36 38 6 2 49 51 sort t1 {}} +} {5 2 36 38 6 2 49 51 sort t1 *} do_test between-1.5.1 { queryplan { SELECT * FROM t1 WHERE 26 BETWEEN y AND z ORDER BY +w @@ -107,7 +117,7 @@ do_test between-1.5.3 { queryplan { SELECT * FROM t1 WHERE 26 BETWEEN y AND +z ORDER BY +w } -} {4 2 25 27 sort t1 {}} +} {4 2 25 27 sort t1 *} finish_test From 74990dce64a98940db8bd437a5dda5fafa4caca0 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 19:01:26 +0000 Subject: [PATCH 069/144] Resolve ambiguities in test cases in collate2.test. FossilOrigin-Name: dcbbcb2e6c85780276cb3a392549f70e21e94408 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/collate2.test | 6 ++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 78c40ea581..58036befe9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbug\sin\sthe\stransitive_closure\svirtual\stable\sthat\sNGQP\sexposes.\nUpdate\sbetween.test\smodule\sto\savoid\susing\ssqlite_query_plan. -D 2013-06-03T18:50:15.467 +C Resolve\sambiguities\sin\stest\scases\sin\scollate2.test. +D 2013-06-03T19:01:26.660 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -366,7 +366,7 @@ F test/close.test e37610d60e9c9b9979a981f3f50071d7dff28616 F test/closure01.test dbb28f1ea9eeaf0a53ec5bc0fed352e479def8c7 F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce -F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49 +F test/collate2.test 285cef1b58ce2b3cf074a386f763ce753c81c97f F test/collate3.test 79558a286362cb9ed603c6fa543f1cda7f563f0f F test/collate4.test 031f7265c13308b724ba3c49f41cc04612bd92b1 F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 15328987cc876d7a4e34561b6b0e08937aefe4be -R 0bfbc2c20668c92dcdb991d487aaa95a +P aa66b864204b4b8717d845499132b987eb8ef924 +R 62f1f59de9bf7b607ff3cad8a2a9dba4 U drh -Z d205bcca63c72f2d174184c36108bd89 +Z 7508c3c33af72ab568a1feb83056a8cb diff --git a/manifest.uuid b/manifest.uuid index 3a34f12991..f007fe30fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aa66b864204b4b8717d845499132b987eb8ef924 \ No newline at end of file +dcbbcb2e6c85780276cb3a392549f70e21e94408 \ No newline at end of file diff --git a/test/collate2.test b/test/collate2.test index bf619231da..c758b0a6db 100644 --- a/test/collate2.test +++ b/test/collate2.test @@ -636,13 +636,15 @@ do_test collate2-4.2 { do_test collate2-4.3 { execsql { SELECT collate2t1.a FROM collate2t1, collate2t3 - WHERE collate2t1.b = collate2t3.b||''; + WHERE collate2t1.b = collate2t3.b||'' + ORDER BY +collate2t1.a DESC; } } {aa aA Aa AA} do_test collate2-4.4 { execsql { SELECT collate2t1.a FROM collate2t1, collate2t3 - WHERE collate2t3.b||'' = collate2t1.b; + WHERE collate2t3.b||'' = collate2t1.b + ORDER BY +collate2t1.a DESC; } } {aa aA Aa AA} From e3b7c9216cf2c5a5b8170b6024426447ebac8f9f Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 19:17:40 +0000 Subject: [PATCH 070/144] Do not use an index fullscan for an UPDATE or DELETE or if disabled by sqlite3_test_control() or sqlite3_config(). FossilOrigin-Name: fabb21854e662b1d8e5631e79f828d5322ceb595 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 7 ++++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 58036befe9..0a83808515 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Resolve\sambiguities\sin\stest\scases\sin\scollate2.test. -D 2013-06-03T19:01:26.660 +C Do\snot\suse\san\sindex\sfullscan\sfor\san\sUPDATE\sor\sDELETE\sor\sif\sdisabled\sby\nsqlite3_test_control()\sor\ssqlite3_config(). +D 2013-06-03T19:17:40.684 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c a60b27296226bc073ae87988f7cec222d9523d7d +F src/where.c 6226d9912f494a92b51b06c58b5c0eed9b7eb84e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P aa66b864204b4b8717d845499132b987eb8ef924 -R 62f1f59de9bf7b607ff3cad8a2a9dba4 +P dcbbcb2e6c85780276cb3a392549f70e21e94408 +R 5e83ed1a81fa16225d238fe289659759 U drh -Z 7508c3c33af72ab568a1feb83056a8cb +Z 8c74536a41fa8c42d526bd323c460f6c diff --git a/manifest.uuid b/manifest.uuid index f007fe30fa..c94f0e1371 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dcbbcb2e6c85780276cb3a392549f70e21e94408 \ No newline at end of file +fabb21854e662b1d8e5631e79f828d5322ceb595 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 92aa607fc8..ee604f0713 100644 --- a/src/where.c +++ b/src/where.c @@ -4224,7 +4224,12 @@ static int whereLoopAddBtree( pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; /* Full scan via index */ - if( (m==0 || b) && pProbe->bUnordered==0 ){ + if( (m==0 || b) + && pProbe->bUnordered==0 + && (pBuilder->pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 + && sqlite3GlobalConfig.bUseCis + && OptimizationEnabled(pBuilder->pParse->db, SQLITE_CoverIdxScan) + ){ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; pNew->rRun = (m==0) ? (rSize + rLogSize)*(1+b) : (rSize*rLogSize); From f5ad80397d44c088a3974e2838446011f2430b97 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 20:39:15 +0000 Subject: [PATCH 071/144] Fix a typo in a collating function inside the e_reindex.test script. FossilOrigin-Name: 4d74fccf02134a998a84097b021ba9d501e34ff0 --- manifest | 13 ++++++------- manifest.uuid | 2 +- test/e_reindex.test | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 6635065e0c..4c2a451fd1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\sshell\sto\sprovide\smore\sflexibility\swhen\sentering\snumeric\sarguments\non\sdot-commands.\s\sIn\sparticular,\sallow\shexadecimal\sarguments\sto\s.wheretrace\nand\s.testctrl\scommands.\s\sCherrypick\sfrom\s[b9578c371ee5]. -D 2013-06-03T12:47:43.357 +C Fix\sa\stypo\sin\sa\scollating\sfunction\sinside\sthe\se_reindex.test\sscript. +D 2013-06-03T20:39:15.752 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -428,7 +428,7 @@ F test/e_expr.test 5489424d3d9a452ac3701cdf4b680ae31a157894 F test/e_fkey.test 79a985d95340c6072a884359426ce95cf33e656a F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 F test/e_insert.test d5331cc95e101af2508159fc98b6801631659ffe -F test/e_reindex.test dfedfc32c5a282b0596c6537cbcd4217fbb1a216 +F test/e_reindex.test 5e6dff3a060b5234d496f6e84c3e59a94b4dce4d F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_select.test d5af998a402740d8f0488158d22075df2b6f88fa F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92 @@ -1093,8 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7cc0c4ee11ad250fa848e7da4713d70fc0fa3715 -Q +b9578c371ee569dca6a0964019959a93407c8ef9 -R c008097aeb0fb5fb21f8c2495cc9a0d5 +P 3bd5ad095b23102dd3379cb62997cbf23cc67b7a +R 0bab77d0f95310ae1c21cfea10915144 U drh -Z 3060a4de0d44f47720b8e142580eccbb +Z 1023ee14390bd42e471d5323a67fa234 diff --git a/manifest.uuid b/manifest.uuid index df3f6e42f9..e3db3db774 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3bd5ad095b23102dd3379cb62997cbf23cc67b7a \ No newline at end of file +4d74fccf02134a998a84097b021ba9d501e34ff0 \ No newline at end of file diff --git a/test/e_reindex.test b/test/e_reindex.test index b39f37e0de..c75f6acaab 100644 --- a/test/e_reindex.test +++ b/test/e_reindex.test @@ -98,7 +98,7 @@ proc sort_by_length {lhs rhs} { array set V {one 1 two 2 three 3 four 4 five 5 six 6 seven 7 eight 8} proc sort_by_value {lhs rhs} { global V - set res [expr {$V($lhs) - $V(rhs)}] + set res [expr {$V($lhs) - $V($rhs)}] if {$res!=0} {return $res} return [string compare $lhs $rhs] } From a3855653ed06222b8c0f0329a4ab23ea8a8adbbb Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 21:25:28 +0000 Subject: [PATCH 072/144] Adjust the xBestIndex methods on both the fuzzer and transitive_closure virtual tables so that an unused MATCH operator gets a really large cost. Remove ambiguities from the fuzzer test cases. FossilOrigin-Name: e2c1af78b65a8ace976fa6c035db212e1ffc79b8 --- ext/misc/closure.c | 6 ++++++ ext/misc/fuzzer.c | 13 ++++++++++++- manifest | 16 ++++++++-------- manifest.uuid | 2 +- test/fuzzer1.test | 17 +++++++++++------ 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/ext/misc/closure.c b/ext/misc/closure.c index 665cc7ce44..260a783042 100644 --- a/ext/misc/closure.c +++ b/ext/misc/closure.c @@ -826,12 +826,17 @@ static int closureBestIndex( int iPlan = 0; int i; int idx = 1; + int seenMatch = 0; const struct sqlite3_index_constraint *pConstraint; closure_vtab *pVtab = (closure_vtab*)pTab; double rCost = 10000000.0; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->iColumn==CLOSURE_COL_ROOT + && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + seenMatch = 1; + } if( pConstraint->usable==0 ) continue; if( (iPlan & 1)==0 && pConstraint->iColumn==CLOSURE_COL_ROOT @@ -895,6 +900,7 @@ static int closureBestIndex( ){ pIdxInfo->orderByConsumed = 1; } + if( seenMatch && (iPlan&1)==0 ) rCost *= 1e30; pIdxInfo->estimatedCost = rCost; return SQLITE_OK; diff --git a/ext/misc/fuzzer.c b/ext/misc/fuzzer.c index 642b8f9e92..023bdb1d09 100644 --- a/ext/misc/fuzzer.c +++ b/ext/misc/fuzzer.c @@ -1077,9 +1077,16 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int iDistTerm = -1; int iRulesetTerm = -1; int i; + int seenMatch = 0; const struct sqlite3_index_constraint *pConstraint; + double rCost = 100000; + pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->iColumn==0 + && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ + seenMatch = 1; + } if( pConstraint->usable==0 ) continue; if( (iPlan & 1)==0 && pConstraint->iColumn==0 @@ -1088,6 +1095,7 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ iPlan |= 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; + rCost /= 1000000.0; } if( (iPlan & 2)==0 && pConstraint->iColumn==1 @@ -1096,6 +1104,7 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ){ iPlan |= 2; iDistTerm = i; + rCost /= 10.0; } if( (iPlan & 4)==0 && pConstraint->iColumn==2 @@ -1104,6 +1113,7 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ iPlan |= 4; pIdxInfo->aConstraintUsage[i].omit = 1; iRulesetTerm = i; + rCost /= 10.0; } } if( iPlan & 2 ){ @@ -1122,7 +1132,8 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ){ pIdxInfo->orderByConsumed = 1; } - pIdxInfo->estimatedCost = (double)10000; + if( seenMatch && (iPlan&1)==0 ) rCost *= 1e30; + pIdxInfo->estimatedCost = rCost; return SQLITE_OK; } diff --git a/manifest b/manifest index dba927beb0..75f057b5a8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Pull\sin\srecent\strunk\schanges.\s\sFix\sthe\sORDER\sBY\soptimizer\sso\sthat\sit\sis\sbetter\nable\sto\sdeal\swith\sCOLLATE\sclauses.\s\sClean\sup\sambiguities\sin\sthe\sdescidx1.test\nscript. -D 2013-06-03T20:46:35.011 +C Adjust\sthe\sxBestIndex\smethods\son\sboth\sthe\sfuzzer\sand\stransitive_closure\nvirtual\stables\sso\sthat\san\sunused\sMATCH\soperator\sgets\sa\sreally\slarge\scost.\nRemove\sambiguities\sfrom\sthe\sfuzzer\stest\scases. +D 2013-06-03T21:25:28.624 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -107,8 +107,8 @@ F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 F ext/icu/icu.c 7538f98eab2854cf17fa5f7797bffa6c76e3863b F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c eae8454cd9dcb287b2a3ec2e65a865a4ac5f0d06 -F ext/misc/closure.c b88aa95fbe32edc74e16ed5bb6646d249a2bf6ad -F ext/misc/fuzzer.c 51bd96960b6b077d41d6f3cedefbcb57f29efaa2 +F ext/misc/closure.c 997c20ddf35f85ab399f4a02a557a9baa822ec32 +F ext/misc/fuzzer.c 79ac20b68794dfe03626f3a31681e6c240583052 F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556 F ext/misc/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e F ext/misc/percentile.c 4fb5e46c4312b0be74e8e497ac18f805f0e3e6c5 @@ -561,7 +561,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 -F test/fuzzer1.test 41bd5aa6ae0cf18d06342a4476e3cad98604ae48 +F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 F test/hook.test 45cb22b940c3cc0af616ba7430f666e245711a48 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P fabb21854e662b1d8e5631e79f828d5322ceb595 4d74fccf02134a998a84097b021ba9d501e34ff0 -R b746dc544342dfc07463de0423275bdc +P 6bc71dfcf0ef757c5c2b426dd8fddc1e5ae0f598 +R 9f95af129af308d556c3b0bed3929212 U drh -Z 5182eac11ae0820ee1af6bccc6719c26 +Z 30d36dfc5ff4e44e38a2e90ed964881e diff --git a/manifest.uuid b/manifest.uuid index 1e5db89b77..5fac46b81c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6bc71dfcf0ef757c5c2b426dd8fddc1e5ae0f598 \ No newline at end of file +e2c1af78b65a8ace976fa6c035db212e1ffc79b8 \ No newline at end of file diff --git a/test/fuzzer1.test b/test/fuzzer1.test index 473d0e1868..4ee5730807 100644 --- a/test/fuzzer1.test +++ b/test/fuzzer1.test @@ -1728,36 +1728,41 @@ do_execsql_test 8.1 { do_execsql_test 8.2.1 { SELECT cFrom, cTo, word FROM x3_rules CROSS JOIN x3 - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo; } {a x x a y y a z z} do_execsql_test 8.2.2 { SELECT cFrom, cTo, word FROM x3 CROSS JOIN x3_rules - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC } {a z z a y y a x x} do_execsql_test 8.2.3 { SELECT cFrom, cTo, word FROM x3_rules, x3 - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC; } {a z z a y y a x x} do_execsql_test 8.2.4 { SELECT cFrom, cTo, word FROM x3, x3_rules - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC; } {a z z a y y a x x} do_execsql_test 8.2.5 { CREATE INDEX i1 ON x3_rules(cost); SELECT cFrom, cTo, word FROM x3_rules, x3 - WHERE word MATCH 'a' AND cost=distance AND ruleset=2; + WHERE word MATCH 'a' AND cost=distance AND ruleset=2 + ORDER BY +cTo DESC; } {a z z a y y a x x} do_execsql_test 8.2.5 { - SELECT word FROM x3_rules, x3 WHERE word MATCH x3_rules.cFrom AND ruleset=2; + SELECT word FROM x3_rules, x3 WHERE word MATCH x3_rules.cFrom AND ruleset=2 } {a z y x a z y x a z y x} do_execsql_test 8.2.6 { From 7c171098b7adec43ea43022e58e1b8acafec7d28 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Jun 2013 22:08:20 +0000 Subject: [PATCH 073/144] Remove more vestiges of sqlite_query_plan from the test cases. FossilOrigin-Name: eb27086e8a8a4d5fcb2ea358256a555e34339423 --- manifest | 22 +++++++++--------- manifest.uuid | 2 +- test/between.test | 2 +- test/intpkey.test | 7 ++++-- test/like.test | 57 +++++++++++++++++++++++++++++++--------------- test/subquery.test | 7 ++++-- test/where2.test | 3 +-- test/where3.test | 26 ++++++++++++++------- 8 files changed, 81 insertions(+), 45 deletions(-) diff --git a/manifest b/manifest index 75f057b5a8..e5312f3930 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adjust\sthe\sxBestIndex\smethods\son\sboth\sthe\sfuzzer\sand\stransitive_closure\nvirtual\stables\sso\sthat\san\sunused\sMATCH\soperator\sgets\sa\sreally\slarge\scost.\nRemove\sambiguities\sfrom\sthe\sfuzzer\stest\scases. -D 2013-06-03T21:25:28.624 +C Remove\smore\svestiges\sof\ssqlite_query_plan\sfrom\sthe\stest\scases. +D 2013-06-03T22:08:20.442 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -335,7 +335,7 @@ F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f F test/bc_common.tcl 5c8689cc6d2fb44b7c0968ae4f85eb26d50022fa -F test/between.test bec144cd75698402bbda8ad8e23bd8588e426145 +F test/between.test e6896728a636e3e610bcb2f87c9305120c809bc5 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 7c79f1ef0c6c2c2bc1e7bd895596fab32bfb4796 F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 @@ -596,7 +596,7 @@ F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6 F test/instr.test a34e1d46a9eefb098a7167ef0e730a4a3d82fba0 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc -F test/intpkey.test 7af30f6ae852d8d1c2b70e4bf1551946742e92d8 +F test/intpkey.test a9674fc6195e0952e4e6105a9981ce1e48e7f215 F test/io.test ecf44cc81664ad54d8253e2d88fc705b6554abe3 F test/ioerr.test 40bb2cfcab63fb6aa7424cd97812a84bc16b5fb8 F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d @@ -619,7 +619,7 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test 0e5412f4dac4a849f613e1ef8b529d56a6e31d08 +F test/like.test 52e650adfa208325f928b847571d77b647af07c3 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99 F test/loadext.test 92e6dfefd1229c3ef4aaabd87419efd8fa57a7a5 @@ -792,7 +792,7 @@ F test/spellfix.test bea537caf587df30d430c2c6a8fe9f64b8712834 F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 F test/stat.test be8d477306006ec696bc86757cfb34bec79447ce F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 -F test/subquery.test 869562de9e8c5d8147e0451a2ce5b58cf55ce389 +F test/subquery.test 3b97763ada8b3a4092d2c80db3ebc0e7870e7eaf F test/subquery2.test 91e1e364072aeff431d1f9689b15147e421d88c7 F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a @@ -1029,8 +1029,8 @@ F test/walshared.test 6dda2293880c300baf5d791c307f653094585761 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81 -F test/where2.test f902f62d60f20b0257dd700f0c4a2945527fca8e -F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006 +F test/where2.test 116fb0d6e98a423d12eb9a65906218ce09936674 +F test/where3.test ae3054e1216ecc0afbcb83674310ebc5de25ba09 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 6bc71dfcf0ef757c5c2b426dd8fddc1e5ae0f598 -R 9f95af129af308d556c3b0bed3929212 +P e2c1af78b65a8ace976fa6c035db212e1ffc79b8 +R 85129ff0b9a881f15c06fc2c70cadd93 U drh -Z 30d36dfc5ff4e44e38a2e90ed964881e +Z 30b7be3ba3d79e592e3b359a6ec5ea92 diff --git a/manifest.uuid b/manifest.uuid index 5fac46b81c..387facd0c5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e2c1af78b65a8ace976fa6c035db212e1ffc79b8 \ No newline at end of file +eb27086e8a8a4d5fcb2ea358256a555e34339423 \ No newline at end of file diff --git a/test/between.test b/test/between.test index 98be29aea7..f089cd95d3 100644 --- a/test/between.test +++ b/test/between.test @@ -48,7 +48,7 @@ do_test between-1.0 { # This procedure executes the SQL. Then it appends to the result the # "sort" or "nosort" keyword depending on whether or not any sorting -# is done. Then it appends the ::sqlite_query_plan variable. +# is done. Then it appends the names of the table and index used. # proc queryplan {sql} { set ::sqlite_sort_count 0 diff --git a/test/intpkey.test b/test/intpkey.test index db39421284..7ed25e4a13 100644 --- a/test/intpkey.test +++ b/test/intpkey.test @@ -125,8 +125,11 @@ do_test intpkey-1.12.1 { } } {4 one two} do_test intpkey-1.12.2 { - set sqlite_query_plan -} {t1 *} + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a==4; + } +} {/SEARCH TABLE t1 /} # Try to insert a non-integer value into the primary key field. This # should result in a data type mismatch. diff --git a/test/like.test b/test/like.test index 80ba418588..f68a93537b 100644 --- a/test/like.test +++ b/test/like.test @@ -156,14 +156,27 @@ ifcapable !like_opt { # This procedure executes the SQL. Then it appends to the result the # "sort" or "nosort" keyword (as in the cksort procedure above) then -# it appends the ::sqlite_query_plan variable. +# it appends the names of the table and index used. # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\W} \ + $x all as tab idx]} { + lappend data {} $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + lappend data $tab * + } + } + return $data } # Perform tests on the like optimization. @@ -176,7 +189,7 @@ do_test like-3.1 { queryplan { SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } -} {ABC {ABC abc xyz} abc abcd sort t1 {}} +} {ABC {ABC abc xyz} abc abcd sort t1 *} do_test like-3.2 { set sqlite_like_count } {12} @@ -269,8 +282,8 @@ do_test like-3.12 { # do_test like-3.13 { set sqlite_like_count 0 + db eval {PRAGMA case_sensitive_like=off;} queryplan { - PRAGMA case_sensitive_like=off; SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } } {ABC {ABC abc xyz} abc abcd nosort {} i1} @@ -282,12 +295,14 @@ do_test like-3.14 { # do_test like-3.15 { set sqlite_like_count 0 - queryplan { + db eval { PRAGMA case_sensitive_like=on; DROP INDEX i1; + } + queryplan { SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } -} {abc abcd sort t1 {}} +} {abc abcd sort t1 *} do_test like-3.16 { set sqlite_like_count } 12 @@ -299,7 +314,7 @@ do_test like-3.17 { queryplan { SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1; } -} {abc abcd sort t1 {}} +} {abc abcd sort t1 *} do_test like-3.18 { set sqlite_like_count } 12 @@ -318,8 +333,8 @@ do_test like-3.20 { } 0 do_test like-3.21 { set sqlite_like_count 0 + db eval {PRAGMA case_sensitive_like=on;} queryplan { - PRAGMA case_sensitive_like=on; SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1; } } {abc abcd nosort {} i1} @@ -328,8 +343,8 @@ do_test like-3.22 { } 0 do_test like-3.23 { set sqlite_like_count 0 + db eval {PRAGMA case_sensitive_like=off;} queryplan { - PRAGMA case_sensitive_like=off; SELECT x FROM t1 WHERE x GLOB 'a[bc]d' ORDER BY 1; } } {abd acd nosort {} i1} @@ -809,60 +824,66 @@ do_test like-11.0 { } } {12} do_test like-11.1 { + db eval {PRAGMA case_sensitive_like=OFF;} queryplan { - PRAGMA case_sensitive_like=OFF; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; } } {abc abcd ABC ABCD nosort t11 *} do_test like-11.2 { + db eval {PRAGMA case_sensitive_like=ON;} queryplan { - PRAGMA case_sensitive_like=ON; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; } } {abc abcd nosort t11 *} do_test like-11.3 { - queryplan { + db eval { PRAGMA case_sensitive_like=OFF; CREATE INDEX t11b ON t11(b); + } + queryplan { SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11b} do_test like-11.4 { + db eval {PRAGMA case_sensitive_like=ON;} queryplan { - PRAGMA case_sensitive_like=ON; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; } } {abc abcd nosort t11 *} do_test like-11.5 { - queryplan { + db eval { PRAGMA case_sensitive_like=OFF; DROP INDEX t11b; CREATE INDEX t11bnc ON t11(b COLLATE nocase); + } + queryplan { SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11bnc} do_test like-11.6 { + db eval {CREATE INDEX t11bb ON t11(b COLLATE binary);} queryplan { - CREATE INDEX t11bb ON t11(b COLLATE binary); SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11bnc} do_test like-11.7 { + db eval {PRAGMA case_sensitive_like=ON;} queryplan { - PRAGMA case_sensitive_like=ON; SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY +a; } } {abc abcd sort {} t11bb} do_test like-11.8 { + db eval {PRAGMA case_sensitive_like=OFF;} queryplan { - PRAGMA case_sensitive_like=OFF; SELECT b FROM t11 WHERE b GLOB 'abc*' ORDER BY +a; } } {abc abcd sort {} t11bb} do_test like-11.9 { - queryplan { + db eval { CREATE INDEX t11cnc ON t11(c COLLATE nocase); CREATE INDEX t11cb ON t11(c COLLATE binary); + } + queryplan { SELECT c FROM t11 WHERE c LIKE 'abc%' ORDER BY +a; } } {abc abcd ABC ABCD sort {} t11cnc} diff --git a/test/subquery.test b/test/subquery.test index f601d3f80b..da0a44cc5c 100644 --- a/test/subquery.test +++ b/test/subquery.test @@ -241,8 +241,11 @@ do_test subquery-2.5.3.1 { } {10.0} do_test subquery-2.5.3.2 { # Verify that the t4i index was not used in the previous query - set ::sqlite_query_plan -} {t4 {}} + execsql { + EXPLAIN QUERY PLAN + SELECT * FROM t4 WHERE x IN (SELECT a FROM t3); + } +} {/SCAN TABLE t4 /} do_test subquery-2.5.4 { execsql { DROP TABLE t3; diff --git a/test/where2.test b/test/where2.test index 60937adcc5..d7fb514a87 100644 --- a/test/where2.test +++ b/test/where2.test @@ -66,7 +66,7 @@ proc cksort {sql} { # This procedure executes the SQL. Then it appends to the result the # "sort" or "nosort" keyword (as in the cksort procedure above) then -# it appends the ::sqlite_query_plan variable. +# it appends the name of the table and index used. # proc queryplan {sql} { set ::sqlite_sort_count 0 @@ -84,7 +84,6 @@ proc queryplan {sql} { } } return $data - # return [concat $data $::sqlite_query_plan] } diff --git a/test/where3.test b/test/where3.test index e08f9051e2..c8ec8eb169 100644 --- a/test/where3.test +++ b/test/where3.test @@ -103,12 +103,22 @@ ifcapable explain { } # This procedure executes the SQL. Then it appends -# the ::sqlite_query_plan variable. +# the names of the table and index used # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] - return [concat $data $::sqlite_query_plan] + set eqp [execsql "EXPLAIN QUERY PLAN $sql"] + # puts eqp=$eqp + foreach {a b c x} $eqp { + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + $x all as tab idx]} { + lappend data $tab $idx + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + lappend data $tab * + } + } + return $data } @@ -144,37 +154,37 @@ do_test where3-2.1 { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND bpk=ax } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.1 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON cx=dpk WHERE cpk=bx AND bpk=ax } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.2 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON cx=dpk WHERE bx=cpk AND bpk=ax } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.3 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON cx=dpk WHERE bx=cpk AND ax=bpk } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.4 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE bx=cpk AND ax=bpk } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.1.5 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND ax=bpk } -} {tA {} tB * tC * tD *} +} {tA * tB * tC * tD *} do_test where3-2.2 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx From 7699d1c4e5061ec35dc36c4a755de79869b8b990 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Jun 2013 12:42:29 +0000 Subject: [PATCH 074/144] Refactor the ORDER BY optimizer in the NGQP so that it is easier to maintain and so that it can support optimizing out GROUP BY and DISTINCT clauses. FossilOrigin-Name: e605c468e3a1163167831c4a6220825c0b5d083b --- manifest | 18 +-- manifest.uuid | 2 +- src/build.c | 2 + src/sqliteInt.h | 6 + src/where.c | 312 +++++++++++++++++++++++---------------- test/tkt-2a5629202f.test | 7 +- 6 files changed, 210 insertions(+), 137 deletions(-) diff --git a/manifest b/manifest index e5312f3930..3b65c600a9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\smore\svestiges\sof\ssqlite_query_plan\sfrom\sthe\stest\scases. -D 2013-06-03T22:08:20.442 +C Refactor\sthe\sORDER\sBY\soptimizer\sin\sthe\sNGQP\sso\sthat\sit\sis\seasier\sto\smaintain\nand\sso\sthat\sit\scan\ssupport\soptimizing\sout\sGROUP\sBY\sand\sDISTINCT\sclauses. +D 2013-06-04T12:42:29.293 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -165,7 +165,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c 7fba377c29573adfc6091832e27ee1fcbefb51d0 F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 -F src/build.c 92ef9483189389828966153c5950f2e5a49c1182 +F src/build.c 838cbdcbf18de2fd5723ad5864a78cc806f6c75b F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 @@ -220,7 +220,7 @@ F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 3ddccdf8ef912119da26945f2d8dff98f59e1d58 +F src/sqliteInt.h 259d999abebf4498615e9237a18c0815257a1f2f F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 0082ef59948fc8c28b35226f44e1718cb1b0300a +F src/where.c cca3284b915ee9c51dd9188e3a74e648ddf3db47 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -820,7 +820,7 @@ F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 -F test/tkt-2a5629202f.test 1ab32e084e9fc3d36be6dee2617530846a0eb0b6 +F test/tkt-2a5629202f.test befaa77b90426a5ca8025724279e0bc26336610e F test/tkt-2d1a5c67d.test d371279946622698ab393ff88cad9f5f6d82960b F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 6fb8807851964da0d24e942f2e19c7c705b9fb58 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P e2c1af78b65a8ace976fa6c035db212e1ffc79b8 -R 85129ff0b9a881f15c06fc2c70cadd93 +P eb27086e8a8a4d5fcb2ea358256a555e34339423 +R 3dd8dcdfd7f56eca682f5b0b9f200abc U drh -Z 30b7be3ba3d79e592e3b359a6ec5ea92 +Z 6cf52a3b39b332b4094772bd0e2b3942 diff --git a/manifest.uuid b/manifest.uuid index 387facd0c5..7dcbb18dc0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eb27086e8a8a4d5fcb2ea358256a555e34339423 \ No newline at end of file +e605c468e3a1163167831c4a6220825c0b5d083b \ No newline at end of file diff --git a/src/build.c b/src/build.c index 3c91cdcfdb..255fd37a01 100644 --- a/src/build.c +++ b/src/build.c @@ -2695,6 +2695,7 @@ Index *sqlite3CreateIndex( pIndex->pTable = pTab; pIndex->nColumn = pList->nExpr; pIndex->onError = (u8)onError; + pIndex->uniqNotNull = onError==OE_Abort; pIndex->autoIndex = (u8)(pName==0); pIndex->pSchema = db->aDb[iDb].pSchema; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); @@ -2753,6 +2754,7 @@ Index *sqlite3CreateIndex( pIndex->azColl[i] = zColl; requestedSortOrder = pListItem->sortOrder & sortOrderMask; pIndex->aSortOrder[i] = (u8)requestedSortOrder; + if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0; } sqlite3DefaultRowEst(pIndex); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e99098cd0a..2b07d2ef02 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1544,6 +1544,7 @@ struct Index { u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ + unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ #ifdef SQLITE_ENABLE_STAT3 int nSample; /* Number of elements in aSample[] */ tRowcnt avgEq; /* Average nEq value for key values not in aSample */ @@ -1889,6 +1890,11 @@ typedef u64 Bitmask; */ #define BMS ((int)(sizeof(Bitmask)*8)) +/* +** A bit in a Bitmask +*/ +#define MASKBIT(n) (((Bitmask)1)<<(n)) + /* ** The following structure describes the FROM clause of a SELECT statement. ** Each table or subquery in the FROM clause is a separate element of diff --git a/src/where.c b/src/where.c index 57dc7e8aef..7577acbfb3 100644 --- a/src/where.c +++ b/src/where.c @@ -327,7 +327,7 @@ struct WhereLoopBuilder { #define WHERE_INDEXED 0x00000200 /* WhereLoop.u.btree.pIndex is valid */ #define WHERE_VIRTUALTABLE 0x00000400 /* WhereLoop.u.vtab is valid */ #define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */ -#define WHERE_UNIQUE 0x00001000 /* Selects no more than one row */ +#define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ #define WHERE_TEMP_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_COVER_SCAN 0x00008000 /* Full scan of a covering index */ @@ -482,7 +482,7 @@ static Bitmask getMask(WhereMaskSet *pMaskSet, int iCursor){ assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 ); for(i=0; in; i++){ if( pMaskSet->ix[i]==iCursor ){ - return ((Bitmask)1)<a; pTermnTermu.leftColumn; - Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); if( (idxCols & cMask)==0 ){ @@ -1860,14 +1860,14 @@ static void constructAutomaticIndex( ** original table changes and the index and table cannot both be used ** if they go out of sync. */ - extraCols = pSrc->colUsed & (~idxCols | (((Bitmask)1)<<(BMS-1))); + extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol; testcase( pTable->nCol==BMS-1 ); testcase( pTable->nCol==BMS-2 ); for(i=0; icolUsed & (((Bitmask)1)<<(BMS-1)) ){ + if( pSrc->colUsed & MASKBIT(BMS-1) ){ nColumn += pTable->nCol - BMS + 1; } pLoop->wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY; @@ -1891,7 +1891,7 @@ static void constructAutomaticIndex( for(pTerm=pWC->a; pTermu.leftColumn; - Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); if( (idxCols & cMask)==0 ){ Expr *pX = pTerm->pExpr; idxCols |= cMask; @@ -1907,13 +1907,13 @@ static void constructAutomaticIndex( /* Add additional columns needed to make the automatic index into ** a covering index */ for(i=0; iaiColumn[n] = i; pIdx->azColl[n] = "BINARY"; n++; } } - if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){ + if( pSrc->colUsed & MASKBIT(BMS-1) ){ for(i=BMS-1; inCol; i++){ pIdx->aiColumn[n] = i; pIdx->azColl[n] = "BINARY"; @@ -3390,7 +3390,7 @@ static Bitmask codeOneLoopStart( /* Record the instruction used to terminate the loop. Disable ** WHERE clause terms made redundant by the index range scan. */ - if( pLoop->wsFlags & WHERE_UNIQUE ){ + if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; }else if( bRev ){ pLevel->op = OP_Prev; @@ -4004,6 +4004,7 @@ static int whereLoopAddBtreeIndex( if( pNew->nTerm>=pBuilder->mxTerm ) break; /* Repeated column in index */ pNew->aTerm[pNew->nTerm++] = pTerm; pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~pNew->maskSelf; + pNew->rRun = rLogSize; if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; pNew->wsFlags |= WHERE_COLUMN_IN; @@ -4014,22 +4015,27 @@ static int whereLoopAddBtreeIndex( /* "x IN (value, value, ...)" */ nIn = pExpr->x.pList->nExpr; } + pNew->rRun *= nIn; pNew->u.btree.nEq++; pNew->nOut = (double)iRowEst * nInMul * nIn; }else if( pTerm->eOperator & (WO_EQ) ){ + assert( (pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 + || nInMul==1 ); pNew->wsFlags |= WHERE_COLUMN_EQ; - if( iCol<0 + if( iCol<0 || (pProbe->onError==OE_Abort && nInMul==1 && pNew->u.btree.nEq==pProbe->nColumn-1) ){ - pNew->wsFlags |= WHERE_UNIQUE; + testcase( pNew->wsFlags & WHERE_COLUMN_IN ); + pNew->wsFlags |= WHERE_ONEROW; } pNew->u.btree.nEq++; pNew->nOut = (double)iRowEst * nInMul; }else if( pTerm->eOperator & (WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_NULL; pNew->u.btree.nEq++; - pNew->nOut = (double)iRowEst * nInMul; + nIn = 2; /* Assume IS NULL matches two rows */ + pNew->nOut = (double)iRowEst * nInMul * nIn; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; @@ -4040,7 +4046,6 @@ static int whereLoopAddBtreeIndex( pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? pNew->aTerm[pNew->nTerm-2] : 0; } - pNew->rRun = rLogSize*nIn; /* Cost for nIn binary searches */ if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ /* Adjust nOut and rRun for STAT3 range values */ double rDiv; @@ -4218,7 +4223,7 @@ static int whereLoopAddBtree( for(j=pProbe->nColumn-1; j>=0; j--){ int x = pProbe->aiColumn[j]; if( xwsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; @@ -4529,7 +4534,7 @@ whereLoopAddAll_end: } /* -** Examine a WherePath (with the addition of the extra WhereLoop of the 4th +** Examine a WherePath (with the addition of the extra WhereLoop of the 5th ** parameters) to see if it outputs rows in the requested ORDER BY ** (or GROUP BY) without requiring a separate source operation. Return: ** @@ -4542,52 +4547,50 @@ static int wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ WherePath *pPath, /* The WherePath to check */ int nLoop, /* Number of entries in pPath->aLoop[] */ - int isLastLoop, /* True for the very last loop */ + int isLastLoop, /* True if pLast is the inner-most loop */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* Mask of WhereLoops to run in reverse order */ ){ u8 revSet; /* True if rev is known */ u8 rev; /* Composite sort order */ u8 revIdx; /* Index sort order */ - u8 isOneRow; /* Current WhereLoop is a one-row loop */ - u8 requireOneRow = 0; /* All subsequent loops must be one-row */ - u8 isUniqueIdx; /* Current WhereLoop uses a unique index */ - u16 nColumn; - u16 nOrderBy; - int i, j; - int nUsed = 0; - int iCur; - int iColumn; - WhereLoop *pLoop; - ExprList *pOrderBy = pWInfo->pOrderBy; - Expr *pOBExpr; - CollSeq *pColl; - Index *pIndex; - sqlite3 *db = pWInfo->pParse->db; - Bitmask revMask = 0; + u8 isWellOrdered; /* All WhereLoops are well-ordered so far */ + u16 nColumn; /* Number of columns in pIndex */ + u16 nOrderBy; /* Number terms in the ORDER BY clause */ + int iLoop; /* Index of WhereLoop in pPath being processed */ + int i, j; /* Loop counters */ + int iCur; /* Cursor number for current WhereLoop */ + int iColumn; /* A column number within table iCur */ + WhereLoop *pLoop; /* Current WhereLoop being processed. */ + ExprList *pOrderBy = pWInfo->pOrderBy; /* the ORDER BY clause */ + WhereTerm *pTerm; /* A single term of the WHERE clause */ + Expr *pOBExpr; /* An expression from the ORDER BY clause */ + CollSeq *pColl; /* COLLATE function from an ORDER BY clause term */ + Index *pIndex; /* The index associated with pLoop */ + sqlite3 *db = pWInfo->pParse->db; /* Database connection */ + Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ + Bitmask obDone; /* Mask of all ORDER BY terms */ + Bitmask orderedMask; /* Mask of all well-ordered loops */ + WhereMaskSet *pMaskSet; /* WhereMaskSet object for this where clause */ + /* - ** We say the WhereLoop is "one-row" if all of the following are true: + ** We say the WhereLoop is "one-row" if it generates no more than one + ** row of output. A WhereLoop is one-row if all of the following are true: ** (a) All index columns match with WHERE_COLUMN_EQ. ** (b) The index is unique + ** Any WhereLoop with an WHERE_COLUMN_EQ constraint on the rowid is one-row. + ** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags. ** - ** General rules: (not an algorithm!) - ** - ** (1) If the current WhereLoop is one-row, then match over any and all - ** ORDER BY terms for the current WhereLoop and proceed to the next - ** WhereLoop. - ** - ** (2) If the current WhereLoop is not one-row, then all subsequent - ** WhereLoops must be one-row. - ** - ** (3) Optionally match any ORDER BY terms against the first nEq columns - ** of the index. - ** - ** (4) Index columns past nEq must match ORDER BY terms one-for-one. - ** - ** (5) If all columns of a UNIQUE index have been matched against ORDER BY - ** terms, then any subsequent entries in the ORDER BY clause against the - ** same table can be skipped. + ** We say the WhereLoop is "well-ordered" if + ** (i) it satisfies at least one term of the ORDER BY clause, and + ** (ii) every row output is distinct over the terms that match the + ** ORDER BY clause. + ** Every one-row WhereLoop is automatically well-ordered, even if it + ** does not match any terms of the ORDER BY clause. + ** For condition (ii), be mindful that a UNIQUE column can have multiple + ** rows that are NULL and so it not necessarily distinct. The column + ** must be UNIQUE and NOT NULL. in order to be well-ordered. */ assert( pOrderBy!=0 ); @@ -4595,95 +4598,152 @@ static int wherePathSatisfiesOrderBy( /* Sortability of virtual tables is determined by the xBestIndex method ** of the virtual table itself */ if( pLast->wsFlags & WHERE_VIRTUALTABLE ){ - assert( nLoop==0 ); + testcase( nLoop>0 ); /* True when outer loops are one-row and match + ** no ORDER BY terms */ return pLast->u.vtab.isOrdered; } + if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; - /* Sorting is always required if any term of the ORDER BY is not a - ** column reference */ nOrderBy = pOrderBy->nExpr; -#if 0 - for(i=0; ia[i].pExpr); - if( pOBExpr->op!=TK_COLUMN ) return 0; - } -#endif - - for(i=0; i<=nLoop && nUsedaLoop[i] : pLast; + if( nOrderBy>60 ) return 0; + isWellOrdered = 1; + obDone = MASKBIT(nOrderBy)-1; + orderedMask = 0; + pMaskSet = pWInfo->pWC->pMaskSet; + for(iLoop=0; isWellOrdered && obSataLoop[iLoop] : pLast; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); - isOneRow = isUniqueIdx = 1; - if( pLoop->wsFlags & WHERE_IPK ){ - if( (pLoop->wsFlags & WHERE_COLUMN_IN)!=0 ) isOneRow = 0; - if( pLoop->u.btree.nEq!=1 ) isOneRow = 0; - pIndex = 0; - nColumn = 0; - }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ - return 0; - }else{ - nColumn = pIndex->nColumn; - if( pIndex->onError==OE_None ){ - isOneRow = isUniqueIdx = 0; - }else if( (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_RANGE - |WHERE_COLUMN_NULL))!=0 ){ - isOneRow = 0; - }else if( pLoop->u.btree.nEq < pIndex->nColumn ){ - isOneRow = 0; - } - } - if( !isOneRow && requireOneRow ) return 0; - requireOneRow = !isOneRow; iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; - j = 0; - revSet = rev = 0; - for(j=0; j<=nColumn && nUseda[nUsed].pExpr); - if( pOBExpr->op!=TK_COLUMN ) return 0; - if( pOBExpr->iTable!=iCur ) break; - if( isOneRow ){ j--; continue; } - if( jaiColumn[j]; - revIdx = pIndex->aSortOrder[j]; - if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; - }else{ - /* The ROWID column at the end */ - iColumn = -1; - revIdx = 0; - } - skipable = ju.btree.nEq && pLoop->aTerm[j]->eOperator!=WO_IN; - if( pOBExpr->iColumn!=iColumn ){ - if( skipable ){ nUsed--; continue; } + if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ + if( pLoop->wsFlags & WHERE_IPK ){ + pIndex = 0; + nColumn = 0; + }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; + }else{ + nColumn = pIndex->nColumn; } - if( iColumn>=0 ){ - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[nUsed].pExpr); - if( !pColl ) pColl = db->pDfltColl; - if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ){ - return 0; + + /* For every term of the index that is constrained by == or IS NULL + ** mark off corresponding ORDER BY terms wherever they occur + ** in the ORDER BY clause. + */ + for(i=0; iu.btree.nEq; i++){ + pTerm = pLoop->aTerm[i]; + if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))==0 ) continue; + iColumn = pTerm->u.leftColumn; + for(j=0; ja[j].pExpr); + if( pOBExpr->op!=TK_COLUMN ) continue; + if( pOBExpr->iTable!=iCur ) continue; + if( pOBExpr->iColumn!=iColumn ) continue; + if( iColumn>=0 ){ + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[j].pExpr); + if( !pColl ) pColl = db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pIndex->azColl[i])!=0 ) continue; + } + obSat |= MASKBIT(j); } + if( obSat==obDone ) return 1; } - if( !skipable ){ - if( revSet ){ - if( (rev ^ revIdx)!=pOrderBy->a[nUsed].sortOrder ) return 0; + + /* Loop through all columns of the index and deal with the ones + ** that are not constrained by == or IN. + */ + rev = revSet = 0; + for(j=0; j<=nColumn; j++){ + u8 bOnce; /* True to run the ORDER BY search loop */ + + if( ju.btree.nEq + && (pLoop->aTerm[j]->eOperator & (WO_EQ|WO_ISNULL))!=0 + ){ + continue; /* Skip == and IS NULL terms already processed */ + } + + /* Get the column number in the table and sort order for the + ** j-th column of the index for this WhereLoop + */ + if( jaiColumn[j]; + revIdx = pIndex->aSortOrder[j]; + if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; }else{ - rev = revIdx ^ pOrderBy->a[nUsed].sortOrder; - revSet = 1; + /* The ROWID column at the end */ + iColumn = -1; + revIdx = 0; + } + + /* An unconstrained column that might be NULL means that this + ** WhereLoop is not well-ordered + */ + if( iColumn>=0 + && j>=pLoop->u.btree.nEq + && pIndex->pTable->aCol[iColumn].notNull==0 + ){ + isWellOrdered = 0; + } + + /* Find the ORDER BY term that corresponds to the j-th column + ** of the index and and mark that ORDER BY term off + */ + bOnce = 1; + for(i=0; bOnce && ia[i].pExpr); + if( pOBExpr->op!=TK_COLUMN ) continue; + if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ) bOnce = 0; + if( pOBExpr->iTable!=iCur ) continue; + if( pOBExpr->iColumn!=iColumn ) continue; + if( iColumn>=0 ){ + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); + if( !pColl ) pColl = db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; + } + bOnce = 1; + break; + } + if( bOnce && iwctrlFlags & WHERE_GROUPBY)==0 ){ + /* If we have an ORDER BY clause, we must match the next available + ** column of the ORDER BY */ + if( revSet ){ + if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0; + }else{ + rev = revIdx ^ pOrderBy->a[i].sortOrder; + if( rev ) *pRevMask |= MASKBIT(iLoop); + revSet = 1; + } + } + }else{ + /* No match found */ + if( jonError!=OE_Abort ){ + isWellOrdered = 0; + } + break; + } + } /* end Loop over all index columns */ + } /* end-if not one-row */ + + /* Mark off any other ORDER BY terms that reference pLoop */ + if( isWellOrdered ){ + orderedMask |= pLoop->maskSelf; + for(i=0; ia[i].pExpr; + if( (exprTableUsage(pMaskSet, p)&~orderedMask)==0 ){ + obSat |= MASKBIT(i); } - } - if( j>=nColumn-1 && isUniqueIdx ){ - if( isLastLoop && i==nLoop ) break; - j--; - isOneRow = 1; } } - if( rev ) revMask |= ((Bitmask)1)<nLevel==1 ); - if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 && (andFlags & WHERE_UNIQUE)!=0 ){ + if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 && (andFlags & WHERE_ONEROW)!=0 ){ pWInfo->okOnePass = 1; pWInfo->a[0].plan.wsFlags &= ~WHERE_IDX_ONLY; } diff --git a/test/tkt-2a5629202f.test b/test/tkt-2a5629202f.test index 037f100f65..5f31d1ecc0 100644 --- a/test/tkt-2a5629202f.test +++ b/test/tkt-2a5629202f.test @@ -46,6 +46,12 @@ do_execsql_test 1.3 { SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c } {null/four null/three a/one b/two} +do_execsql_test 1.4 { + DROP INDEX t8; + CREATE UNIQUE INDEX i1 ON t8(b, c); + SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c +} {null/four null/three a/one b/two} + #------------------------------------------------------------------------- # @@ -68,4 +74,3 @@ do_test 2.4 { } {sort} finish_test - From ef71c1f0904e1e3b245ef9a26dc8bcdcb4064ccb Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Jun 2013 12:58:02 +0000 Subject: [PATCH 075/144] Fix a display issue with EXPLAIN QUERY PLAN. FossilOrigin-Name: ff2fa407558360f2499b6df0392ab3cdb4788dec --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 3b65c600a9..5e757202a7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactor\sthe\sORDER\sBY\soptimizer\sin\sthe\sNGQP\sso\sthat\sit\sis\seasier\sto\smaintain\nand\sso\sthat\sit\scan\ssupport\soptimizing\sout\sGROUP\sBY\sand\sDISTINCT\sclauses. -D 2013-06-04T12:42:29.293 +C Fix\sa\sdisplay\sissue\swith\sEXPLAIN\sQUERY\sPLAN. +D 2013-06-04T12:58:02.050 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c cca3284b915ee9c51dd9188e3a74e648ddf3db47 +F src/where.c 89e9e0180fb061529c2335483e698461020008b3 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P eb27086e8a8a4d5fcb2ea358256a555e34339423 -R 3dd8dcdfd7f56eca682f5b0b9f200abc +P e605c468e3a1163167831c4a6220825c0b5d083b +R 0c3dd4aecffc3c33e948e0ad3535455c U drh -Z 6cf52a3b39b332b4094772bd0e2b3942 +Z fde826e1fa4a5f4defa852132d2e9311 diff --git a/manifest.uuid b/manifest.uuid index 7dcbb18dc0..b2ed6c1c78 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e605c468e3a1163167831c4a6220825c0b5d083b \ No newline at end of file +ff2fa407558360f2499b6df0392ab3cdb4788dec \ No newline at end of file diff --git a/src/where.c b/src/where.c index 7577acbfb3..fa06259d67 100644 --- a/src/where.c +++ b/src/where.c @@ -319,6 +319,7 @@ struct WhereLoopBuilder { #define WHERE_COLUMN_RANGE 0x00000002 /* xEXPR */ #define WHERE_COLUMN_IN 0x00000004 /* x IN (...) */ #define WHERE_COLUMN_NULL 0x00000008 /* x IS NULL */ +#define WHERE_CONSTRAINT 0x0000000f /* Any of the WHERE_COLUMN_xxx values */ #define WHERE_TOP_LIMIT 0x00000010 /* xEXPR or x>=EXPR constraint */ #define WHERE_BOTH_LIMIT 0x00000030 /* Both x>EXPR and x Date: Tue, 4 Jun 2013 13:07:44 +0000 Subject: [PATCH 076/144] Increase the estimated full-scan cost for an FTS3 table. FossilOrigin-Name: 8d9f29f847f38612447c79a5fb366a9143ef6205 --- ext/fts3/fts3.c | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 374d690688..e3a11b301a 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1423,7 +1423,7 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ ** strategy is possible. */ pInfo->idxNum = FTS3_FULLSCAN_SEARCH; - pInfo->estimatedCost = 500000; + pInfo->estimatedCost = 5000000; for(i=0; inConstraint; i++){ struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; if( pCons->usable==0 ) continue; diff --git a/manifest b/manifest index 5e757202a7..1046753ec0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sdisplay\sissue\swith\sEXPLAIN\sQUERY\sPLAN. -D 2013-06-04T12:58:02.050 +C Increase\sthe\sestimated\sfull-scan\scost\sfor\san\sFTS3\stable. +D 2013-06-04T13:07:44.387 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -78,7 +78,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 931b3c83abdd1ab3bb389b2130431c2a9ff73b91 +F ext/fts3/fts3.c 760fecd100598dc22f9733d472b7cf2e9375c620 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 0b167bed9e63151635620a4f639bc62ac6012cba F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P e605c468e3a1163167831c4a6220825c0b5d083b -R 0c3dd4aecffc3c33e948e0ad3535455c +P ff2fa407558360f2499b6df0392ab3cdb4788dec +R 5715088460a26a1980fd1c02022e33fe U drh -Z fde826e1fa4a5f4defa852132d2e9311 +Z e8fb494e500ca7853631ddff96a44d93 diff --git a/manifest.uuid b/manifest.uuid index b2ed6c1c78..c6152c2bac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff2fa407558360f2499b6df0392ab3cdb4788dec \ No newline at end of file +8d9f29f847f38612447c79a5fb366a9143ef6205 \ No newline at end of file From ee73b87181bbbda3e00b172c42613bccbf1bf6d7 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Jun 2013 13:37:26 +0000 Subject: [PATCH 077/144] Better determination of when an index is UNIQUE. FossilOrigin-Name: 63fd025ad98c33826342824c51436ac92e2bb579 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 1046753ec0..7cdae30fd3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increase\sthe\sestimated\sfull-scan\scost\sfor\san\sFTS3\stable. -D 2013-06-04T13:07:44.387 +C Better\sdetermination\sof\swhen\san\sindex\sis\sUNIQUE. +D 2013-06-04T13:37:26.983 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 89e9e0180fb061529c2335483e698461020008b3 +F src/where.c 07d741484ae3f3758ec7e9a607bebc9ca3d04830 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ff2fa407558360f2499b6df0392ab3cdb4788dec -R 5715088460a26a1980fd1c02022e33fe +P 8d9f29f847f38612447c79a5fb366a9143ef6205 +R 816acabe38521333f8c2b91e9413c2fb U drh -Z e8fb494e500ca7853631ddff96a44d93 +Z 7aae80e9f7f08a338e021a4d83d77e82 diff --git a/manifest.uuid b/manifest.uuid index c6152c2bac..603eff6cc4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8d9f29f847f38612447c79a5fb366a9143ef6205 \ No newline at end of file +63fd025ad98c33826342824c51436ac92e2bb579 \ No newline at end of file diff --git a/src/where.c b/src/where.c index fa06259d67..4c062435c6 100644 --- a/src/where.c +++ b/src/where.c @@ -4024,7 +4024,7 @@ static int whereLoopAddBtreeIndex( || nInMul==1 ); pNew->wsFlags |= WHERE_COLUMN_EQ; if( iCol<0 - || (pProbe->onError==OE_Abort && nInMul==1 + || (pProbe->onError!=OE_None && nInMul==1 && pNew->u.btree.nEq==pProbe->nColumn-1) ){ testcase( pNew->wsFlags & WHERE_COLUMN_IN ); @@ -4721,7 +4721,7 @@ static int wherePathSatisfiesOrderBy( } }else{ /* No match found */ - if( jonError!=OE_Abort ){ + if( jonError==OE_None ){ isWellOrdered = 0; } break; From aec93a1f2d37aa86e8174a4ef5be065c9b4dc3b3 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Jun 2013 15:31:16 +0000 Subject: [PATCH 078/144] Test case updates. FossilOrigin-Name: 0360fec7c093870269211447e9642b5ee34ff778 --- manifest | 12 ++--- manifest.uuid | 2 +- test/orderby1.test | 125 ++++++++++++++++++++++++++------------------- 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/manifest b/manifest index 7cdae30fd3..076d503589 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Better\sdetermination\sof\swhen\san\sindex\sis\sUNIQUE. -D 2013-06-04T13:37:26.983 +C Test\scase\supdates. +D 2013-06-04T15:31:16.980 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -690,7 +690,7 @@ F test/notnull.test 2afad748d18fd66d01f66463de73b3e2501fb226 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 -F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae +F test/orderby1.test 3c5ff32c23364fb3d567ad53b945837736e701ce F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99 F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 8d9f29f847f38612447c79a5fb366a9143ef6205 -R 816acabe38521333f8c2b91e9413c2fb +P 63fd025ad98c33826342824c51436ac92e2bb579 +R 67e11291890a37d4a1f5e5249ecb5cb8 U drh -Z 7aae80e9f7f08a338e021a4d83d77e82 +Z 7007403ff7385bdec3d57bd5a78d418a diff --git a/manifest.uuid b/manifest.uuid index 603eff6cc4..314ab804b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -63fd025ad98c33826342824c51436ac92e2bb579 \ No newline at end of file +0360fec7c093870269211447e9642b5ee34ff778 \ No newline at end of file diff --git a/test/orderby1.test b/test/orderby1.test index f459fc8195..73ecb67dc7 100644 --- a/test/orderby1.test +++ b/test/orderby1.test @@ -48,7 +48,7 @@ do_test 1.0 { } {} do_test 1.1a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -66,7 +66,7 @@ do_test 1.1b { # do_test 1.2a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -75,7 +75,7 @@ do_test 1.2a { do_test 1.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -85,13 +85,13 @@ do_test 1.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 1.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -101,55 +101,58 @@ db cache flush # do_test 1.4a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 1.4b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 1.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } -} {~/ORDER BY/} ;# optimized out +} {/ORDER BY/} ;# separate sorting pass due to mixed DESC/ASC do_test 1.5a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 1.5b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 1.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } -} {~/ORDER BY/} ;# optimized out +} {/ORDER BY/} ;# separate sorting pass due to mixed DESC/ASC do_test 1.6a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 1.6b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 1.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY title DESC, tn DESC } -} {~/ORDER BY/} ;# ORDER BY optimized-out +} {~/ORDER BY/} ;# ORDER BY # Reconstruct the test data to use indices rather than integer primary keys. @@ -183,7 +186,7 @@ do_test 2.0 { } {} do_test 2.1a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -192,28 +195,28 @@ do_test 2.1a { do_test 2.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } -} {~/ORDER BY/} ;# ORDER BY optimized out +} {/ORDER BY/} ;# ORDER BY required because of missing aid term in ORDER BY do_test 2.1c { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.1d { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn } -} {~/ORDER BY/} ;# ORDER BY optimized out +} {/ORDER BY/} ;# ORDER BY required in this case # The same query with ORDER BY clause optimization disabled via + operators # should give exactly the same answer. # do_test 2.2a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -222,7 +225,7 @@ do_test 2.2a { do_test 2.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -232,13 +235,13 @@ do_test 2.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -248,55 +251,55 @@ db cache flush # do_test 2.4a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 2.4b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 2.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn } -} {~/ORDER BY/} ;# optimized out +} {/ORDER BY/} ;# separate sorting pass due to mixed DESC/ASC do_test 2.5a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 2.5b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 2.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } -} {~/ORDER BY/} ;# optimized out +} {/ORDER BY/} ;# separate sorting pass due to mixed ASC/DESC do_test 2.6a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 2.6b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 2.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } -} {~/ORDER BY/} ;# ORDER BY optimized out +} {/ORDER BY/} ;# ORDER BY required # Generate another test dataset, but this time using mixed ASC/DESC indices. @@ -348,7 +351,7 @@ do_test 3.1b { # do_test 3.2a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} @@ -357,7 +360,7 @@ do_test 3.2a { do_test 3.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -367,13 +370,13 @@ do_test 3.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 3.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -383,38 +386,38 @@ db cache flush # do_test 3.4a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 3.4b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} ;# verify same order after sorting do_test 3.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } -} {~/ORDER BY/} ;# optimized out +} {/ORDER BY/} ;# separate sorting pass due to mismatched DESC/ASC do_test 3.5a { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 3.5b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 3.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC } -} {~/ORDER BY/} ;# optimzed out +} {/ORDER BY/} ;# separate sorting pass due to mismatched ASC/DESC do_test 3.6a { @@ -424,7 +427,8 @@ do_test 3.6a { } {three-a three-c two-a two-b one-a one-c} do_test 3.6b { db eval { - SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) + ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 3.6c { @@ -434,5 +438,22 @@ do_test 3.6c { } } {~/ORDER BY/} ;# inverted ASC/DESC is optimized out +# Ticket 5ed1772895bf3deeab78c5e3519b1da9165c541b (2013-06-04) +# Incorrect ORDER BY on an indexed JOIN +# +do_test 4.0 { + db eval { + CREATE TABLE t41(a INT UNIQUE NOT NULL, b INT NOT NULL); + CREATE INDEX t41ba ON t41(b,a); + CREATE TABLE t42(x INT NOT NULL REFERENCES t41(a), y INT NOT NULL); + CREATE UNIQUE INDEX t42xy ON t42(x,y); + INSERT INTO t41 VALUES(1,1),(3,1); + INSERT INTO t42 VALUES(1,13),(1,15),(3,14),(3,16); + + SELECT b, y FROM t41 CROSS JOIN t42 ON x=a ORDER BY b, y; + } +} {1 13 1 14 1 15 1 16} + + finish_test From 907717fe074d5f5b44b40b7f868b0b2447d3e470 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Jun 2013 18:03:22 +0000 Subject: [PATCH 079/144] Get the index-only optimization working for OR queries. FossilOrigin-Name: 774d5ff857cfad3471401ed518ed0959eb912e6c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 076d503589..7dd0d0fc27 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\scase\supdates. -D 2013-06-04T15:31:16.980 +C Get\sthe\sindex-only\soptimization\sworking\sfor\sOR\squeries. +D 2013-06-04T18:03:22.637 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 07d741484ae3f3758ec7e9a607bebc9ca3d04830 +F src/where.c e46c09e1fb10d9b9822441cbc0e92712d68b193c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 63fd025ad98c33826342824c51436ac92e2bb579 -R 67e11291890a37d4a1f5e5249ecb5cb8 +P 0360fec7c093870269211447e9642b5ee34ff778 +R 0af0bd237ed8aa13c84924b3ff155245 U drh -Z 7007403ff7385bdec3d57bd5a78d418a +Z c037722d2012f6d1382fb3f047d6db42 diff --git a/manifest.uuid b/manifest.uuid index 314ab804b9..07874c82c4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0360fec7c093870269211447e9642b5ee34ff778 \ No newline at end of file +774d5ff857cfad3471401ed518ed0959eb912e6c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4c062435c6..885a15df35 100644 --- a/src/where.c +++ b/src/where.c @@ -3593,7 +3593,7 @@ static Bitmask codeOneLoopStart( && (ii==0 || pSubLoop->u.btree.pIndex==pCov) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); - pCov = pLoop->u.btree.pIndex; + pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; } From d84ce35bfdae2a4bb25eeb2e808d94f9ba0286a3 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Jun 2013 18:27:41 +0000 Subject: [PATCH 080/144] Restore the PRAGMA reverse_unordered_selects behavior. FossilOrigin-Name: f49cd6c4e752e39801f9d5de0bc370d26f43837c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 7dd0d0fc27..487bb8cc30 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\sthe\sindex-only\soptimization\sworking\sfor\sOR\squeries. -D 2013-06-04T18:03:22.637 +C Restore\sthe\sPRAGMA\sreverse_unordered_selects\sbehavior. +D 2013-06-04T18:27:41.462 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e46c09e1fb10d9b9822441cbc0e92712d68b193c +F src/where.c cc1e1a7255b6722a419d6a5016d89f227e7a9ce7 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 0360fec7c093870269211447e9642b5ee34ff778 -R 0af0bd237ed8aa13c84924b3ff155245 +P 774d5ff857cfad3471401ed518ed0959eb912e6c +R a1a3ee93fd22dda060fc640b96157ac6 U drh -Z c037722d2012f6d1382fb3f047d6db42 +Z ec57b78c26a34e23e063493e6b075b85 diff --git a/manifest.uuid b/manifest.uuid index 07874c82c4..dd954ef445 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -774d5ff857cfad3471401ed518ed0959eb912e6c \ No newline at end of file +f49cd6c4e752e39801f9d5de0bc370d26f43837c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 885a15df35..3bb15bdc96 100644 --- a/src/where.c +++ b/src/where.c @@ -5250,6 +5250,8 @@ WhereInfo *sqlite3WhereBegin( if( pWInfo->pOrderBy ){ wherePathSolver(pWInfo, pWInfo->nRowOut); if( db->mallocFailed ) goto whereBeginError; + }else if( db->flags & SQLITE_ReverseOrder ){ + pWInfo->revMask = (Bitmask)(-1); } if( pParse->nErr || db->mallocFailed ){ goto whereBeginError; From e353ee3898ce329271e8b4dd726307e730907601 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Jun 2013 23:40:53 +0000 Subject: [PATCH 081/144] Update some variable names and comments in the ORDER BY optimizer. Fix a bug in the ORDER BY optimizer dealing with IS NULL constraints. Updates to test cases. FossilOrigin-Name: cf96eb5945a9bab71104cb1581ee13ab30022566 --- manifest | 14 ++++----- manifest.uuid | 2 +- src/where.c | 82 +++++++++++++++++++++++++++--------------------- test/where3.test | 12 +++---- 4 files changed, 60 insertions(+), 50 deletions(-) diff --git a/manifest b/manifest index 487bb8cc30..7b304b267b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Restore\sthe\sPRAGMA\sreverse_unordered_selects\sbehavior. -D 2013-06-04T18:27:41.462 +C Update\ssome\svariable\snames\sand\scomments\sin\sthe\sORDER\sBY\soptimizer.\s\sFix\sa\nbug\sin\sthe\sORDER\sBY\soptimizer\sdealing\swith\sIS\sNULL\sconstraints.\s\sUpdates\nto\stest\scases. +D 2013-06-04T23:40:53.563 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c cc1e1a7255b6722a419d6a5016d89f227e7a9ce7 +F src/where.c 0b8fd61de3c71df0ba084d13177c384bb50e4d22 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1030,7 +1030,7 @@ F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81 F test/where2.test 116fb0d6e98a423d12eb9a65906218ce09936674 -F test/where3.test ae3054e1216ecc0afbcb83674310ebc5de25ba09 +F test/where3.test 311c04e16f72816616d05d96dd354db7bce545eb F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 774d5ff857cfad3471401ed518ed0959eb912e6c -R a1a3ee93fd22dda060fc640b96157ac6 +P f49cd6c4e752e39801f9d5de0bc370d26f43837c +R e9f7dc193466abcd06681335597fcecc U drh -Z ec57b78c26a34e23e063493e6b075b85 +Z dc06d4669e35a15ef353fefc6b023d96 diff --git a/manifest.uuid b/manifest.uuid index dd954ef445..269a302e79 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f49cd6c4e752e39801f9d5de0bc370d26f43837c \ No newline at end of file +cf96eb5945a9bab71104cb1581ee13ab30022566 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 3bb15bdc96..d9dccf7541 100644 --- a/src/where.c +++ b/src/where.c @@ -4555,7 +4555,9 @@ static int wherePathSatisfiesOrderBy( u8 revSet; /* True if rev is known */ u8 rev; /* Composite sort order */ u8 revIdx; /* Index sort order */ - u8 isWellOrdered; /* All WhereLoops are well-ordered so far */ + u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */ + u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */ + u8 isMatch; /* iColumn matches a term of the ORDER BY clause */ u16 nColumn; /* Number of columns in pIndex */ u16 nOrderBy; /* Number terms in the ORDER BY clause */ int iLoop; /* Index of WhereLoop in pPath being processed */ @@ -4571,8 +4573,8 @@ static int wherePathSatisfiesOrderBy( sqlite3 *db = pWInfo->pParse->db; /* Database connection */ Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ Bitmask obDone; /* Mask of all ORDER BY terms */ - Bitmask orderedMask; /* Mask of all well-ordered loops */ - WhereMaskSet *pMaskSet; /* WhereMaskSet object for this where clause */ + Bitmask orderDistinctMask; /* Mask of all well-ordered loops */ + WhereMaskSet *pMaskSet; /* WhereMaskSet object for this where clause */ /* @@ -4583,15 +4585,18 @@ static int wherePathSatisfiesOrderBy( ** Any WhereLoop with an WHERE_COLUMN_EQ constraint on the rowid is one-row. ** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags. ** - ** We say the WhereLoop is "well-ordered" if - ** (i) it satisfies at least one term of the ORDER BY clause, and - ** (ii) every row output is distinct over the terms that match the - ** ORDER BY clause. - ** Every one-row WhereLoop is automatically well-ordered, even if it - ** does not match any terms of the ORDER BY clause. - ** For condition (ii), be mindful that a UNIQUE column can have multiple - ** rows that are NULL and so it not necessarily distinct. The column - ** must be UNIQUE and NOT NULL. in order to be well-ordered. + ** We say the WhereLoop is "order-distinct" if the set of columns from + ** that WhereLoop that are in the ORDER BY clause are different for every + ** row of the WhereLoop. Every one-row WhereLoop is automatically + ** order-distinct. A WhereLoop that has no columns in the ORDER BY clause + ** is not order-distinct. To be order-distinct is not quite the same as being + ** UNIQUE since a UNIQUE column or index can have multiple rows that + ** are NULL and NULL values are equivalent for the purpose of order-distinct. + ** To be order-distinct, the columns must be UNIQUE and NOT NULL. + ** + ** The rowid for a table is always UNIQUE and NOT NULL so whenever the + ** rowid appears in the ORDER BY clause, the corresponding WhereLoop is + ** automatically order-distinct. */ assert( pOrderBy!=0 ); @@ -4606,12 +4611,12 @@ static int wherePathSatisfiesOrderBy( if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; nOrderBy = pOrderBy->nExpr; - if( nOrderBy>60 ) return 0; - isWellOrdered = 1; + if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ + isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; - orderedMask = 0; + orderDistinctMask = 0; pMaskSet = pWInfo->pWC->pMaskSet; - for(iLoop=0; isWellOrdered && obSataLoop[iLoop] : pLast; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; @@ -4623,9 +4628,10 @@ static int wherePathSatisfiesOrderBy( return 0; }else{ nColumn = pIndex->nColumn; + isOrderDistinct = pIndex->onError!=OE_None; } - /* For every term of the index that is constrained by == or IS NULL + /* For every term of the index that is constrained by == or IS NULL, ** mark off corresponding ORDER BY terms wherever they occur ** in the ORDER BY clause. */ @@ -4653,17 +4659,20 @@ static int wherePathSatisfiesOrderBy( ** that are not constrained by == or IN. */ rev = revSet = 0; + distinctColumns = 0; for(j=0; j<=nColumn; j++){ u8 bOnce; /* True to run the ORDER BY search loop */ + /* Skip over == and IS NULL terms */ if( ju.btree.nEq - && (pLoop->aTerm[j]->eOperator & (WO_EQ|WO_ISNULL))!=0 + && ((i = pLoop->aTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 ){ - continue; /* Skip == and IS NULL terms already processed */ + if( i & WO_ISNULL ) isOrderDistinct = 0; + continue; } - /* Get the column number in the table and sort order for the - ** j-th column of the index for this WhereLoop + /* Get the column number in the table (iColumn) and sort order + ** (revIdx) for the j-th column of the index. */ if( j=0 + if( isOrderDistinct + && iColumn>=0 && j>=pLoop->u.btree.nEq && pIndex->pTable->aCol[iColumn].notNull==0 ){ - isWellOrdered = 0; + isOrderDistinct = 0; } /* Find the ORDER BY term that corresponds to the j-th column ** of the index and and mark that ORDER BY term off */ bOnce = 1; + isMatch = 0; for(i=0; bOnce && ia[i].pExpr); - if( pOBExpr->op!=TK_COLUMN ) continue; if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ) bOnce = 0; + if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; if( iColumn>=0 ){ @@ -4702,15 +4713,15 @@ static int wherePathSatisfiesOrderBy( if( !pColl ) pColl = db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } - bOnce = 1; + isMatch = 1; break; } - if( bOnce && iwctrlFlags & WHERE_GROUPBY)==0 ){ - /* If we have an ORDER BY clause, we must match the next available - ** column of the ORDER BY */ + /* Make sure the sort order is compatible in an ORDER BY clause. + ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0; }else{ @@ -4721,29 +4732,28 @@ static int wherePathSatisfiesOrderBy( } }else{ /* No match found */ - if( jonError==OE_None ){ - isWellOrdered = 0; - } + if( j==0 || jmaskSelf; + if( isOrderDistinct ){ + orderDistinctMask |= pLoop->maskSelf; for(i=0; ia[i].pExpr; - if( (exprTableUsage(pMaskSet, p)&~orderedMask)==0 ){ + if( (exprTableUsage(pMaskSet, p)&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); } } } } if( obSat==obDone ) return 1; - if( !isWellOrdered ) return 0; + if( !isOrderDistinct ) return 0; if( isLastLoop ) return 1; return -1; } diff --git a/test/where3.test b/test/where3.test index c8ec8eb169..842f683749 100644 --- a/test/where3.test +++ b/test/where3.test @@ -190,37 +190,37 @@ do_test where3-2.2 { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=bx } -} {tB {} tA * tC * tD *} +} {tB * tA * tC * tD *} do_test where3-2.3 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=bx } -} {tB {} tA * tC * tD *} +} {tB * tA * tC * tD *} do_test where3-2.4 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE apk=cx AND bpk=ax } -} {tC {} tA * tB * tD *} +} {tC * tA * tB * tD *} do_test where3-2.5 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=ax AND bpk=cx } -} {tA {} tC * tB * tD *} +} {tA * tC * tB * tD *} do_test where3-2.6 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE bpk=cx AND apk=bx } -} {tC {} tB * tA * tD *} +} {tC * tB * tA * tD *} do_test where3-2.7 { queryplan { SELECT * FROM tA, tB, tC LEFT JOIN tD ON dpk=cx WHERE cpk=bx AND apk=cx } -} {tB {} tC * tA * tD *} +} {tB * tC * tA * tD *} # Ticket [13f033c865f878953] # If the outer loop must be a full table scan, do not let ANALYZE trick From 6f403ca45093a939d867b3e1e6f4e07af375b2e7 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Jun 2013 12:18:15 +0000 Subject: [PATCH 082/144] Add a test case contributed on the mailing list that works in NGQP but fails in legacy. FossilOrigin-Name: 96afe50866a08ed14e911c3c955030f7ab83a3ed --- manifest | 11 +++--- manifest.uuid | 2 +- test/contrib01.test | 90 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 test/contrib01.test diff --git a/manifest b/manifest index 7b304b267b..ed506f992c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\ssome\svariable\snames\sand\scomments\sin\sthe\sORDER\sBY\soptimizer.\s\sFix\sa\nbug\sin\sthe\sORDER\sBY\soptimizer\sdealing\swith\sIS\sNULL\sconstraints.\s\sUpdates\nto\stest\scases. -D 2013-06-04T23:40:53.563 +C Add\sa\stest\scase\scontributed\son\sthe\smailing\slist\nthat\sworks\sin\sNGQP\sbut\sfails\sin\slegacy. +D 2013-06-05T12:18:15.188 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -378,6 +378,7 @@ F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6 F test/colmeta.test 087c42997754b8c648819832241daf724f813322 F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b F test/conflict.test 0b3922d2304a14a47e3ccd61bbd6824327af659b +F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4 F test/corrupt.test 4aabd06cff3fe759e3e658bcc17b71789710665e F test/corrupt2.test 9c0ab4becd50e9050bc1ebb8675456a4e5587bf0 F test/corrupt3.test 889d7cdb811800303aa722d7813fe8a4299cf726 @@ -1093,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P f49cd6c4e752e39801f9d5de0bc370d26f43837c -R e9f7dc193466abcd06681335597fcecc +P cf96eb5945a9bab71104cb1581ee13ab30022566 +R 373c05c6780cec478b9924edf49e0658 U drh -Z dc06d4669e35a15ef353fefc6b023d96 +Z c785a25f44da51b36475ec1e8ccfb14e diff --git a/manifest.uuid b/manifest.uuid index 269a302e79..bafc3efa21 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf96eb5945a9bab71104cb1581ee13ab30022566 \ No newline at end of file +96afe50866a08ed14e911c3c955030f7ab83a3ed \ No newline at end of file diff --git a/test/contrib01.test b/test/contrib01.test new file mode 100644 index 0000000000..43ea47c3e4 --- /dev/null +++ b/test/contrib01.test @@ -0,0 +1,90 @@ +# 2013-06-05 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file contains test cases that were contributed on the sqlite-users +# mailing list on 2013-06-05 by Mi Chen at mi.chen@echostar.com. +# +# At the time it was contributed, this test failed on trunk, but +# worked on the NGQP. + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Build some test data +# +do_test contrib01-1.0 { + db eval { + CREATE TABLE T1 (B INTEGER NOT NULL, + C INTEGER NOT NULL, + D INTEGER NOT NULL, + E INTEGER NOT NULL, + F INTEGER NOT NULL, + G INTEGER NOT NULL, + H INTEGER NOT NULL, + PRIMARY KEY (B, C, D)); + + CREATE TABLE T2 (A INTEGER NOT NULL, + B INTEGER NOT NULL, + C INTEGER NOT NULL, + PRIMARY KEY (A, B, C)); + + INSERT INTO T2(A, B, C) VALUES(702118,16183,15527); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15560); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15561); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15563); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15564); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15566); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15567); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15569); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15612); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15613); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15638); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15681); + INSERT INTO T2(A, B, C) VALUES(702118,16183,15682); + + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15527,6,0,5,5,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15560,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15561,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15563,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15564,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15566,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15567,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15569,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15612,6,0,5,5,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15613,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15638,6,0,5,2,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15681,6,0,5,5,0); + INSERT INTO T1(B, C, D, E, F, G, H) VALUES(16183,15682,6,0,5,2,0); + } +} {} +do_test contrib01-1.1 { + db eval { + SELECT T2.A, T2.B, T1.D, T1.E, T1.F, T1.G, T1.H, MAX(T1.C), '^' + FROM T1, T2 + WHERE T1.B = T2.B + AND T1.C = T2.C + GROUP BY T2.A, T2.B, T1.D, T1.E, T1.F, T1.G, T1.H + ORDER BY +max(t1.c); + } +} {702118 16183 6 0 5 5 0 15681 ^ 702118 16183 6 0 5 2 0 15682 ^} +do_test contrib01-1.2 { + db eval { + SELECT T2.A, T2.B, T1.D, T1.E, T1.F, T1.G, T1.H, MAX(T1.C), '^' + FROM T1, T2 + WHERE T1.B = T2.B + AND T1.C = T2.C + GROUP BY T2.A, T2.B, T1.F, T1.D, T1.E, T1.G, T1.H + ORDER BY +max(t1.c); + } +} {702118 16183 6 0 5 5 0 15681 ^ 702118 16183 6 0 5 2 0 15682 ^} + +finish_test From cd0f407c3f9ab27cfac6be88e53ce0036d2208b2 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Jun 2013 12:47:59 +0000 Subject: [PATCH 083/144] Performance tweak to whereLoopInsert(). FossilOrigin-Name: 1c4a78807b7a28c9976ca8c5722ff4e2e8755b7e --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 32 +++++++++++++++++--------------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index ed506f992c..ae6211e19d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\stest\scase\scontributed\son\sthe\smailing\slist\nthat\sworks\sin\sNGQP\sbut\sfails\sin\slegacy. -D 2013-06-05T12:18:15.188 +C Performance\stweak\sto\swhereLoopInsert(). +D 2013-06-05T12:47:59.358 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 0b8fd61de3c71df0ba084d13177c384bb50e4d22 +F src/where.c 3b175d731c15e30bd8893b0309f9e7e8d0f11121 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P cf96eb5945a9bab71104cb1581ee13ab30022566 -R 373c05c6780cec478b9924edf49e0658 +P 96afe50866a08ed14e911c3c955030f7ab83a3ed +R 70441548922262718992448fc2500d0d U drh -Z c785a25f44da51b36475ec1e8ccfb14e +Z 415f390706a3e5c8723b2ce592b50c3b diff --git a/manifest.uuid b/manifest.uuid index bafc3efa21..ce1f9dfb25 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -96afe50866a08ed14e911c3c955030f7ab83a3ed \ No newline at end of file +1c4a78807b7a28c9976ca8c5722ff4e2e8755b7e \ No newline at end of file diff --git a/src/where.c b/src/where.c index d9dccf7541..3af73198e8 100644 --- a/src/where.c +++ b/src/where.c @@ -3859,25 +3859,27 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ */ for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ) continue; - if( p->nTermnTerm - && (p->wsFlags & WHERE_INDEXED)!=0 - && (pTemplate->wsFlags & WHERE_INDEXED)!=0 - && p->u.btree.pIndex==pTemplate->u.btree.pIndex - && p->prereq==pTemplate->prereq - ){ - /* Overwrite an existing WhereLoop with an similar one that uses - ** more terms of the index */ - pNext = p->pNextLoop; - whereLoopClear(db, p); - break; - } if( (p->prereq & pTemplate->prereq)==p->prereq && p->rSetup<=pTemplate->rSetup && p->rRun<=pTemplate->rRun ){ - /* Already holding an equal or better WhereLoop. - ** Return without changing or adding anything */ - goto whereLoopInsert_noop; + /* p is equal or better than pTemplate */ + if( p->nTermnTerm + && (p->wsFlags & WHERE_INDEXED)!=0 + && (pTemplate->wsFlags & WHERE_INDEXED)!=0 + && p->u.btree.pIndex==pTemplate->u.btree.pIndex + && p->prereq==pTemplate->prereq + ){ + /* Overwrite an existing WhereLoop with an similar one that uses + ** more terms of the index */ + pNext = p->pNextLoop; + whereLoopClear(db, p); + break; + }else{ + /* pTemplate is not helpful. + ** Return without changing or adding anything */ + goto whereLoopInsert_noop; + } } if( (p->prereq & pTemplate->prereq)==pTemplate->prereq && p->rSetup>=pTemplate->rSetup From f2c9229f73e7ceb6899f246e19c10dfd644b58a5 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 5 Jun 2013 16:17:21 +0000 Subject: [PATCH 084/144] Up until now the fts4 "unicode61" tokenizer has treated all private use codepoints except the first and last of each of the three ranges as alphanumeric (eligible to be part of tokens). This commit fixes this so that all private use codepoints are considered alphanumeric. In other words, it fixes the handling of codepoints 0xE000, 0xF8FF, 0xF0000, 0xFFFFD, 0x100000 and 0x10FFFD. FossilOrigin-Name: 6cfd9af5250029c0d275be027b4208c48954a8a1 --- ext/fts3/fts3_unicode2.c | 43 +++++++++++++++++----------------- ext/fts3/unicode/mkunicode.tcl | 11 +++++---- manifest | 18 +++++++------- manifest.uuid | 2 +- test/fts4unicode.test | 18 ++++++++++++++ 5 files changed, 56 insertions(+), 36 deletions(-) diff --git a/ext/fts3/fts3_unicode2.c b/ext/fts3/fts3_unicode2.c index 3c24569026..fba688ff9c 100644 --- a/ext/fts3/fts3_unicode2.c +++ b/ext/fts3/fts3_unicode2.c @@ -101,28 +101,27 @@ int sqlite3FtsUnicodeIsalnum(int c){ 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, - 0x037FFC02, 0x03E3FC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, - 0x03F4F802, 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, - 0x03F95013, 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, - 0x03FCEC06, 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, - 0x04040003, 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, - 0x040E7C01, 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, - 0x04280403, 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, - 0x04294009, 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, - 0x04420003, 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, - 0x04460003, 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, - 0x05BD442E, 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, - 0x07480046, 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, - 0x075C5401, 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, - 0x075EA401, 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, - 0x07C2800F, 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, - 0x07C4C03C, 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, - 0x07C94002, 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, - 0x07CE8025, 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, - 0x07D108B6, 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, - 0x07D7EC46, 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, - 0x38008060, 0x380400F0, 0x3C000001, 0x3FFFF401, 0x40000001, - 0x43FFF401, + 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, + 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, + 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, + 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, + 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, + 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, + 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, + 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, + 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, + 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, + 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, + 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, + 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, + 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, + 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, + 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, + 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, + 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, + 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, + 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, + 0x380400F0, }; static const unsigned int aAscii[4] = { 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, diff --git a/ext/fts3/unicode/mkunicode.tcl b/ext/fts3/unicode/mkunicode.tcl index 0d58e8aa5c..2da17c51a5 100644 --- a/ext/fts3/unicode/mkunicode.tcl +++ b/ext/fts3/unicode/mkunicode.tcl @@ -239,7 +239,10 @@ proc an_load_unicodedata_text {zName} { foreach $lField $fields {} set iCode [expr "0x$code"] - set bAlnum [expr {[lsearch {L N} [string range $general_category 0 0]]>=0}] + set bAlnum [expr { + [lsearch {L N} [string range $general_category 0 0]] >= 0 + || $general_category=="Co" + }] if { !$bAlnum } { lappend lRet $iCode } } @@ -360,7 +363,7 @@ proc print_isalnum {zFunc lRange} { } assert( aEntry[0]=aEntry[iRes] ); - return (c >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); + return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); } return 1;} puts "\}" @@ -729,7 +732,7 @@ proc print_fileheader {} { */ }] puts "" - puts "#if !defined(SQLITE_DISABLE_FTS3_UNICODE)" + puts "#if defined(SQLITE_ENABLE_FTS4_UNICODE61)" puts "#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)" puts "" puts "#include " @@ -805,4 +808,4 @@ if {$::generate_test_code} { } puts "#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */" -puts "#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */" +puts "#endif /* !defined(SQLITE_ENABLE_FTS4_UNICODE61) */" diff --git a/manifest b/manifest index 4c2a451fd1..600d211c42 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sa\scollating\sfunction\sinside\sthe\se_reindex.test\sscript. -D 2013-06-03T20:39:15.752 +C Up\suntil\snow\sthe\sfts4\s"unicode61"\stokenizer\shas\streated\sall\sprivate\suse\scodepoints\sexcept\sthe\sfirst\sand\slast\sof\seach\sof\sthe\sthree\sranges\sas\salphanumeric\s(eligible\sto\sbe\spart\sof\stokens).\sThis\scommit\sfixes\sthis\sso\sthat\sall\sprivate\suse\scodepoints\sare\sconsidered\salphanumeric.\sIn\sother\swords,\sit\sfixes\sthe\shandling\sof\scodepoints\s0xE000,\s0xF8FF,\s0xF0000,\s0xFFFFD,\s0x100000\sand\s0x10FFFD. +D 2013-06-05T16:17:21.916 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -95,14 +95,14 @@ F ext/fts3/fts3_tokenizer.c bbdc731bc91338050675c6d1da9ab82147391e16 F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9 -F ext/fts3/fts3_unicode2.c a863f05f758af36777dffc2facc898bc73fec896 +F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d F ext/fts3/fts3_write.c 6a1fc0e922e76b68e594bf7bc33bac72af9dc47b F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197 F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7 -F ext/fts3/unicode/mkunicode.tcl 7a9bc018e2962abb79563c5a39fe581fcbf2f675 +F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 F ext/icu/icu.c 7538f98eab2854cf17fa5f7797bffa6c76e3863b F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 @@ -550,7 +550,7 @@ F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584 -F test/fts4unicode.test 25ccad45896f8e50f6a694cff738a35f798cdb40 +F test/fts4unicode.test c8ac44217bf6c17812b03eaafa6c06995ad304c2 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/func.test b0fc34fdc36897769651975a2b0a606312753643 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 3bd5ad095b23102dd3379cb62997cbf23cc67b7a -R 0bab77d0f95310ae1c21cfea10915144 -U drh -Z 1023ee14390bd42e471d5323a67fa234 +P 4d74fccf02134a998a84097b021ba9d501e34ff0 +R 659aea33cb10f326783eda2b62f9d699 +U dan +Z 74ecc7396dceda2a9a9f04f8bd9d8ced diff --git a/manifest.uuid b/manifest.uuid index e3db3db774..0ba0d6eb30 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4d74fccf02134a998a84097b021ba9d501e34ff0 \ No newline at end of file +6cfd9af5250029c0d275be027b4208c48954a8a1 \ No newline at end of file diff --git a/test/fts4unicode.test b/test/fts4unicode.test index 8bd83f6d9e..aee7f05b1b 100644 --- a/test/fts4unicode.test +++ b/test/fts4unicode.test @@ -384,5 +384,23 @@ foreach T $tokenizers { do_isspace_test 6.$T.19 $T {8287 12288} } +#------------------------------------------------------------------------- +# Test that the private use ranges are treated as alphanumeric. +# +breakpoint +foreach {tn1 c} { + 1 \ue000 2 \ue001 3 \uf000 4 \uf8fe 5 \uf8ff +} { + foreach {tn2 config res} { + 1 "" "0 hello*world hello*world" + 2 "separators=*" "0 hello hello 1 world world" + } { + set config [string map [list * $c] $config] + set input [string map [list * $c] "hello*world"] + set output [string map [list * $c] $res] + do_unicode_token_test3 7.$tn1.$tn2 {*}$config $input $output + } +} + finish_test From e9d935a8aa0dcef214933cd14c2c454674f36431 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Jun 2013 16:19:59 +0000 Subject: [PATCH 085/144] Minor performance tuning of the NGQP. FossilOrigin-Name: cbef38c2d123e7d5a02c2a2450e8b329e3e96ee9 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 12 +++++++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index ae6211e19d..454d643033 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Performance\stweak\sto\swhereLoopInsert(). -D 2013-06-05T12:47:59.358 +C Minor\sperformance\stuning\sof\sthe\sNGQP. +D 2013-06-05T16:19:59.536 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 3b175d731c15e30bd8893b0309f9e7e8d0f11121 +F src/where.c 7d8a020b2d60ff2b536e6325af18ed11c24f81e5 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 96afe50866a08ed14e911c3c955030f7ab83a3ed -R 70441548922262718992448fc2500d0d +P 1c4a78807b7a28c9976ca8c5722ff4e2e8755b7e +R 4c15e208b04c5a33c6528133849a04db U drh -Z 415f390706a3e5c8723b2ce592b50c3b +Z c639596f7b6bcfbd4cf032fe7e7c5fd1 diff --git a/manifest.uuid b/manifest.uuid index ce1f9dfb25..2673f09571 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1c4a78807b7a28c9976ca8c5722ff4e2e8755b7e \ No newline at end of file +cbef38c2d123e7d5a02c2a2450e8b329e3e96ee9 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 3af73198e8..4229ddc7ec 100644 --- a/src/where.c +++ b/src/where.c @@ -752,7 +752,8 @@ WhereTerm *whereScanInit( ){ int j; - memset(pScan, 0, sizeof(*pScan)); + /* memset(pScan, 0, sizeof(*pScan)); */ + pScan->pCurrent = 0; pScan->pOrigWC = pWC; pScan->pWC = pWC; if( pIdx && iColumn>=0 ){ @@ -761,8 +762,12 @@ WhereTerm *whereScanInit( if( NEVER(j>=pIdx->nColumn) ) return 0; } pScan->zCollName = pIdx->azColl[j]; + }else{ + pScan->idxaff = 0; + pScan->zCollName = 0; } pScan->opMask = opMask; + pScan->k = 0; pScan->aEquiv[0] = iCur; pScan->aEquiv[1] = iColumn; pScan->nEquiv = 2; @@ -4782,7 +4787,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ ** error occurs. */ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ - const int mxChoice = 10; /* Maximum number of simultaneous paths tracked */ + int mxChoice = 10; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ @@ -4801,6 +4806,7 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ db = pWInfo->pParse->db; nLoop = pWInfo->nLevel; + mxChoice = (nLoop==1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace>=2 ) sqlite3DebugPrintf("---- begin solver\n"); @@ -4814,7 +4820,7 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ aFrom = aTo+mxChoice; memset(aFrom, 0, sizeof(aFrom[0])); pX = (WhereLoop**)(aFrom+mxChoice); - for(ii=0, pFrom=aTo; ii0; ii--, pFrom++, pX += nLoop){ pFrom->aLoop = pX; } From 783dece5d67533c564215c295f66e8dcb3feb006 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Jun 2013 17:53:43 +0000 Subject: [PATCH 086/144] Performance improvement for the OR-clause analysis in the NGQP. FossilOrigin-Name: 9b1c4954e468d0acfb5787e6bff56d50a3e7bc1a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 28 ++++++++++++++-------------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index 454d643033..68794b6938 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sperformance\stuning\sof\sthe\sNGQP. -D 2013-06-05T16:19:59.536 +C Performance\simprovement\sfor\sthe\sOR-clause\sanalysis\sin\sthe\sNGQP. +D 2013-06-05T17:53:43.355 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 7d8a020b2d60ff2b536e6325af18ed11c24f81e5 +F src/where.c 35e510bf0de4925316934e0ae989db9d062069d5 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 1c4a78807b7a28c9976ca8c5722ff4e2e8755b7e -R 4c15e208b04c5a33c6528133849a04db +P cbef38c2d123e7d5a02c2a2450e8b329e3e96ee9 +R 0e9737367b7d6db3cdf59c7691a34aed U drh -Z c639596f7b6bcfbd4cf032fe7e7c5fd1 +Z 4606f36521508d3eb4fac531dd74f101 diff --git a/manifest.uuid b/manifest.uuid index 2673f09571..0a8e044566 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cbef38c2d123e7d5a02c2a2450e8b329e3e96ee9 \ No newline at end of file +9b1c4954e468d0acfb5787e6bff56d50a3e7bc1a \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4229ddc7ec..342c9ac721 100644 --- a/src/where.c +++ b/src/where.c @@ -4430,17 +4430,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ if( pWC->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; - pItem = pBuilder->pTabList->a + pNew->iTab; - iCur = pItem->iCursor; - sSubBuild = *pBuilder; - sSubBuild.pOrderBy = 0; - sSubBuild.pBest = &sBest; - tempWC.pParse = pWC->pParse; - tempWC.pMaskSet = pWC->pMaskSet; - tempWC.pOuter = pWC; - tempWC.op = TK_AND; - tempWC.wctrlFlags = 0; - tempWC.nTerm = 1; for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 @@ -4452,12 +4441,23 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ double rTotal = 0; double nRow = 0; Bitmask prereq = mExtra; - + + pItem = pBuilder->pTabList->a + pNew->iTab; + iCur = pItem->iCursor; + sSubBuild = *pBuilder; + sSubBuild.pOrderBy = 0; + sSubBuild.pBest = &sBest; for(pOrTerm=pOrWC->a; pOrTermeOperator& WO_AND)!=0 ){ + if( (pOrTerm->eOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; }else if( pOrTerm->leftCursor==iCur ){ + tempWC.pParse = pWC->pParse; + tempWC.pMaskSet = pWC->pMaskSet; + tempWC.pOuter = pWC; + tempWC.op = TK_AND; + tempWC.wctrlFlags = 0; + tempWC.nTerm = 1; tempWC.a = pOrTerm; sSubBuild.pWC = &tempWC; }else{ @@ -4787,7 +4787,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ ** error occurs. */ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ - int mxChoice = 10; /* Maximum number of simultaneous paths tracked */ + int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ From 6f32848d619dbcd0ca213b2c815bc39bb6587986 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Jun 2013 23:39:34 +0000 Subject: [PATCH 087/144] Move the definitions of the WhereLevel and WhereInfo objects out of sqliteInt.h and into where.c. This will facilitate future refactoring of the internal query planner data structures. FossilOrigin-Name: 1574653b9b4522b489d4c62d9cf70166bb3bddfd --- manifest | 18 ++++---- manifest.uuid | 2 +- src/select.c | 19 +++++--- src/sqliteInt.h | 74 +++--------------------------- src/update.c | 2 +- src/where.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 146 insertions(+), 86 deletions(-) diff --git a/manifest b/manifest index 68794b6938..3602c781f7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Performance\simprovement\sfor\sthe\sOR-clause\sanalysis\sin\sthe\sNGQP. -D 2013-06-05T17:53:43.355 +C Move\sthe\sdefinitions\sof\sthe\sWhereLevel\sand\sWhereInfo\sobjects\sout\sof\nsqliteInt.h\sand\sinto\swhere.c.\s\sThis\swill\sfacilitate\sfuture\srefactoring\nof\sthe\sinternal\squery\splanner\sdata\sstructures. +D 2013-06-05T23:39:34.316 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -215,12 +215,12 @@ F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c 22ee971346a736ddefdc4497d07c92f2e9978afc +F src/select.c 5e8fe15b1c5b2cc592880d3f039c6a6da55bf253 F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 259d999abebf4498615e9237a18c0815257a1f2f +F src/sqliteInt.h 7b85b09d746cde295c7a0f60711421a28f5c4905 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -272,7 +272,7 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12 F src/trigger.c 5c0ea9b8755e7c5e1a700f3e27ac4f8d92dd221e -F src/update.c 4c0c6864c4349ba292042e984a56d15985b57f4e +F src/update.c 8e76c3d03e4b7b21cb250bd2df0c05e12993e577 F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 F src/vacuum.c ddf21cc9577c4cb459d08bee9863a78ec000c5bb @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 35e510bf0de4925316934e0ae989db9d062069d5 +F src/where.c 83c6fce38c5c22a1573bc3acbc0d1241a140331a F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P cbef38c2d123e7d5a02c2a2450e8b329e3e96ee9 -R 0e9737367b7d6db3cdf59c7691a34aed +P 9b1c4954e468d0acfb5787e6bff56d50a3e7bc1a +R 2a5a6c03912e176e1d2592bfb6917650 U drh -Z 4606f36521508d3eb4fac531dd74f101 +Z 58f6e83bb7528a16d0e3d3a98418299b diff --git a/manifest.uuid b/manifest.uuid index 0a8e044566..abc266545e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9b1c4954e468d0acfb5787e6bff56d50a3e7bc1a \ No newline at end of file +1574653b9b4522b489d4c62d9cf70166bb3bddfd \ No newline at end of file diff --git a/src/select.c b/src/select.c index 9705c19058..d160513bd3 100644 --- a/src/select.c +++ b/src/select.c @@ -4267,9 +4267,13 @@ int sqlite3Select( /* Begin the database scan. */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, pDist, 0,0); if( pWInfo==0 ) goto select_end; - if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut; - if( pWInfo->eDistinct ) sDistinct.eTnctType = pWInfo->eDistinct; - if( pOrderBy && pWInfo->nOBSat==pOrderBy->nExpr ) pOrderBy = 0; + if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ + p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); + } + if( sqlite3WhereIsDistinct(pWInfo) ){ + sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); + } + if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0; /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral @@ -4282,7 +4286,8 @@ int sqlite3Select( /* Use the standard inner loop. */ selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, &sDistinct, pDest, - pWInfo->iContinue, pWInfo->iBreak); + sqlite3WhereContinueLabel(pWInfo), + sqlite3WhereBreakLabel(pWInfo)); /* End the database scan loop. */ @@ -4399,7 +4404,7 @@ int sqlite3Select( sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, 0, 0); if( pWInfo==0 ) goto select_end; - if( pWInfo->nOBSat==pGroupBy->nExpr ){ + if( sqlite3WhereIsOrdered(pWInfo) ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo @@ -4680,8 +4685,8 @@ int sqlite3Select( } updateAccumulator(pParse, &sAggInfo); assert( pMinMax==0 || pMinMax->nExpr==1 ); - if( pWInfo->nOBSat>0 ){ - sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak); + if( sqlite3WhereIsOrdered(pWInfo) ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo)); VdbeComment((v, "%s() by index", (flag==WHERE_ORDERBY_MIN?"min":"max"))); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2b07d2ef02..76835385fb 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -721,7 +721,6 @@ typedef struct VTable VTable; typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WhereInfo WhereInfo; -typedef struct WhereLevel WhereLevel; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and @@ -1954,44 +1953,6 @@ struct SrcList { #define JT_ERROR 0x0040 /* unknown or unsupported join type */ -/* -** For each nested loop in a WHERE clause implementation, the WhereInfo -** structure contains a single instance of this structure. This structure -** is intended to be private to the where.c module and should not be -** access or modified by other modules. -** -** The pIdxInfo field is used to help pick the best index on a -** virtual table. The pIdxInfo pointer contains indexing -** information for the i-th table in the FROM clause before reordering. -** All the pIdxInfo pointers are freed by whereInfoFree() in where.c. -** All other information in the i-th WhereLevel object for the i-th table -** after FROM clause ordering. -*/ -struct WhereLevel { - int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ - int iTabCur; /* The VDBE cursor used to access the table */ - int iIdxCur; /* The VDBE cursor used to access pIdx */ - int addrBrk; /* Jump here to break out of the loop */ - int addrNxt; /* Jump here to start the next IN combination */ - int addrCont; /* Jump here to continue with the next loop cycle */ - int addrFirst; /* First instruction of interior of the loop */ - u8 iFrom; /* FIXME: Which entry in the FROM clause */ - u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */ - int p1, p2; /* Operands of the opcode used to ends the loop */ - union { /* Information that depends on plan.wsFlags */ - struct { - int nIn; /* Number of entries in aInLoop[] */ - struct InLoop { - int iCur; /* The VDBE cursor used by this IN operator */ - int addrInTop; /* Top of the IN loop */ - u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ - } *aInLoop; /* Information about each nested IN operator */ - } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ - Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ - } u; - struct WhereLoop *pWLoop; /* The selected WhereLoop object */ -}; - /* ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin() ** and the WhereInfo.wctrlFlags member. @@ -2007,35 +1968,6 @@ struct WhereLevel { #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ -/* -** The WHERE clause processing routine has two halves. The -** first part does the start of the WHERE loop and the second -** half does the tail of the WHERE loop. An instance of -** this structure is returned by the first half and passed -** into the second half to give some continuity. -*/ -struct WhereInfo { - Parse *pParse; /* Parsing and code generating context */ - SrcList *pTabList; /* List of tables in the join */ - ExprList *pOrderBy; /* The ORDER BY clause or NULL */ - ExprList *pDistinct; /* DISTINCT ON values, or NULL */ - Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ - u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ - u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ - u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ - u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ - u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ - int iTop; /* The very beginning of the WHERE loop */ - int iContinue; /* Jump here to continue with next record */ - int iBreak; /* Jump here to break out of the loop */ - int nLevel; /* Number of nested loop */ - struct WhereClause *pWC; /* Decomposition of the WHERE clause */ - struct WhereLoop *pLoops; /* List of all WhereLoop objects */ - double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ - double nRowOut; /* Estimated number of output rows */ - WhereLevel a[1]; /* Information about each nest loop in WHERE */ -}; - /* Allowed values for WhereInfo.eDistinct and DistinctCtx.eTnctType */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ @@ -2864,6 +2796,12 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); +double sqlite3WhereOutputRowCount(WhereInfo*); +int sqlite3WhereIsDistinct(WhereInfo*); +int sqlite3WhereIsOrdered(WhereInfo*); +int sqlite3WhereContinueLabel(WhereInfo*); +int sqlite3WhereBreakLabel(WhereInfo*); +int sqlite3WhereOkOnePass(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); diff --git a/src/update.c b/src/update.c index 3ab1ab2a4b..5b18ebd6bf 100644 --- a/src/update.c +++ b/src/update.c @@ -318,7 +318,7 @@ void sqlite3Update( pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, 0 ); if( pWInfo==0 ) goto update_cleanup; - okOnePass = pWInfo->okOnePass; + okOnePass = sqlite3WhereOkOnePass(pWInfo); /* Remember the rowid of every item to be updated. */ diff --git a/src/where.c b/src/where.c index 342c9ac721..4d03776bf2 100644 --- a/src/where.c +++ b/src/where.c @@ -39,6 +39,7 @@ typedef struct WhereClause WhereClause; typedef struct WhereMaskSet WhereMaskSet; typedef struct WhereOrInfo WhereOrInfo; typedef struct WhereAndInfo WhereAndInfo; +typedef struct WhereLevel WhereLevel; typedef struct WhereLoop WhereLoop; typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; @@ -47,6 +48,73 @@ typedef struct WhereScan WhereScan; typedef struct WhereVtabPlan WhereVtabPlan; +/* +** For each nested loop in a WHERE clause implementation, the WhereInfo +** structure contains a single instance of this structure. This structure +** is intended to be private to the where.c module and should not be +** access or modified by other modules. +** +** The pIdxInfo field is used to help pick the best index on a +** virtual table. The pIdxInfo pointer contains indexing +** information for the i-th table in the FROM clause before reordering. +** All the pIdxInfo pointers are freed by whereInfoFree() in where.c. +** All other information in the i-th WhereLevel object for the i-th table +** after FROM clause ordering. +*/ +struct WhereLevel { + int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ + int iTabCur; /* The VDBE cursor used to access the table */ + int iIdxCur; /* The VDBE cursor used to access pIdx */ + int addrBrk; /* Jump here to break out of the loop */ + int addrNxt; /* Jump here to start the next IN combination */ + int addrCont; /* Jump here to continue with the next loop cycle */ + int addrFirst; /* First instruction of interior of the loop */ + u8 iFrom; /* FIXME: Which entry in the FROM clause */ + u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */ + int p1, p2; /* Operands of the opcode used to ends the loop */ + union { /* Information that depends on plan.wsFlags */ + struct { + int nIn; /* Number of entries in aInLoop[] */ + struct InLoop { + int iCur; /* The VDBE cursor used by this IN operator */ + int addrInTop; /* Top of the IN loop */ + u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ + } *aInLoop; /* Information about each nested IN operator */ + } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ + Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ + } u; + struct WhereLoop *pWLoop; /* The selected WhereLoop object */ +}; + +/* +** The WHERE clause processing routine has two halves. The +** first part does the start of the WHERE loop and the second +** half does the tail of the WHERE loop. An instance of +** this structure is returned by the first half and passed +** into the second half to give some continuity. +*/ +struct WhereInfo { + Parse *pParse; /* Parsing and code generating context */ + SrcList *pTabList; /* List of tables in the join */ + ExprList *pOrderBy; /* The ORDER BY clause or NULL */ + ExprList *pDistinct; /* DISTINCT ON values, or NULL */ + Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ + u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ + u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ + u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ + u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ + u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ + int iTop; /* The very beginning of the WHERE loop */ + int iContinue; /* Jump here to continue with next record */ + int iBreak; /* Jump here to break out of the loop */ + int nLevel; /* Number of nested loop */ + struct WhereClause *pWC; /* Decomposition of the WHERE clause */ + struct WhereLoop *pLoops; /* List of all WhereLoop objects */ + double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ + double nRowOut; /* Estimated number of output rows */ + WhereLevel a[1]; /* Information about each nest loop in WHERE */ +}; + /* ** Each instance of this object represents a way of evaluating one ** term of a join. The WhereClause object holds a table of these @@ -333,6 +401,54 @@ struct WhereLoopBuilder { #define WHERE_TEMP_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_COVER_SCAN 0x00008000 /* Full scan of a covering index */ +/* +** Return the estimated number of output rows from a WHERE clause +*/ +double sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ + return pWInfo->nRowOut; +} + +/* +** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this +** WHERE clause returns outputs for DISTINCT processing. +*/ +int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ + return pWInfo->eDistinct; +} + +/* +** Return TRUE if the WHERE clause returns rows in ORDER BY order. +** Return FALSE if the output needs to be sorted. +*/ +int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ + return pWInfo->nOBSat>0; +} + +/* +** Return the VDBE address or label to jump to in order to continue +** immediately with the next row of a WHERE clause. +*/ +int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ + return pWInfo->iContinue; +} + +/* +** Return the VDBE address or label to jump to in order to break +** out of a WHERE loop. +*/ +int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ + return pWInfo->iBreak; +} + +/* +** Return TRUE if an UPDATE or DELETE statement can operate directly on +** the rowids returned by a WHERE clause. Return FALSE if doing an +** UPDATE or DELETE might change subsequent WHERE clause results. +*/ +int sqlite3WhereOkOnePass(WhereInfo *pWInfo){ + return pWInfo->okOnePass; +} + /* ** Initialize a preallocated WhereClause structure. */ @@ -4179,6 +4295,7 @@ static int whereLoopAddBtree( /* Automatic indexes */ if( !pBuilder->pBest + && pBuilder->pTabList->nSrc>1 && (pBuilder->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->viaCoroutine && !pSrc->notIndexed From 70d18344831f0ed6a0fe82041a263eb269d4ad97 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Jun 2013 19:16:33 +0000 Subject: [PATCH 088/144] Clean up and reorganize the elements of the various objects in the analysis tree for the NGQP. FossilOrigin-Name: bfc76ae1e94fc5b7fd2c9484a36a8dfe6655d165 --- manifest | 12 +-- manifest.uuid | 2 +- src/where.c | 222 ++++++++++++++++++++++++-------------------------- 3 files changed, 113 insertions(+), 123 deletions(-) diff --git a/manifest b/manifest index 3602c781f7..9f0a3553bc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Move\sthe\sdefinitions\sof\sthe\sWhereLevel\sand\sWhereInfo\sobjects\sout\sof\nsqliteInt.h\sand\sinto\swhere.c.\s\sThis\swill\sfacilitate\sfuture\srefactoring\nof\sthe\sinternal\squery\splanner\sdata\sstructures. -D 2013-06-05T23:39:34.316 +C Clean\sup\sand\sreorganize\sthe\selements\sof\sthe\svarious\sobjects\sin\sthe\nanalysis\stree\sfor\sthe\sNGQP. +D 2013-06-06T19:16:33.565 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 83c6fce38c5c22a1573bc3acbc0d1241a140331a +F src/where.c e3b7d7ef7aebae993b5ee37b7fc104f1dcea4bc0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 9b1c4954e468d0acfb5787e6bff56d50a3e7bc1a -R 2a5a6c03912e176e1d2592bfb6917650 +P 1574653b9b4522b489d4c62d9cf70166bb3bddfd +R 5e3fae80c355d69a47b06cb86e66bb8c U drh -Z 58f6e83bb7528a16d0e3d3a98418299b +Z 38b156b13260a994e987fde6c73313cc diff --git a/manifest.uuid b/manifest.uuid index abc266545e..5ddbbffbb4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1574653b9b4522b489d4c62d9cf70166bb3bddfd \ No newline at end of file +bfc76ae1e94fc5b7fd2c9484a36a8dfe6655d165 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4d03776bf2..d86e3c6464 100644 --- a/src/where.c +++ b/src/where.c @@ -45,8 +45,6 @@ typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; -typedef struct WhereVtabPlan WhereVtabPlan; - /* ** For each nested loop in a WHERE clause implementation, the WhereInfo @@ -86,35 +84,6 @@ struct WhereLevel { struct WhereLoop *pWLoop; /* The selected WhereLoop object */ }; -/* -** The WHERE clause processing routine has two halves. The -** first part does the start of the WHERE loop and the second -** half does the tail of the WHERE loop. An instance of -** this structure is returned by the first half and passed -** into the second half to give some continuity. -*/ -struct WhereInfo { - Parse *pParse; /* Parsing and code generating context */ - SrcList *pTabList; /* List of tables in the join */ - ExprList *pOrderBy; /* The ORDER BY clause or NULL */ - ExprList *pDistinct; /* DISTINCT ON values, or NULL */ - Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ - u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ - u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ - u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ - u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ - u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ - int iTop; /* The very beginning of the WHERE loop */ - int iContinue; /* Jump here to continue with next record */ - int iBreak; /* Jump here to break out of the loop */ - int nLevel; /* Number of nested loop */ - struct WhereClause *pWC; /* Decomposition of the WHERE clause */ - struct WhereLoop *pLoops; /* List of all WhereLoop objects */ - double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ - double nRowOut; /* Estimated number of output rows */ - WhereLevel a[1]; /* Information about each nest loop in WHERE */ -}; - /* ** Each instance of this object represents a way of evaluating one ** term of a join. The WhereClause object holds a table of these @@ -279,11 +248,9 @@ struct WhereScan { ** subclauses points to the WhereClause object for the whole clause. */ struct WhereClause { - Parse *pParse; /* The parser context */ - WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */ + WhereInfo *pWInfo; /* WHERE clause processing context */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ - u16 wctrlFlags; /* Might include WHERE_AND_ONLY */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ @@ -347,16 +314,46 @@ struct WhereMaskSet { */ struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ - sqlite3 *db; /* Database connection */ - Parse *pParse; /* Parsing context */ +// sqlite3 *db; /* Database connection */ +// Parse *pParse; /* Parsing context */ +// SrcList *pTabList; /* FROM clause */ WhereClause *pWC; /* WHERE clause terms */ - SrcList *pTabList; /* FROM clause */ ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ WhereLoop *pBest; /* If non-NULL, store single best loop here */ int mxTerm; /* Maximum number of aTerm[] entries on pNew */ }; +/* +** The WHERE clause processing routine has two halves. The +** first part does the start of the WHERE loop and the second +** half does the tail of the WHERE loop. An instance of +** this structure is returned by the first half and passed +** into the second half to give some continuity. +*/ +struct WhereInfo { + Parse *pParse; /* Parsing and code generating context */ + SrcList *pTabList; /* List of tables in the join */ + ExprList *pOrderBy; /* The ORDER BY clause or NULL */ + ExprList *pDistinct; /* DISTINCT ON values, or NULL */ + Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ + u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ + u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ + u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ + u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ + u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ + int iTop; /* The very beginning of the WHERE loop */ + int iContinue; /* Jump here to continue with next record */ + int iBreak; /* Jump here to break out of the loop */ + int nLevel; /* Number of nested loop */ + WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ + WhereClause sWC; /* Decomposition of the WHERE clause */ + WhereLoop *pLoops; /* List of all WhereLoop objects */ + double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ + double nRowOut; /* Estimated number of output rows */ + WhereLevel a[1]; /* Information about each nest loop in WHERE */ +}; + /* ** Bitmasks for the operators that indices are able to exploit. An ** OR-ed combination of these values can be used when searching for @@ -454,17 +451,13 @@ int sqlite3WhereOkOnePass(WhereInfo *pWInfo){ */ static void whereClauseInit( WhereClause *pWC, /* The WhereClause to be initialized */ - Parse *pParse, /* The parsing context */ - WhereMaskSet *pMaskSet, /* Mapping from table cursor numbers to bitmasks */ - u16 wctrlFlags /* Might include WHERE_AND_ONLY */ + WhereInfo *pWInfo /* The WHERE processing context */ ){ - pWC->pParse = pParse; - pWC->pMaskSet = pMaskSet; + pWC->pWInfo = pWInfo; pWC->pOuter = 0; pWC->nTerm = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; - pWC->wctrlFlags = wctrlFlags; } /* Forward reference */ @@ -493,7 +486,7 @@ static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){ static void whereClauseClear(WhereClause *pWC){ int i; WhereTerm *a; - sqlite3 *db = pWC->pParse->db; + sqlite3 *db = pWC->pWInfo->pParse->db; for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){ if( a->wtFlags & TERM_DYNAMIC ){ sqlite3ExprDelete(db, a->pExpr); @@ -534,7 +527,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ testcase( wtFlags & TERM_VIRTUAL ); /* EV: R-00211-15100 */ if( pWC->nTerm>=pWC->nSlot ){ WhereTerm *pOld = pWC->a; - sqlite3 *db = pWC->pParse->db; + sqlite3 *db = pWC->pWInfo->pParse->db; pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 ); if( pWC->a==0 ){ if( wtFlags & TERM_DYNAMIC ){ @@ -811,14 +804,15 @@ WhereTerm *whereScanNext(WhereScan *pScan){ /* Verify the affinity and collating sequence match */ if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){ CollSeq *pColl; + Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ continue; } assert(pX->pLeft); - pColl = sqlite3BinaryCompareCollSeq(pWC->pParse, + pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); - if( pColl==0 ) pColl = pWC->pParse->db->pDfltColl; + if( pColl==0 ) pColl = pParse->db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } @@ -1177,11 +1171,11 @@ static void exprAnalyzeOrTerm( WhereClause *pWC, /* the complete WHERE clause */ int idxTerm /* Index of the OR-term to be analyzed */ ){ - Parse *pParse = pWC->pParse; /* Parser context */ + WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ + Parse *pParse = pWInfo->pParse; /* Parser context */ sqlite3 *db = pParse->db; /* Database connection */ WhereTerm *pTerm = &pWC->a[idxTerm]; /* The term to be analyzed */ Expr *pExpr = pTerm->pExpr; /* The expression of the term */ - WhereMaskSet *pMaskSet = pWC->pMaskSet; /* Table use masks */ int i; /* Loop counters */ WhereClause *pOrWc; /* Breakup of pTerm into subterms */ WhereTerm *pOrTerm; /* A Sub-term within the pOrWc */ @@ -1200,7 +1194,7 @@ static void exprAnalyzeOrTerm( if( pOrInfo==0 ) return; pTerm->wtFlags |= TERM_ORINFO; pOrWc = &pOrInfo->wc; - whereClauseInit(pOrWc, pWC->pParse, pMaskSet, pWC->wctrlFlags); + whereClauseInit(pOrWc, pWInfo); whereSplit(pOrWc, pExpr, TK_OR); exprAnalyzeAll(pSrc, pOrWc); if( db->mallocFailed ) return; @@ -1226,7 +1220,7 @@ static void exprAnalyzeOrTerm( pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; pAndWC = &pAndInfo->wc; - whereClauseInit(pAndWC, pWC->pParse, pMaskSet, pWC->wctrlFlags); + whereClauseInit(pAndWC, pWC->pWInfo); whereSplit(pAndWC, pOrTerm->pExpr, TK_AND); exprAnalyzeAll(pSrc, pAndWC); pAndWC->pOuter = pWC; @@ -1235,7 +1229,7 @@ static void exprAnalyzeOrTerm( for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); if( allowedOp(pAndTerm->pExpr->op) ){ - b |= getMask(pMaskSet, pAndTerm->leftCursor); + b |= getMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } } } @@ -1246,10 +1240,10 @@ static void exprAnalyzeOrTerm( ** corresponding TERM_VIRTUAL term */ }else{ Bitmask b; - b = getMask(pMaskSet, pOrTerm->leftCursor); + b = getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor); if( pOrTerm->wtFlags & TERM_VIRTUAL ){ WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; - b |= getMask(pMaskSet, pOther->leftCursor); + b |= getMask(&pWInfo->sMaskSet, pOther->leftCursor); } indexable &= b; if( (pOrTerm->eOperator & WO_EQ)==0 ){ @@ -1311,7 +1305,7 @@ static void exprAnalyzeOrTerm( assert( j==1 ); continue; } - if( (chngToIN & getMask(pMaskSet, pOrTerm->leftCursor))==0 ){ + if( (chngToIN & getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){ /* This term must be of the form t1.a==t2.b where t2 is in the ** chngToIN set but t1 is not. This term will be either preceeded ** or follwed by an inverted copy (t2.b==t1.a). Skip this term @@ -1330,7 +1324,7 @@ static void exprAnalyzeOrTerm( ** on the second iteration */ assert( j==1 ); assert( IsPowerOfTwo(chngToIN) ); - assert( chngToIN==getMask(pMaskSet, iCursor) ); + assert( chngToIN==getMask(&pWInfo->sMaskSet, iCursor) ); break; } testcase( j==1 ); @@ -1379,7 +1373,7 @@ static void exprAnalyzeOrTerm( assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); - pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup); + pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; } assert( pLeft!=0 ); @@ -1428,6 +1422,7 @@ static void exprAnalyze( WhereClause *pWC, /* the WHERE clause */ int idxTerm /* Index of the term to be analyzed */ ){ + WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ WhereTerm *pTerm; /* The term to be analyzed */ WhereMaskSet *pMaskSet; /* Set of table index masks */ Expr *pExpr; /* The expression to be analyzed */ @@ -1438,14 +1433,14 @@ static void exprAnalyze( int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ int noCase = 0; /* LIKE/GLOB distinguishes case */ int op; /* Top-level operator. pExpr->op */ - Parse *pParse = pWC->pParse; /* Parsing context */ + Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection */ if( db->mallocFailed ){ return; } pTerm = &pWC->a[idxTerm]; - pMaskSet = pWC->pMaskSet; + pMaskSet = &pWInfo->sMaskSet; pExpr = pTerm->pExpr; assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); @@ -3068,7 +3063,6 @@ static void explainOneScan( static Bitmask codeOneLoopStart( WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ - u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ Bitmask notReady /* Which tables are currently available */ ){ int j, k; /* Loop counters */ @@ -3091,14 +3085,14 @@ static Bitmask codeOneLoopStart( pParse = pWInfo->pParse; v = pParse->pVdbe; - pWC = pWInfo->pWC; + pWC = &pWInfo->sWC; pLevel = &pWInfo->a[iLevel]; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; bRev = (pWInfo->revMask>>iLevel)&1; omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 - && (wctrlFlags & WHERE_FORCE_TABLE)==0; + && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0; VdbeNoopComment((v, "Begin Join Loop %d", iLevel)); /* Create labels for the "break" and "continue" instructions @@ -3355,7 +3349,7 @@ static Bitmask codeOneLoopStart( ** the first one after the nEq equality constraints in the index, ** this requires some special handling. */ - if( (wctrlFlags&WHERE_ORDERBY_MIN)!=0 + if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 && (pWInfo->nOBSat>0) && (pIdx->nColumn>nEq) ){ @@ -3624,7 +3618,7 @@ static Bitmask codeOneLoopStart( ** fall through to the next instruction, just as an OP_Next does if ** called on an uninitialized cursor. */ - if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ + if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ regRowset = ++pParse->nMem; regRowid = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); @@ -3679,7 +3673,7 @@ static Bitmask codeOneLoopStart( explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); - if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ + if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); int r; r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur, @@ -3751,7 +3745,7 @@ static Bitmask codeOneLoopStart( pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } - newNotReady = notReady & ~getMask(pWC->pMaskSet, iCur); + newNotReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur); /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. @@ -3906,7 +3900,7 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ */ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ if( ALWAYS(pWInfo) ){ - whereClauseClear(pWInfo->pWC); + whereClauseClear(&pWInfo->sWC); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; pWInfo->pLoops = p->pNextLoop; @@ -3945,8 +3939,8 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p, *pNext = 0, *pToFree = 0; WhereTerm **paTerm = 0; - sqlite3 *db = pBuilder->db; WhereInfo *pWInfo = pBuilder->pWInfo; + sqlite3 *db = pWInfo->pParse->db; /* If pBuilder->pBest is defined, then only keep track of the single ** best WhereLoop. pBuilder->pBest->maskSelf==0 indicates that no @@ -3969,7 +3963,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ #if WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf("ins-best: "); - whereLoopPrint(pTemplate, pBuilder->pTabList); + whereLoopPrint(pTemplate, pWInfo->pTabList); } #endif return SQLITE_OK; @@ -4021,10 +4015,10 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ if( sqlite3WhereTrace & 0x8 ){ if( p!=0 ){ sqlite3DebugPrintf("ins-del: "); - whereLoopPrint(p, pBuilder->pTabList); + whereLoopPrint(p, pWInfo->pTabList); } sqlite3DebugPrintf("ins-new: "); - whereLoopPrint(pTemplate, pBuilder->pTabList); + whereLoopPrint(pTemplate, pWInfo->pTabList); } #endif if( p==0 ){ @@ -4060,7 +4054,7 @@ whereLoopInsert_noop: #if WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf("ins-noop: "); - whereLoopPrint(pTemplate, pBuilder->pTabList); + whereLoopPrint(pTemplate, pWInfo->pTabList); } #endif return SQLITE_OK; @@ -4079,7 +4073,9 @@ static int whereLoopAddBtreeIndex( Index *pProbe, /* An index on pSrc */ int nInMul /* Number of iterations due to IN */ ){ - sqlite3 *db; /* Database connection malloc context */ + WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */ + Parse *pParse = pWInfo->pParse; /* Parsing context */ + sqlite3 *db = pParse->db; /* Database connection malloc context */ WhereLoop *pNew; /* Template WhereLoop under construction */ WhereTerm *pTerm; /* A WhereTerm under consideration */ int opMask; /* Valid operators for constraints */ @@ -4091,7 +4087,6 @@ static int whereLoopAddBtreeIndex( double rLogSize; /* Logarithm of table size */ WhereTerm *pTop, *pBtm; /* Top and bottom range constraints */ - db = pBuilder->db; pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM; @@ -4173,18 +4168,18 @@ static int whereLoopAddBtreeIndex( if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ /* Adjust nOut and rRun for STAT3 range values */ double rDiv; - whereRangeScanEst(pBuilder->pParse, pProbe, pNew->u.btree.nEq, + whereRangeScanEst(pParse, pProbe, pNew->u.btree.nEq, pBtm, pTop, &rDiv); pNew->nOut = savedLoop.nOut/rDiv; } #ifdef SQLITE_ENABLE_STAT3 if( pNew->u.btree.nEq==1 && pProbe->nSample ){ if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ - rc = whereEqualScanEst(pBuilder->pParse, pProbe, pTerm->pExpr->pRight, + rc = whereEqualScanEst(pParse, pProbe, pTerm->pExpr->pRight, &pNew->nOut); }else if( (pTerm->eOperator & WO_IN) && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ - rc = whereInScanEst(pBuilder->pParse, pProbe, pTerm->pExpr->x.pList, + rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &pNew->nOut); } @@ -4227,7 +4222,7 @@ static int indexMightHelpWithOrderBy( int iCol; int ii; - if( (pOB = pBuilder->pOrderBy)==0 ) return 0; + if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; iCol = pIndex->aiColumn[0]; for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); @@ -4249,10 +4244,12 @@ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ Bitmask mExtra /* 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 */ tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ + SrcList *pTabList; /* The FROM clause */ struct SrcList_item *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ @@ -4262,7 +4259,9 @@ static int whereLoopAddBtree( double rLogSize; /* Logarithm of the number of rows in the table */ pNew = pBuilder->pNew; - pSrc = pBuilder->pTabList->a + pNew->iTab; + pWInfo = pBuilder->pWInfo; + pTabList = pWInfo->pTabList; + pSrc = pTabList->a + pNew->iTab; assert( !IsVirtual(pSrc->pTab) ); if( pSrc->pIndex ){ @@ -4295,8 +4294,8 @@ static int whereLoopAddBtree( /* Automatic indexes */ if( !pBuilder->pBest - && pBuilder->pTabList->nSrc>1 - && (pBuilder->pParse->db->flags & SQLITE_AutoIndex)!=0 + && pTabList->nSrc>1 + && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->viaCoroutine && !pSrc->notIndexed && !pSrc->isCorrelated @@ -4356,9 +4355,9 @@ static int whereLoopAddBtree( /* Full scan via index */ if( (m==0 || b) && pProbe->bUnordered==0 - && (pBuilder->pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 + && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis - && OptimizationEnabled(pBuilder->pParse->db, SQLITE_CoverIdxScan) + && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ){ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; @@ -4384,6 +4383,7 @@ static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ Bitmask mExtra /* Extra prerequesites for using this table */ ){ + WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ WhereClause *pWC; /* The WHERE clause */ struct SrcList_item *pSrc; /* The FROM clause term to search */ @@ -4401,11 +4401,12 @@ static int whereLoopAddVirtual( WhereLoop *pNew; int rc = SQLITE_OK; - pParse = pBuilder->pParse; + pWInfo = pBuilder->pWInfo; + pParse = pWInfo->pParse; db = pParse->db; pWC = pBuilder->pWC; pNew = pBuilder->pNew; - pSrc = &pBuilder->pTabList->a[pNew->iTab]; + pSrc = &pWInfo->pTabList->a[pNew->iTab]; pTab = pSrc->pTab; assert( IsVirtual(pTab) ); pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pBuilder->pOrderBy); @@ -4532,6 +4533,7 @@ whereLoopAddVtab_exit: ** btrees or virtual tables. */ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ + WhereInfo *pWInfo = pBuilder->pWInfo; WhereClause *pWC; WhereLoop *pNew; WhereTerm *pTerm, *pWCEnd; @@ -4542,9 +4544,8 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ WhereLoop sBest; struct SrcList_item *pItem; - pWC = pBuilder->pWC; - if( pWC->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; + if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; @@ -4559,7 +4560,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ double nRow = 0; Bitmask prereq = mExtra; - pItem = pBuilder->pTabList->a + pNew->iTab; + pItem = pWInfo->pTabList->a + pNew->iTab; iCur = pItem->iCursor; sSubBuild = *pBuilder; sSubBuild.pOrderBy = 0; @@ -4569,11 +4570,9 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ if( (pOrTerm->eOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; }else if( pOrTerm->leftCursor==iCur ){ - tempWC.pParse = pWC->pParse; - tempWC.pMaskSet = pWC->pMaskSet; + tempWC.pWInfo = pWC->pWInfo; tempWC.pOuter = pWC; tempWC.op = TK_AND; - tempWC.wctrlFlags = 0; tempWC.nTerm = 1; tempWC.a = pOrTerm; sSubBuild.pWC = &tempWC; @@ -4610,14 +4609,15 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ ** Add all WhereLoop objects for all tables */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ + WhereInfo *pWInfo = pBuilder->pWInfo; Bitmask mExtra = 0; Bitmask mPrior = 0; int iTab; - SrcList *pTabList = pBuilder->pTabList; + SrcList *pTabList = pWInfo->pTabList; struct SrcList_item *pItem; WhereClause *pWC = pBuilder->pWC; - sqlite3 *db = pBuilder->db; - int nTabList = pBuilder->pWInfo->nLevel; + sqlite3 *db = pWInfo->pParse->db; + int nTabList = pWInfo->nLevel; int rc = SQLITE_OK; WhereLoop *pNew; @@ -4637,7 +4637,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ } for(iTab=0, pItem=pTabList->a; iTabiTab = iTab; - pNew->maskSelf = getMask(pWC->pMaskSet, pItem->iCursor); + pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor); if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ mExtra = mPrior; } @@ -4698,7 +4698,6 @@ static int wherePathSatisfiesOrderBy( Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ Bitmask obDone; /* Mask of all ORDER BY terms */ Bitmask orderDistinctMask; /* Mask of all well-ordered loops */ - WhereMaskSet *pMaskSet; /* WhereMaskSet object for this where clause */ /* @@ -4739,7 +4738,6 @@ static int wherePathSatisfiesOrderBy( isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; - pMaskSet = pWInfo->pWC->pMaskSet; for(iLoop=0; isOrderDistinct && obSataLoop[iLoop] : pLast; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); @@ -4870,7 +4868,7 @@ static int wherePathSatisfiesOrderBy( Expr *p; if( MASKBIT(i) & obSat ) continue; p = pOrderBy->a[i].pExpr; - if( (exprTableUsage(pMaskSet, p)&~orderDistinctMask)==0 ){ + if( (exprTableUsage(&pWInfo->sMaskSet, p)&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); } } @@ -5239,9 +5237,6 @@ WhereInfo *sqlite3WhereBegin( /* Variable initialization */ memset(&sWLB, 0, sizeof(sWLB)); - sWLB.pParse = pParse; - sWLB.db = pParse->db; - sWLB.pTabList = pTabList; sWLB.pOrderBy = pOrderBy; /* The number of tables in the FROM clause is limited by the number of @@ -5269,11 +5264,7 @@ WhereInfo *sqlite3WhereBegin( */ db = pParse->db; nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); - pWInfo = sqlite3DbMallocZero(db, - nByteWInfo + - sizeof(WhereClause) + - sizeof(WhereMaskSet) - ); + pWInfo = sqlite3DbMallocZero(db, nByteWInfo); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); pWInfo = 0; @@ -5285,12 +5276,11 @@ WhereInfo *sqlite3WhereBegin( pWInfo->pOrderBy = pOrderBy; pWInfo->pDistinct = pDistinct; pWInfo->iBreak = sqlite3VdbeMakeLabel(v); - pWInfo->pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo]; pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; - pMaskSet = (WhereMaskSet*)&pWInfo->pWC[1]; + pMaskSet = &pWInfo->sMaskSet; sWLB.pWInfo = pWInfo; - sWLB.pWC = pWInfo->pWC; + sWLB.pWC = &pWInfo->sWC; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ @@ -5300,9 +5290,9 @@ WhereInfo *sqlite3WhereBegin( ** subexpression is separated by an AND operator. */ initMaskSet(pMaskSet); - whereClauseInit(pWInfo->pWC, pParse, pMaskSet, wctrlFlags); + whereClauseInit(&pWInfo->sWC, pWInfo); sqlite3ExprCodeConstants(pParse, pWhere); - whereSplit(pWInfo->pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ + whereSplit(&pWInfo->sWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. @@ -5347,7 +5337,7 @@ WhereInfo *sqlite3WhereBegin( ** want to analyze these virtual terms, so start analyzing at the end ** and work forward so that the added virtual terms are never processed. */ - exprAnalyzeAll(pTabList, pWInfo->pWC); + exprAnalyzeAll(pTabList, &pWInfo->sWC); if( db->mallocFailed ){ goto whereBeginError; } @@ -5356,7 +5346,7 @@ WhereInfo *sqlite3WhereBegin( ** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to ** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT. */ - if( pDistinct && isDistinctRedundant(pParse,pTabList,pWInfo->pWC,pDistinct) ){ + if( pDistinct && isDistinctRedundant(pParse,pTabList,&pWInfo->sWC,pDistinct) ){ pDistinct = 0; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } @@ -5467,7 +5457,7 @@ WhereInfo *sqlite3WhereBegin( } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLoop->wsFlags & WHERE_TEMP_INDEX)!=0 ){ - constructAutomaticIndex(pParse, pWInfo->pWC, pTabItem, notReady, pLevel); + constructAutomaticIndex(pParse, &pWInfo->sWC, pTabItem, notReady, pLevel); }else #endif if( pLoop->wsFlags & WHERE_INDEXED ){ @@ -5482,7 +5472,7 @@ WhereInfo *sqlite3WhereBegin( VdbeComment((v, "%s", pIx->zName)); } sqlite3CodeVerifySchema(pParse, iDb); - notReady &= ~getMask(pWInfo->pWC->pMaskSet, pTabItem->iCursor); + notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor); } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; @@ -5495,7 +5485,7 @@ WhereInfo *sqlite3WhereBegin( for(ii=0; iia[ii]; explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags); - notReady = codeOneLoopStart(pWInfo, ii, wctrlFlags, notReady); + notReady = codeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; } From e3be82cf188d5e3582c4d1c605870ba119d31b83 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Jun 2013 19:25:42 +0000 Subject: [PATCH 089/144] Remove some commented-out code that was mistakenly left in the previous check-in. FossilOrigin-Name: b4a5dbad36bceabc5c5350e7676af6ad42de04eb --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 --- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 9f0a3553bc..7068f05a1e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Clean\sup\sand\sreorganize\sthe\selements\sof\sthe\svarious\sobjects\sin\sthe\nanalysis\stree\sfor\sthe\sNGQP. -D 2013-06-06T19:16:33.565 +C Remove\ssome\scommented-out\scode\sthat\swas\smistakenly\sleft\sin\sthe\sprevious\ncheck-in. +D 2013-06-06T19:25:42.472 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e3b7d7ef7aebae993b5ee37b7fc104f1dcea4bc0 +F src/where.c 0b652e425f7a958a66591b082731c4e8379d8954 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 1574653b9b4522b489d4c62d9cf70166bb3bddfd -R 5e3fae80c355d69a47b06cb86e66bb8c +P bfc76ae1e94fc5b7fd2c9484a36a8dfe6655d165 +R 6ac62cf90895a44c1fcede6b2ff8eacf U drh -Z 38b156b13260a994e987fde6c73313cc +Z b5c1236cedf9282cba7e1987b8db3ea9 diff --git a/manifest.uuid b/manifest.uuid index 5ddbbffbb4..0f8825c921 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bfc76ae1e94fc5b7fd2c9484a36a8dfe6655d165 \ No newline at end of file +b4a5dbad36bceabc5c5350e7676af6ad42de04eb \ No newline at end of file diff --git a/src/where.c b/src/where.c index d86e3c6464..21277f1d25 100644 --- a/src/where.c +++ b/src/where.c @@ -314,9 +314,6 @@ struct WhereMaskSet { */ struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ -// sqlite3 *db; /* Database connection */ -// Parse *pParse; /* Parsing context */ -// SrcList *pTabList; /* FROM clause */ WhereClause *pWC; /* WHERE clause terms */ ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ From 4efc9298fb4fde4f5001b8d0e3155bbde5cffcea Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Jun 2013 23:02:03 +0000 Subject: [PATCH 090/144] Improved management of the space to hold WhereLoop.aLTerm[]. FossilOrigin-Name: d4141ecbea3abbe83525910684fbd89eb74eeb34 --- manifest | 12 +- manifest.uuid | 2 +- src/where.c | 338 +++++++++++++++++++++++++++++--------------------- 3 files changed, 207 insertions(+), 145 deletions(-) diff --git a/manifest b/manifest index 7068f05a1e..b68a0110a6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\ssome\scommented-out\scode\sthat\swas\smistakenly\sleft\sin\sthe\sprevious\ncheck-in. -D 2013-06-06T19:25:42.472 +C Improved\smanagement\sof\sthe\sspace\sto\shold\sWhereLoop.aLTerm[]. +D 2013-06-06T23:02:03.759 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 0b652e425f7a958a66591b082731c4e8379d8954 +F src/where.c e029cd3fe9f2fcc857cf19d05b352b2359638271 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P bfc76ae1e94fc5b7fd2c9484a36a8dfe6655d165 -R 6ac62cf90895a44c1fcede6b2ff8eacf +P b4a5dbad36bceabc5c5350e7676af6ad42de04eb +R c565385814d78fee98948398a72cac6f U drh -Z b5c1236cedf9282cba7e1987b8db3ea9 +Z 2b77e3c42c0b772f55707fe4d25f7e48 diff --git a/manifest.uuid b/manifest.uuid index 0f8825c921..bc7a4d415f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b4a5dbad36bceabc5c5350e7676af6ad42de04eb \ No newline at end of file +d4141ecbea3abbe83525910684fbd89eb74eeb34 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 21277f1d25..08569fc60b 100644 --- a/src/where.c +++ b/src/where.c @@ -45,6 +45,7 @@ typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; +typedef float WhereCost; /* ** For each nested loop in a WHERE clause implementation, the WhereInfo @@ -98,11 +99,12 @@ struct WhereLoop { #endif u8 iTab; /* Position in FROM clause of table for this loop */ u8 iSortIdx; /* Sorting index number. 0==None */ - u16 nTerm; /* Number of entries in aTerm[] */ + u16 nLTerm; /* Number of entries in aLTerm[] */ + u16 nLSlot; /* Number of slots allocated for aLTerm[] */ u32 wsFlags; /* WHERE_* flags describing the plan */ - double rSetup; /* One-time setup cost (ex: create transient index) */ - double rRun; /* Cost of running each loop */ - double nOut; /* Estimated number of output rows */ + WhereCost rSetup; /* One-time setup cost (ex: create transient index) */ + WhereCost rRun; /* Cost of running each loop */ + WhereCost nOut; /* Estimated number of output rows */ union { struct { /* Information for internal btree tables */ int nEq; /* Number of equality constraints */ @@ -116,10 +118,14 @@ struct WhereLoop { char *idxStr; /* Index identifier string */ } vtab; } u; - WhereTerm **aTerm; /* WhereTerms used */ + WhereTerm **aLTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ + WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */ }; +/* Forward declaration of methods */ +static int whereLoopResize(sqlite3*, WhereLoop*, int); + /* ** Each instance of this object holds a sequence of WhereLoop objects ** that implement some or all of the entire query plan. @@ -127,8 +133,8 @@ struct WhereLoop { struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ - double nRow; /* Estimated number of rows generated by this path */ - double rCost; /* Total cost of this path */ + WhereCost nRow; /* Estimated number of rows generated by this path */ + WhereCost rCost; /* Total cost of this path */ u8 isOrdered; /* True if this path satisfies ORDER BY */ u8 isOrderedValid; /* True if the isOrdered field is valid */ WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ @@ -318,7 +324,6 @@ struct WhereLoopBuilder { ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ WhereLoop *pBest; /* If non-NULL, store single best loop here */ - int mxTerm; /* Maximum number of aTerm[] entries on pNew */ }; /* @@ -346,8 +351,8 @@ struct WhereInfo { WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereLoop *pLoops; /* List of all WhereLoop objects */ - double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ - double nRowOut; /* Estimated number of output rows */ + WhereCost savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ + WhereCost nRowOut; /* Estimated number of output rows */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; @@ -399,7 +404,7 @@ struct WhereInfo { ** Return the estimated number of output rows from a WHERE clause */ double sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ - return pWInfo->nRowOut; + return (double)pWInfo->nRowOut; } /* @@ -1823,9 +1828,9 @@ static int isDistinctRedundant( ** complexity. Because N is just a guess, it is no great tragedy if ** logN is a little off. */ -static double estLog(double N){ - double logN = 1; - double x = 10; +static WhereCost estLog(WhereCost N){ + WhereCost logN = 1; + WhereCost x = 10; while( N>x ){ logN += 1; x *= 10; @@ -1946,23 +1951,21 @@ static void constructAutomaticIndex( pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; - pLoop->aTerm = sqlite3DbRealloc(pParse->db, pLoop->aTerm, - mxConstraint*sizeof(pLoop->aTerm[0])); - if( pLoop->aTerm==0 ) return; - for(pTerm=pWC->a; pTermnTerma; pTermnLTermu.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); if( (idxCols & cMask)==0 ){ - pLoop->aTerm[nColumn++] = pTerm; + if( whereLoopResize(pParse->db, pLoop, nColumn+1) ) return; + pLoop->aLTerm[nColumn++] = pTerm; idxCols |= cMask; } } } assert( nColumn>0 ); - pLoop->u.btree.nEq = pLoop->nTerm = nColumn; + pLoop->u.btree.nEq = pLoop->nLTerm = nColumn; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED | WHERE_TEMP_INDEX; @@ -2118,7 +2121,6 @@ static sqlite3_index_info *allocateIndexInfo( + sizeof(*pIdxOrderBy)*nOrderBy ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return 0; } @@ -2241,7 +2243,7 @@ static int whereKeyStats( int i, eType; int isEq = 0; i64 v; - double r, rS; + WhereCost r, rS; assert( roundUp==0 || roundUp==1 ); assert( pIdx->nSample>0 ); @@ -2459,7 +2461,7 @@ static int whereRangeScanEst( int nEq, /* index into p->aCol[] of the range-compared column */ WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ - double *pRangeDiv /* OUT: Reduce search space by this divisor */ + WhereCost *pRangeDiv /* OUT: Reduce search space by this divisor */ ){ int rc = SQLITE_OK; @@ -2498,9 +2500,9 @@ static int whereRangeScanEst( } if( rc==SQLITE_OK ){ if( iUpper<=iLower ){ - *pRangeDiv = (double)p->aiRowEst[0]; + *pRangeDiv = (WhereCost)p->aiRowEst[0]; }else{ - *pRangeDiv = (double)p->aiRowEst[0]/(double)(iUpper - iLower); + *pRangeDiv = (WhereCost)p->aiRowEst[0]/(WhereCost)(iUpper - iLower); } /*WHERETRACE(("range scan regions: %u..%u div=%g\n", (u32)iLower, (u32)iUpper, *pRangeDiv));*/ @@ -2513,9 +2515,9 @@ static int whereRangeScanEst( UNUSED_PARAMETER(nEq); #endif assert( pLower || pUpper ); - *pRangeDiv = (double)1; - if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= (double)4; - if( pUpper ) *pRangeDiv *= (double)4; + *pRangeDiv = (WhereCost)1; + if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= (WhereCost)4; + if( pUpper ) *pRangeDiv *= (WhereCost)4; return rc; } @@ -2541,7 +2543,7 @@ static int whereEqualScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ - double *pnRow /* Write the revised row estimate here */ + WhereCost *pnRow /* Write the revised row estimate here */ ){ sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */ u8 aff; /* Column affinity */ @@ -2590,11 +2592,11 @@ static int whereInScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ - double *pnRow /* Write the revised row estimate here */ + WhereCost *pnRow /* Write the revised row estimate here */ ){ int rc = SQLITE_OK; /* Subfunction return code */ - double nEst; /* Number of rows for a single term */ - double nRowEst = (double)0; /* New estimate of the number of rows */ + WhereCost nEst; /* Number of rows for a single term */ + WhereCost nRowEst = (WhereCost)0; /* New estimate of the number of rows */ int i; /* Loop counter */ assert( p->aSample!=0 ); @@ -2858,7 +2860,7 @@ static int codeAllEqualityTerms( assert( pIdx->nColumn>=nEq ); for(j=0; jaTerm[j]; + pTerm = pLoop->aLTerm[j]; assert( pTerm!=0 ); /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ @@ -3132,14 +3134,14 @@ static Bitmask codeOneLoopStart( */ int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; - int nConstraint = pLoop->nTerm; + int nConstraint = pLoop->nLTerm; sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; jaTerm[j]; + pTerm = pLoop->aLTerm[j]; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); addrNotFound = pLevel->addrNxt; @@ -3155,7 +3157,7 @@ static Bitmask codeOneLoopStart( pLoop->u.vtab.needFree = 0; for(j=0; ju.vtab.omitMask>>j)&1 ){ - disableTerm(pLevel, pLoop->aTerm[j]); + disableTerm(pLevel, pLoop->aLTerm[j]); } } pLevel->op = OP_VNext; @@ -3176,7 +3178,7 @@ static Bitmask codeOneLoopStart( */ assert( pLoop->u.btree.nEq==1 ); iReleaseReg = sqlite3GetTempReg(pParse); - pTerm = pLoop->aTerm[0]; + pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); @@ -3202,8 +3204,8 @@ static Bitmask codeOneLoopStart( assert( omitTable==0 ); j = 0; pStart = pEnd = 0; - if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aTerm[j++]; - if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aTerm[j++]; + if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; + if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; if( bRev ){ pTerm = pStart; pStart = pEnd; @@ -3361,11 +3363,11 @@ static Bitmask codeOneLoopStart( */ j = nEq; if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ - pRangeStart = pLoop->aTerm[j++]; + pRangeStart = pLoop->aLTerm[j++]; nExtraReg = 1; } if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ - pRangeEnd = pLoop->aTerm[j++]; + pRangeEnd = pLoop->aLTerm[j++]; nExtraReg = 1; } @@ -3574,7 +3576,7 @@ static Bitmask codeOneLoopStart( int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ - pTerm = pLoop->aTerm[0]; + pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->eOperator & WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); @@ -3860,19 +3862,27 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ sqlite3DebugPrintf(" %-15s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" fg %05x N %d", p->wsFlags, p->nTerm); + sqlite3DebugPrintf(" fg %05x N %d", p->wsFlags, p->nLTerm); sqlite3DebugPrintf(" cost %.2g,%.2g,%.2g\n", p->prereq, p->rSetup, p->rRun, p->nOut); } #endif /* -** Deallocate internal memory used by a WhereLoop object +** Convert bulk memory into a valid WhereLoop that can be passed +** to whereLoopClear harmlessly. */ -static void whereLoopClear(sqlite3 *db, WhereLoop *p){ - sqlite3DbFree(db, p->aTerm); - p->aTerm = 0; - p->nTerm = 0; +static void whereLoopInit(WhereLoop *p){ + p->aLTerm = p->aLTermSpace; + p->nLTerm = 0; + p->nLSlot = ArraySize(p->aLTermSpace); + p->wsFlags = 0; +} + +/* +** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. +*/ +static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ if( p->u.vtab.needFree ) sqlite3_free(p->u.vtab.idxStr); p->u.vtab.needFree = 0; @@ -3884,6 +3894,61 @@ static void whereLoopClear(sqlite3 *db, WhereLoop *p){ } } + +/* +** Deallocate internal memory used by a WhereLoop object +*/ +static void whereLoopClear(sqlite3 *db, WhereLoop *p){ + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + whereLoopClearUnion(db, p); + whereLoopInit(p); +} + +/* +** Increase the memory allocation for pLoop->aLTerm[] to be at least n. +*/ +static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ + WhereTerm **paNew; + if( p->nLSlot>=n ) return SQLITE_OK; + n = (n+7)&~7; + paNew = sqlite3DbMallocRaw(db, sizeof(p->aLTerm[0])*n); + if( paNew==0 ) return SQLITE_NOMEM; + memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + p->aLTerm = paNew; + p->nLSlot = n; + return SQLITE_OK; +} + +/* +** Transfer content from the second pLoop into the first. +*/ +static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ + if( whereLoopResize(db, pTo, pFrom->nLTerm) ) return SQLITE_NOMEM; + whereLoopClearUnion(db, pTo); + pTo->prereq = pFrom->prereq; + pTo->maskSelf = pFrom->maskSelf; + pTo->iTab = pFrom->iTab; + pTo->iSortIdx = pFrom->iSortIdx; + pTo->nLTerm = pFrom->nLTerm; + pTo->rSetup = pFrom->rSetup; + pTo->rRun = pFrom->rRun; + pTo->nOut = pFrom->nOut; + if( pTo->nLTerm ){ + memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); + } + pTo->wsFlags = pFrom->wsFlags; + pTo->u = pFrom->u; + if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ + pFrom->u.vtab.needFree = 0; + }else if( (pFrom->wsFlags & WHERE_TEMP_INDEX)!=0 && pFrom->u.btree.pIndex!=0 ){ + sqlite3DbFree(db, pFrom->u.btree.pIndex->zColAff); + sqlite3DbFree(db, pFrom->u.btree.pIndex); + pFrom->u.btree.pIndex = 0; + } + return SQLITE_OK; +} + /* ** Delete a WhereLoop object */ @@ -3934,8 +3999,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** dependencies */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ - WhereLoop **ppPrev, *p, *pNext = 0, *pToFree = 0; - WhereTerm **paTerm = 0; + WhereLoop **ppPrev, *p, *pNext = 0; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; @@ -3946,17 +4010,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ */ if( (p = pBuilder->pBest)!=0 ){ if( p->maskSelf!=0 ){ - if( p->rRun+p->rSetup < pTemplate->rRun+pTemplate->rSetup ){ + WhereCost rCost = p->rRun + p->rSetup; + WhereCost rTemplate = pTemplate->rRun + pTemplate->rSetup; + if( rCost < rTemplate ){ goto whereLoopInsert_noop; } - if( p->rRun+p->rSetup == pTemplate->rRun+pTemplate->rSetup - && p->prereq <= pTemplate->prereq ){ + if( rCost == rTemplate && p->prereq <= pTemplate->prereq ){ goto whereLoopInsert_noop; } } - *p = *pTemplate; - p->aTerm = 0; - p->u.vtab.needFree = 0; + whereLoopXfer(db, p, pTemplate); #if WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf("ins-best: "); @@ -3976,7 +4039,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ && p->rRun<=pTemplate->rRun ){ /* p is equal or better than pTemplate */ - if( p->nTermnTerm + if( p->nLTermnLTerm && (p->wsFlags & WHERE_INDEXED)!=0 && (pTemplate->wsFlags & WHERE_INDEXED)!=0 && p->u.btree.pIndex==pTemplate->u.btree.pIndex @@ -4019,30 +4082,18 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ } #endif if( p==0 ){ - p = pToFree = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); + p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; + whereLoopInit(p); } - if( pTemplate->nTerm ){ - paTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0])); - if( paTerm==0 ){ - sqlite3DbFree(db, pToFree); - return SQLITE_NOMEM; - } - } - *p = *pTemplate; + whereLoopXfer(db, p, pTemplate); p->pNextLoop = pNext; *ppPrev = p; - p->aTerm = paTerm; - if( p->nTerm ){ - memcpy(p->aTerm, pTemplate->aTerm, p->nTerm*sizeof(p->aTerm[0])); - } if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; if( pIndex && pIndex->tnum==0 ){ p->u.btree.pIndex = 0; } - }else{ - pTemplate->u.vtab.needFree = 0; } return SQLITE_OK; @@ -4077,11 +4128,15 @@ static int whereLoopAddBtreeIndex( WhereTerm *pTerm; /* A WhereTerm under consideration */ int opMask; /* Valid operators for constraints */ WhereScan scan; /* Iterator for WHERE terms */ - WhereLoop savedLoop; /* Saved original content of pNew[] */ + Bitmask saved_prereq; /* Original value of pNew->prereq */ + u16 saved_nLTerm; /* Original value of pNew->nLTerm */ + int saved_nEq; /* Original value of pNew->u.btree.nEq */ + u32 saved_wsFlags; /* Original value of pNew->wsFlags */ + WhereCost saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ tRowcnt iRowEst; /* Estimated index selectivity */ - double rLogSize; /* Logarithm of table size */ + WhereCost rLogSize; /* Logarithm of table size */ WhereTerm *pTop, *pBtm; /* Top and bottom range constraints */ pNew = pBuilder->pNew; @@ -4108,18 +4163,22 @@ static int whereLoopAddBtreeIndex( } pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, pProbe); - savedLoop = *pNew; - pNew->rSetup = (double)0; + saved_nEq = pNew->u.btree.nEq; + saved_nLTerm = pNew->nLTerm; + saved_wsFlags = pNew->wsFlags; + saved_prereq = pNew->prereq; + saved_nOut = pNew->nOut; + pNew->rSetup = (WhereCost)0; rLogSize = estLog(pProbe->aiRowEst[0]); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ int nIn = 1; if( pTerm->prereqRight & pNew->maskSelf ) continue; - pNew->wsFlags = savedLoop.wsFlags; - pNew->u.btree.nEq = savedLoop.u.btree.nEq; - pNew->nTerm = savedLoop.nTerm; - if( pNew->nTerm>=pBuilder->mxTerm ) break; /* Repeated column in index */ - pNew->aTerm[pNew->nTerm++] = pTerm; - pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~pNew->maskSelf; + pNew->wsFlags = saved_wsFlags; + pNew->u.btree.nEq = saved_nEq; + pNew->nLTerm = saved_nLTerm; + if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ + pNew->aLTerm[pNew->nLTerm++] = pTerm; + pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; pNew->rRun = rLogSize; if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; @@ -4133,7 +4192,7 @@ static int whereLoopAddBtreeIndex( } pNew->rRun *= nIn; pNew->u.btree.nEq++; - pNew->nOut = (double)iRowEst * nInMul * nIn; + pNew->nOut = (WhereCost)iRowEst * nInMul * nIn; }else if( pTerm->eOperator & (WO_EQ) ){ assert( (pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 || nInMul==1 ); @@ -4146,12 +4205,12 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_ONEROW; } pNew->u.btree.nEq++; - pNew->nOut = (double)iRowEst * nInMul; + pNew->nOut = (WhereCost)iRowEst * nInMul; }else if( pTerm->eOperator & (WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_NULL; pNew->u.btree.nEq++; nIn = 2; /* Assume IS NULL matches two rows */ - pNew->nOut = (double)iRowEst * nInMul * nIn; + pNew->nOut = (WhereCost)iRowEst * nInMul * nIn; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; @@ -4160,14 +4219,14 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? - pNew->aTerm[pNew->nTerm-2] : 0; + pNew->aLTerm[pNew->nLTerm-2] : 0; } if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ /* Adjust nOut and rRun for STAT3 range values */ - double rDiv; + WhereCost rDiv; whereRangeScanEst(pParse, pProbe, pNew->u.btree.nEq, pBtm, pTop, &rDiv); - pNew->nOut = savedLoop.nOut/rDiv; + pNew->nOut = saved_nOut/rDiv; } #ifdef SQLITE_ENABLE_STAT3 if( pNew->u.btree.nEq==1 && pProbe->nSample ){ @@ -4198,7 +4257,11 @@ static int whereLoopAddBtreeIndex( whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul*nIn); } } - *pNew = savedLoop; + pNew->prereq = saved_prereq; + pNew->u.btree.nEq = saved_nEq; + pNew->wsFlags = saved_wsFlags; + pNew->nOut = saved_nOut; + pNew->nLTerm = saved_nLTerm; return rc; } @@ -4252,8 +4315,8 @@ static int whereLoopAddBtree( int rc = SQLITE_OK; /* Return code */ int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ - double rSize; /* number of rows in the table */ - double rLogSize; /* Logarithm of the number of rows in the table */ + WhereCost rSize; /* number of rows in the table */ + WhereCost rLogSize; /* Logarithm of the number of rows in the table */ pNew = pBuilder->pNew; pWInfo = pBuilder->pWInfo; @@ -4286,7 +4349,7 @@ static int whereLoopAddBtree( } pProbe = &sPk; } - rSize = (double)pSrc->pTab->nRowEst; + rSize = (WhereCost)pSrc->pTab->nRowEst; rLogSize = estLog(rSize); /* Automatic indexes */ @@ -4306,10 +4369,10 @@ static int whereLoopAddBtree( if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; pNew->u.btree.pIndex = 0; - pNew->nTerm = 1; - pNew->aTerm[0] = pTerm; + pNew->nLTerm = 1; + pNew->aLTerm[0] = pTerm; pNew->rSetup = 20*rLogSize*pSrc->pTab->nRowEst; - pNew->nOut = (double)10; + pNew->nOut = (WhereCost)10; pNew->rRun = rLogSize + pNew->nOut; pNew->wsFlags = WHERE_TEMP_INDEX; pNew->prereq = mExtra | pTerm->prereqRight; @@ -4322,9 +4385,9 @@ static int whereLoopAddBtree( */ for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ pNew->u.btree.nEq = 0; - pNew->nTerm = 0; + pNew->nLTerm = 0; pNew->iSortIdx = 0; - pNew->rSetup = (double)0; + pNew->rSetup = (WhereCost)0; pNew->prereq = mExtra; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); @@ -4392,6 +4455,7 @@ static int whereLoopAddVirtual( WhereTerm *pTerm; int i, j; int iTerm, mxTerm; + int nConstraint; int seenIn = 0; /* True if an IN operator is seen */ int seenVar = 0; /* True if a non-constant constraint is seen */ int iPhase; /* 0: const w/o IN, 1: const, 2: no IN, 2: IN */ @@ -4411,9 +4475,11 @@ static int whereLoopAddVirtual( pNew->prereq = 0; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; - pNew->nTerm = 0; + pNew->nLTerm = 0; pNew->u.vtab.needFree = 0; pUsage = pIdxInfo->aConstraintUsage; + nConstraint = pIdxInfo->nConstraint; + if( whereLoopResize(db, pNew, nConstraint) ) return SQLITE_NOMEM; for(iPhase=0; iPhase<=3; iPhase++){ if( !seenIn && (iPhase&1)!=0 ){ @@ -4456,23 +4522,23 @@ static int whereLoopAddVirtual( pIdxInfo->idxNum = 0; pIdxInfo->needToFreeIdxStr = 0; pIdxInfo->orderByConsumed = 0; - /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ - pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); + /* ((WhereCost)2) In case of SQLITE_OMIT_FLOATING_POINT... */ + pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((WhereCost)2); rc = vtabBestIndex(pParse, pTab, pIdxInfo); if( rc ) goto whereLoopAddVtab_exit; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pNew->prereq = 0; mxTerm = -1; - for(i=0; imxTerm; i++) pNew->aTerm[i] = 0; + assert( pNew->nLSlot>=nConstraint ); + for(i=0; iaLTerm[i] = 0; pNew->u.vtab.omitMask = 0; - for(i=0; inConstraint; i++, pIdxCons++){ + for(i=0; i=0 ){ - if( iTerm>=pBuilder->mxTerm ) break; j = pIdxCons->iTermOffset; - if( iTerm>=pIdxInfo->nConstraint + if( iTerm>=nConstraint || j<0 || j>=pWC->nTerm - || pNew->aTerm[iTerm]!=0 + || pNew->aLTerm[iTerm]!=0 ){ rc = SQLITE_ERROR; sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName); @@ -4480,7 +4546,8 @@ static int whereLoopAddVirtual( } pTerm = &pWC->a[j]; pNew->prereq |= pTerm->prereqRight; - pNew->aTerm[iTerm] = pTerm; + assert( iTermnLSlot ); + pNew->aLTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ @@ -4500,17 +4567,18 @@ static int whereLoopAddVirtual( } } } - if( i>=pIdxInfo->nConstraint ){ - pNew->nTerm = mxTerm+1; + if( i>=nConstraint ){ + pNew->nLTerm = mxTerm+1; + assert( pNew->nLTerm<=pNew->nLSlot ); pNew->u.vtab.idxNum = pIdxInfo->idxNum; pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0) && pIdxInfo->orderByConsumed); - pNew->rSetup = (double)0; + pNew->rSetup = (WhereCost)0; pNew->rRun = pIdxInfo->estimatedCost; - pNew->nOut = (double)25; + pNew->nOut = (WhereCost)25; whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); @@ -4545,6 +4613,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; + whereLoopInit(&sBest); for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 @@ -4553,8 +4622,8 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; - double rTotal = 0; - double nRow = 0; + WhereCost rTotal = 0; + WhereCost nRow = 0; Bitmask prereq = mExtra; pItem = pWInfo->pTabList->a + pNew->iTab; @@ -4577,21 +4646,24 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ continue; } sBest.maskSelf = 0; + sBest.rSetup = 0; + sBest.rRun = 0; if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mExtra); }else{ rc = whereLoopAddBtree(&sSubBuild, mExtra); } if( sBest.maskSelf==0 ) break; - assert( sBest.rSetup==(double)0 ); + assert( sBest.rSetup==(WhereCost)0 ); rTotal += sBest.rRun; nRow += sBest.nOut; prereq |= sBest.prereq; } - pNew->nTerm = 1; - pNew->aTerm[0] = pTerm; + assert( pNew->nLSlot>=1 ); + pNew->nLTerm = 1; + pNew->aLTerm[0] = pTerm; pNew->wsFlags = WHERE_MULTI_OR; - pNew->rSetup = (double)0; + pNew->rSetup = (WhereCost)0; pNew->rRun = rTotal; pNew->nOut = nRow; pNew->prereq = prereq; @@ -4599,6 +4671,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ rc = whereLoopInsert(pBuilder, pNew); } } + whereLoopClear(pWInfo->pParse->db, &sBest); return rc; } @@ -4612,7 +4685,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ int iTab; SrcList *pTabList = pWInfo->pTabList; struct SrcList_item *pItem; - WhereClause *pWC = pBuilder->pWC; sqlite3 *db = pWInfo->pParse->db; int nTabList = pWInfo->nLevel; int rc = SQLITE_OK; @@ -4621,17 +4693,8 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ /* Loop over the tables in the join, from left to right */ pBuilder->pNew = pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); if( pNew==0 ) return SQLITE_NOMEM; - pBuilder->mxTerm = pWC->nTerm+1; - while( pWC->pOuter ){ - pWC = pWC->pOuter; - pBuilder->mxTerm += pWC->nTerm; - } - pWC = pBuilder->pWC; - pNew->aTerm = sqlite3DbMallocZero(db,pBuilder->mxTerm*sizeof(pNew->aTerm[0])); - if( pNew->aTerm==0 ){ - rc = SQLITE_NOMEM; - goto whereLoopAddAll_end; - } + pNew->aLTerm = pNew->aLTermSpace; + pNew->nLSlot = ArraySize(pNew->aLTermSpace); for(iTab=0, pItem=pTabList->a; iTabiTab = iTab; pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor); @@ -4649,7 +4712,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; } -whereLoopAddAll_end: whereLoopDelete(db, pBuilder->pNew); pBuilder->pNew = 0; return rc; @@ -4755,7 +4817,7 @@ static int wherePathSatisfiesOrderBy( ** in the ORDER BY clause. */ for(i=0; iu.btree.nEq; i++){ - pTerm = pLoop->aTerm[i]; + pTerm = pLoop->aLTerm[i]; if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))==0 ) continue; iColumn = pTerm->u.leftColumn; for(j=0; ju.btree.nEq - && ((i = pLoop->aTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 + && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 ){ if( i & WO_ISNULL ) isOrderDistinct = 0; continue; @@ -4898,15 +4960,15 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation ** error occurs. */ -static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ +static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ - double rCost; /* Cost of a path */ - double mxCost; /* Maximum cost of a set of paths */ - double rSortCost; /* Cost to do a sort */ + WhereCost rCost; /* Cost of a path */ + WhereCost mxCost; /* Maximum cost of a set of paths */ + WhereCost rSortCost; /* Cost to do a sort */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ @@ -4937,12 +4999,12 @@ static int wherePathSolver(WhereInfo *pWInfo, double nRowEst){ } /* Seed the search with a single WherePath containing zero WhereLoops */ - aFrom[0].nRow = (double)1; + aFrom[0].nRow = (WhereCost)1; nFrom = 1; /* Precompute the cost of sorting the final result set, if the caller ** to sqlite3WhereBegin() was concerned about sorting */ - rSortCost = (double)0; + rSortCost = (WhereCost)0; if( pWInfo->pOrderBy==0 || nRowEst<=0.0 ){ aFrom[0].isOrderedValid = 1; }else{ @@ -5412,7 +5474,7 @@ WhereInfo *sqlite3WhereBegin( */ sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ notReady = ~(Bitmask)0; - pWInfo->nRowOut = (double)1; + pWInfo->nRowOut = (WhereCost)1; for(ii=0, pLevel=pWInfo->a; ii Date: Thu, 6 Jun 2013 23:44:25 +0000 Subject: [PATCH 091/144] Performance improvements. FossilOrigin-Name: 9f8e84ab9874a8af826763b1669adb57abd493ea --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 29 +++++++++++++---------------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/manifest b/manifest index b68a0110a6..b0f5052613 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\smanagement\sof\sthe\sspace\sto\shold\sWhereLoop.aLTerm[]. -D 2013-06-06T23:02:03.759 +C Performance\simprovements. +D 2013-06-06T23:44:25.383 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e029cd3fe9f2fcc857cf19d05b352b2359638271 +F src/where.c fb4bee9bfeb4c1c2019a2ed36cb49d1f72e8dda7 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b4a5dbad36bceabc5c5350e7676af6ad42de04eb -R c565385814d78fee98948398a72cac6f +P d4141ecbea3abbe83525910684fbd89eb74eeb34 +R cd5ddc1e68b8c783ab773654e8fe4f69 U drh -Z 2b77e3c42c0b772f55707fe4d25f7e48 +Z c534f818416a6634a12552ce3fcffbb2 diff --git a/manifest.uuid b/manifest.uuid index bc7a4d415f..b12d1e6402 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d4141ecbea3abbe83525910684fbd89eb74eeb34 \ No newline at end of file +9f8e84ab9874a8af826763b1669adb57abd493ea \ No newline at end of file diff --git a/src/where.c b/src/where.c index 08569fc60b..994df30244 100644 --- a/src/where.c +++ b/src/where.c @@ -3883,18 +3883,19 @@ static void whereLoopInit(WhereLoop *p){ ** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. */ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ - if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ - if( p->u.vtab.needFree ) sqlite3_free(p->u.vtab.idxStr); - p->u.vtab.needFree = 0; - p->u.vtab.idxStr = 0; - }else if( (p->wsFlags & WHERE_TEMP_INDEX)!=0 && p->u.btree.pIndex!=0 ){ - sqlite3DbFree(db, p->u.btree.pIndex->zColAff); - sqlite3DbFree(db, p->u.btree.pIndex); - p->u.btree.pIndex = 0; + if( p->wsFlags & (WHERE_VIRTUALTABLE|WHERE_TEMP_INDEX) ){ + if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 && p->u.vtab.needFree ){ + sqlite3_free(p->u.vtab.idxStr); + p->u.vtab.needFree = 0; + p->u.vtab.idxStr = 0; + }else if( (p->wsFlags & WHERE_TEMP_INDEX)!=0 && p->u.btree.pIndex!=0 ){ + sqlite3DbFree(db, p->u.btree.pIndex->zColAff); + sqlite3DbFree(db, p->u.btree.pIndex); + p->u.btree.pIndex = 0; + } } } - /* ** Deallocate internal memory used by a WhereLoop object */ @@ -3941,9 +3942,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ pTo->u = pFrom->u; if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ pFrom->u.vtab.needFree = 0; - }else if( (pFrom->wsFlags & WHERE_TEMP_INDEX)!=0 && pFrom->u.btree.pIndex!=0 ){ - sqlite3DbFree(db, pFrom->u.btree.pIndex->zColAff); - sqlite3DbFree(db, pFrom->u.btree.pIndex); + }else if( (pFrom->wsFlags & WHERE_TEMP_INDEX)!=0 ){ pFrom->u.btree.pIndex = 0; } return SQLITE_OK; @@ -4048,7 +4047,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ /* Overwrite an existing WhereLoop with an similar one that uses ** more terms of the index */ pNext = p->pNextLoop; - whereLoopClear(db, p); break; }else{ /* pTemplate is not helpful. @@ -4062,7 +4060,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ){ /* Overwrite an existing WhereLoop with a better one */ pNext = p->pNextLoop; - whereLoopClear(db, p); break; } } @@ -4613,7 +4610,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; - whereLoopInit(&sBest); for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 @@ -4626,6 +4622,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ WhereCost nRow = 0; Bitmask prereq = mExtra; + whereLoopInit(&sBest); pItem = pWInfo->pTabList->a + pNew->iTab; iCur = pItem->iCursor; sSubBuild = *pBuilder; @@ -4669,9 +4666,9 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew->prereq = prereq; memset(&pNew->u, 0, sizeof(pNew->u)); rc = whereLoopInsert(pBuilder, pNew); + whereLoopClear(pWInfo->pParse->db, &sBest); } } - whereLoopClear(pWInfo->pParse->db, &sBest); return rc; } From a20141593a5b49e14bbc82c64b5e11cafbdeba57 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Jun 2013 00:29:23 +0000 Subject: [PATCH 092/144] Further prepare-time performance improvements. FossilOrigin-Name: 02741d177bfc2fca23bc99974cd899eba13cb59a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 33 +++++++++++---------------------- 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/manifest b/manifest index b0f5052613..6c3bd8a20c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Performance\simprovements. -D 2013-06-06T23:44:25.383 +C Further\sprepare-time\sperformance\simprovements. +D 2013-06-07T00:29:23.782 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c fb4bee9bfeb4c1c2019a2ed36cb49d1f72e8dda7 +F src/where.c bbd8aad0e54692a107d0f68111a289149814b10c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d4141ecbea3abbe83525910684fbd89eb74eeb34 -R cd5ddc1e68b8c783ab773654e8fe4f69 +P 9f8e84ab9874a8af826763b1669adb57abd493ea +R 8930578735fbc55c72ec3d27796f6bd0 U drh -Z c534f818416a6634a12552ce3fcffbb2 +Z c23263f2bef48916be7bbfa11913b59d diff --git a/manifest.uuid b/manifest.uuid index b12d1e6402..aaaa9ad535 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9f8e84ab9874a8af826763b1669adb57abd493ea \ No newline at end of file +02741d177bfc2fca23bc99974cd899eba13cb59a \ No newline at end of file diff --git a/src/where.c b/src/where.c index 994df30244..3b825214f5 100644 --- a/src/where.c +++ b/src/where.c @@ -99,9 +99,6 @@ struct WhereLoop { #endif u8 iTab; /* Position in FROM clause of table for this loop */ u8 iSortIdx; /* Sorting index number. 0==None */ - u16 nLTerm; /* Number of entries in aLTerm[] */ - u16 nLSlot; /* Number of slots allocated for aLTerm[] */ - u32 wsFlags; /* WHERE_* flags describing the plan */ WhereCost rSetup; /* One-time setup cost (ex: create transient index) */ WhereCost rRun; /* Cost of running each loop */ WhereCost nOut; /* Estimated number of output rows */ @@ -118,6 +115,11 @@ struct WhereLoop { char *idxStr; /* Index identifier string */ } vtab; } u; + u32 wsFlags; /* WHERE_* flags describing the plan */ + u16 nLTerm; /* Number of entries in aLTerm[] */ + /**** whereLoopXfer() copies fields above ***********************/ +# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) + u16 nLSlot; /* Number of slots allocated for aLTerm[] */ WhereTerm **aLTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */ @@ -3927,19 +3929,8 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ if( whereLoopResize(db, pTo, pFrom->nLTerm) ) return SQLITE_NOMEM; whereLoopClearUnion(db, pTo); - pTo->prereq = pFrom->prereq; - pTo->maskSelf = pFrom->maskSelf; - pTo->iTab = pFrom->iTab; - pTo->iSortIdx = pFrom->iSortIdx; - pTo->nLTerm = pFrom->nLTerm; - pTo->rSetup = pFrom->rSetup; - pTo->rRun = pFrom->rRun; - pTo->nOut = pFrom->nOut; - if( pTo->nLTerm ){ - memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); - } - pTo->wsFlags = pFrom->wsFlags; - pTo->u = pFrom->u; + memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); + memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ pFrom->u.vtab.needFree = 0; }else if( (pFrom->wsFlags & WHERE_TEMP_INDEX)!=0 ){ @@ -4685,13 +4676,11 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pWInfo->pParse->db; int nTabList = pWInfo->nLevel; int rc = SQLITE_OK; - WhereLoop *pNew; + WhereLoop *pNew, sNew; /* Loop over the tables in the join, from left to right */ - pBuilder->pNew = pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop)); - if( pNew==0 ) return SQLITE_NOMEM; - pNew->aLTerm = pNew->aLTermSpace; - pNew->nLSlot = ArraySize(pNew->aLTermSpace); + pBuilder->pNew = pNew = &sNew; + whereLoopInit(pNew); for(iTab=0, pItem=pTabList->a; iTabiTab = iTab; pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor); @@ -4709,7 +4698,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; } - whereLoopDelete(db, pBuilder->pNew); + whereLoopClear(db, pNew); pBuilder->pNew = 0; return rc; } From 23fec451a6bdb4d0b598592c66567ef7f6485330 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Jun 2013 02:04:19 +0000 Subject: [PATCH 093/144] Must faster computation of estimated logarithm. FossilOrigin-Name: dfbca3acaeb862f24f25e7810a16ff2066111ff4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 13 ++++++------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 6c3bd8a20c..d0734bd638 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\sprepare-time\sperformance\simprovements. -D 2013-06-07T00:29:23.782 +C Must\sfaster\scomputation\sof\sestimated\slogarithm. +D 2013-06-07T02:04:19.774 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c bbd8aad0e54692a107d0f68111a289149814b10c +F src/where.c 70e1ebd1c3f828f4062fc2b5ada2461419020dae F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 9f8e84ab9874a8af826763b1669adb57abd493ea -R 8930578735fbc55c72ec3d27796f6bd0 +P 02741d177bfc2fca23bc99974cd899eba13cb59a +R 8ee17766ef9ac6851fd1329c34593963 U drh -Z c23263f2bef48916be7bbfa11913b59d +Z adf16c6d5fc0c897d258a12782d83ad0 diff --git a/manifest.uuid b/manifest.uuid index aaaa9ad535..8ae2ff38a7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -02741d177bfc2fca23bc99974cd899eba13cb59a \ No newline at end of file +dfbca3acaeb862f24f25e7810a16ff2066111ff4 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 3b825214f5..c1fc4301d7 100644 --- a/src/where.c +++ b/src/where.c @@ -1831,13 +1831,11 @@ static int isDistinctRedundant( ** logN is a little off. */ static WhereCost estLog(WhereCost N){ - WhereCost logN = 1; - WhereCost x = 10; - while( N>x ){ - logN += 1; - x *= 10; - } - return logN; + u32 a; + assert( sizeof(WhereCost)==4 ); /* 32-bit float input */ + if( N<=0.0 ) return 0.0; + memcpy(&a, &N, 4); + return ((a >>= 23)-127)*0.3; } /* @@ -5398,6 +5396,7 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(("*** Optimizer Start ***\n")); + /* TBD: if( nTablist==1 ) whereCommonCase(&sWLB); */ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; From 753050871aafa9eb61cb368957293adb6ff01259 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Fri, 7 Jun 2013 22:12:20 +0000 Subject: [PATCH 094/144] Improve manual cleaning step performed by the multi-platform build tool for MSVC. FossilOrigin-Name: d5bc1fe1c461bdb3d889ab2e50feb944881822a4 --- manifest | 14 +++++++------- manifest.uuid | 2 +- tool/build-all-msvc.bat | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 600d211c42..3e7f0809e9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Up\suntil\snow\sthe\sfts4\s"unicode61"\stokenizer\shas\streated\sall\sprivate\suse\scodepoints\sexcept\sthe\sfirst\sand\slast\sof\seach\sof\sthe\sthree\sranges\sas\salphanumeric\s(eligible\sto\sbe\spart\sof\stokens).\sThis\scommit\sfixes\sthis\sso\sthat\sall\sprivate\suse\scodepoints\sare\sconsidered\salphanumeric.\sIn\sother\swords,\sit\sfixes\sthe\shandling\sof\scodepoints\s0xE000,\s0xF8FF,\s0xF0000,\s0xFFFFD,\s0x100000\sand\s0x10FFFD. -D 2013-06-05T16:17:21.916 +C Improve\smanual\scleaning\sstep\sperformed\sby\sthe\smulti-platform\sbuild\stool\sfor\sMSVC. +D 2013-06-07T22:12:20.577 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -1048,7 +1048,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd -F tool/build-all-msvc.bat 74fb6e5cca66ebdb6c9bbafb2f8b802f08146d38 x +F tool/build-all-msvc.bat c55f64ca200308fb5fa5c1ee751ea95a13977b5a x F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367 F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 4d74fccf02134a998a84097b021ba9d501e34ff0 -R 659aea33cb10f326783eda2b62f9d699 -U dan -Z 74ecc7396dceda2a9a9f04f8bd9d8ced +P 6cfd9af5250029c0d275be027b4208c48954a8a1 +R dcf91a597f51d84c0ab2afccdf474a00 +U mistachkin +Z e27e17fb6daefee7fbcbf46384d56358 diff --git a/manifest.uuid b/manifest.uuid index 0ba0d6eb30..e69030e607 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6cfd9af5250029c0d275be027b4208c48954a8a1 \ No newline at end of file +d5bc1fe1c461bdb3d889ab2e50feb944881822a4 \ No newline at end of file diff --git a/tool/build-all-msvc.bat b/tool/build-all-msvc.bat index 758036fb75..c433435779 100755 --- a/tool/build-all-msvc.bat +++ b/tool/build-all-msvc.bat @@ -374,7 +374,7 @@ FOR %%P IN (%PLATFORMS%) DO ( REM need to remove the build output for the files we are REM specifically wanting to build for each platform. REM - %__ECHO% DEL /Q sqlite3.dll sqlite3.lib sqlite3.pdb + %__ECHO% DEL /Q *.lo sqlite3.dll sqlite3.lib sqlite3.pdb ) REM From fe685c83d37314b9f1075a34f695b5632d013361 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 8 Jun 2013 19:58:27 +0000 Subject: [PATCH 095/144] Candidate fix for a memory leak that occurs if a CREATE TABLE statement contains two or more COLLATE clauses on the same column definition. FossilOrigin-Name: 60fc77bc537b099bdd48916746109d0332f839af --- manifest | 17 ++++++++++------- manifest.uuid | 2 +- src/build.c | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 3e7f0809e9..a8d7872f9f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improve\smanual\scleaning\sstep\sperformed\sby\sthe\smulti-platform\sbuild\stool\sfor\sMSVC. -D 2013-06-07T22:12:20.577 +C Candidate\sfix\sfor\sa\smemory\sleak\sthat\soccurs\sif\sa\sCREATE\sTABLE\sstatement\ncontains\stwo\sor\smore\sCOLLATE\sclauses\son\sthe\ssame\scolumn\sdefinition. +D 2013-06-08T19:58:27.523 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -165,7 +165,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c 7fba377c29573adfc6091832e27ee1fcbefb51d0 F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 -F src/build.c 92ef9483189389828966153c5950f2e5a49c1182 +F src/build.c 1ecf68522356a90471b07178e186277090d0b027 F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 @@ -1093,7 +1093,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 6cfd9af5250029c0d275be027b4208c48954a8a1 -R dcf91a597f51d84c0ab2afccdf474a00 -U mistachkin -Z e27e17fb6daefee7fbcbf46384d56358 +P d5bc1fe1c461bdb3d889ab2e50feb944881822a4 +R 7e8f7769982f409b915035bea30221de +T *branch * memleak +T *sym-memleak * +T -sym-trunk * +U drh +Z 33f096f01bc764624aabd9216a446650 diff --git a/manifest.uuid b/manifest.uuid index e69030e607..e01f4543fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d5bc1fe1c461bdb3d889ab2e50feb944881822a4 \ No newline at end of file +60fc77bc537b099bdd48916746109d0332f839af \ No newline at end of file diff --git a/src/build.c b/src/build.c index 3c91cdcfdb..067b72f7d0 100644 --- a/src/build.c +++ b/src/build.c @@ -1276,6 +1276,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){ if( sqlite3LocateCollSeq(pParse, zColl) ){ Index *pIdx; + sqlite3DbFree(db, p->aCol[i].zColl); p->aCol[i].zColl = zColl; /* If the column is declared as " PRIMARY KEY COLLATE ", From 60c96cd7890abc4cf8526afc46b62c971e89b8e2 Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 9 Jun 2013 17:21:25 +0000 Subject: [PATCH 096/144] High-speed version of NGQP. Still has some minor problems. FossilOrigin-Name: db2415fa677b84cd0f6dd424283c94e98d246e3b --- manifest | 15 ++++--- manifest.uuid | 2 +- src/where.c | 117 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 105 insertions(+), 29 deletions(-) diff --git a/manifest b/manifest index d0734bd638..39d6b51064 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Must\sfaster\scomputation\sof\sestimated\slogarithm. -D 2013-06-07T02:04:19.774 +C High-speed\sversion\sof\sNGQP.\s\sStill\shas\ssome\sminor\sproblems. +D 2013-06-09T17:21:25.979 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 70e1ebd1c3f828f4062fc2b5ada2461419020dae +F src/where.c 2dae18fe0b79aa90f213c5f2ff385a7ac56d36d5 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 02741d177bfc2fca23bc99974cd899eba13cb59a -R 8ee17766ef9ac6851fd1329c34593963 +P dfbca3acaeb862f24f25e7810a16ff2066111ff4 +R e3ea6bb6c8cd62c47ea6f6e83f99515a +T *branch * nextgen-query-plan-fast +T *sym-nextgen-query-plan-fast * +T -sym-nextgen-query-plan-exp * U drh -Z adf16c6d5fc0c897d258a12782d83ad0 +Z 13597db4c2da76541af04a4f735ffed4 diff --git a/manifest.uuid b/manifest.uuid index 8ae2ff38a7..3a88e72860 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dfbca3acaeb862f24f25e7810a16ff2066111ff4 \ No newline at end of file +db2415fa677b84cd0f6dd424283c94e98d246e3b \ No newline at end of file diff --git a/src/where.c b/src/where.c index c1fc4301d7..135633e1cf 100644 --- a/src/where.c +++ b/src/where.c @@ -5168,6 +5168,75 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ return SQLITE_OK; } +/* +** Most queries use only a single table (they are not joins) and have +** simple == constraints against indexed fields. This routine attempts +** to plan those simple cases using much less ceremony than the +** general-purpose query planner, and thereby yield faster sqlite3_prepare() +** times for the common case. +** +** Return non-zero on success, if this query can be handled by this +** no-frills query planner. Return zero if this query needs the +** general-purpose query planner. +*/ +static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ + WhereInfo *pWInfo; + struct SrcList_item *pItem; + WhereClause *pWC; + WhereTerm *pTerm; + WhereLoop *pLoop; + int iCur; + int i, j; + int nOrderBy; + Table *pTab; + Index *pIdx; + + pWInfo = pBuilder->pWInfo; + assert( pWInfo->pTabList->nSrc>=1 ); + pItem = pWInfo->pTabList->a; + pTab = pItem->pTab; + if( IsVirtual(pTab) ) return 0; + if( pItem->zIndex ) return 0; + iCur = pItem->iCursor; + pWC = &pWInfo->sWC; + pLoop = pBuilder->pNew; + pWInfo->a[0].pWLoop = pLoop; + pLoop->wsFlags = 0; + nOrderBy = pWInfo->pOrderBy ? pWInfo->pOrderBy->nExpr : 0; + pTerm = findTerm(pWC, iCur, -1, 1, WO_EQ, 0); + if( pTerm ){ + pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; + pLoop->aLTerm[0] = pTerm; + pLoop->nLTerm = 1; + pLoop->u.btree.nEq = 1; + pLoop->rRun = (WhereCost)10; + pLoop->nOut = (WhereCost)1; + pWInfo->nRowOut = 1; + pWInfo->nOBSat = nOrderBy; + }else{ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->onError==OE_None ) continue; + for(j=0; jnColumn; j++){ + pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 1, WO_EQ, pIdx); + if( pTerm==0 ) break; + whereLoopResize(pWInfo->pParse->db, pLoop, j); + pLoop->aLTerm[j] = pTerm; + } + if( j!=pIdx->nColumn ) continue; + pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW; + pLoop->nLTerm = j; + pLoop->u.btree.nEq = j; + pLoop->u.btree.pIndex = pIdx; + pLoop->rRun = (WhereCost)15; + pLoop->nOut = (WhereCost)1; + pWInfo->nRowOut = 1; + pWInfo->nOBSat = nOrderBy; + break; + } + } + return pLoop->wsFlags!=0; +} + /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an opaque structure that contains @@ -5307,7 +5376,7 @@ WhereInfo *sqlite3WhereBegin( */ db = pParse->db; nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); - pWInfo = sqlite3DbMallocZero(db, nByteWInfo); + pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); pWInfo = 0; @@ -5324,6 +5393,8 @@ WhereInfo *sqlite3WhereBegin( pMaskSet = &pWInfo->sMaskSet; sWLB.pWInfo = pWInfo; sWLB.pWC = &pWInfo->sWC; + sWLB.pNew = (WhereLoop*)&pWInfo->a[nTabList]; + whereLoopInit(sWLB.pNew); /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ @@ -5396,30 +5467,32 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(("*** Optimizer Start ***\n")); - /* TBD: if( nTablist==1 ) whereCommonCase(&sWLB); */ - rc = whereLoopAddAll(&sWLB); - if( rc ) goto whereBeginError; - - /* Display all of the WhereLoop objects if wheretrace is enabled */ + if( nTabList!=1 || whereSimpleFastCase(&sWLB)==0 ){ + rc = whereLoopAddAll(&sWLB); + if( rc ) goto whereBeginError; + + /* Display all of the WhereLoop objects if wheretrace is enabled */ #ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace ){ - WhereLoop *p; - int i = 0; - static char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" - "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; - for(p=pWInfo->pLoops; p; p=p->pNextLoop){ - p->cId = zLabel[(i++)%sizeof(zLabel)]; - whereLoopPrint(p, pTabList); + if( sqlite3WhereTrace ){ + WhereLoop *p; + int i = 0; + static char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" + "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; + for(p=pWInfo->pLoops; p; p=p->pNextLoop){ + p->cId = zLabel[(i++)%sizeof(zLabel)]; + whereLoopPrint(p, pTabList); + } + } +#endif + + wherePathSolver(pWInfo, -1); + if( db->mallocFailed ) goto whereBeginError; + if( pWInfo->pOrderBy ){ + wherePathSolver(pWInfo, pWInfo->nRowOut); + if( db->mallocFailed ) goto whereBeginError; } } -#endif - - wherePathSolver(pWInfo, -1); - if( db->mallocFailed ) goto whereBeginError; - if( pWInfo->pOrderBy ){ - wherePathSolver(pWInfo, pWInfo->nRowOut); - if( db->mallocFailed ) goto whereBeginError; - }else if( db->flags & SQLITE_ReverseOrder ){ + if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ pWInfo->revMask = (Bitmask)(-1); } if( pParse->nErr || db->mallocFailed ){ From 09081862cf0cba3cf31b747bdbf06670ae1dff78 Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 9 Jun 2013 20:16:26 +0000 Subject: [PATCH 097/144] Add test cases to demonstrate the memory leak on the COLLATE clause. FossilOrigin-Name: 0a60212c9c8404ee079985a58094ed2b2b554d48 --- manifest | 15 ++++++--------- manifest.uuid | 2 +- test/collate1.test | 29 +++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index a8d7872f9f..0e613d65e3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Candidate\sfix\sfor\sa\smemory\sleak\sthat\soccurs\sif\sa\sCREATE\sTABLE\sstatement\ncontains\stwo\sor\smore\sCOLLATE\sclauses\son\sthe\ssame\scolumn\sdefinition. -D 2013-06-08T19:58:27.523 +C Add\stest\scases\sto\sdemonstrate\sthe\smemory\sleak\son\sthe\sCOLLATE\sclause. +D 2013-06-09T20:16:26.380 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -365,7 +365,7 @@ F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287 F test/close.test e37610d60e9c9b9979a981f3f50071d7dff28616 F test/closure01.test dbb28f1ea9eeaf0a53ec5bc0fed352e479def8c7 F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 -F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce +F test/collate1.test b709989e6e6ff6e1d2bd64231c2c1d8146846c9e F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49 F test/collate3.test 79558a286362cb9ed603c6fa543f1cda7f563f0f F test/collate4.test 031f7265c13308b724ba3c49f41cc04612bd92b1 @@ -1093,10 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d5bc1fe1c461bdb3d889ab2e50feb944881822a4 -R 7e8f7769982f409b915035bea30221de -T *branch * memleak -T *sym-memleak * -T -sym-trunk * +P 60fc77bc537b099bdd48916746109d0332f839af +R 866dc59c759cbc65061f28ee32001d2c U drh -Z 33f096f01bc764624aabd9216a446650 +Z a5328cd2740f305b4d17636362fdc07d diff --git a/manifest.uuid b/manifest.uuid index e01f4543fa..002808b770 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -60fc77bc537b099bdd48916746109d0332f839af \ No newline at end of file +0a60212c9c8404ee079985a58094ed2b2b554d48 \ No newline at end of file diff --git a/test/collate1.test b/test/collate1.test index b493ee8f1c..e9ac93aa30 100644 --- a/test/collate1.test +++ b/test/collate1.test @@ -305,4 +305,33 @@ do_test collate1-4.5 { } } {} +# A problem reported on the mailing list: A CREATE TABLE statement +# is allowed to have two or more COLLATE clauses on the same column. +# That probably ought to be an error, but we allow it for backwards +# compatibility. Just make sure it works and doesn't leak memory. +# +do_test collate1-5.1 { + execsql { + CREATE TABLE c5( + id INTEGER PRIMARY KEY, + a TEXT COLLATE binary COLLATE nocase COLLATE rtrim, + b TEXT COLLATE nocase COLLATE binary, + c TEXT COLLATE rtrim COLLATE binary COLLATE rtrim COLLATE nocase + ); + INSERT INTO c5 VALUES(1, 'abc','abc','abc'); + INSERT INTO c5 VALUES(2, 'abc ','ABC','ABC'); + SELECT id FROM c5 WHERE a='abc' ORDER BY id; + } +} {1 2} +do_test collate1-5.2 { + execsql { + SELECT id FROM c5 WHERE b='abc' ORDER BY id; + } +} {1} +do_test collate1-5.3 { + execsql { + SELECT id FROM c5 WHERE c='abc' ORDER BY id; + } +} {1 2} + finish_test From 92a121f46e27cdef9d79a8f192fc62617b8b3218 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Jun 2013 12:15:47 +0000 Subject: [PATCH 098/144] Minor problems in the high-speed NGQP fixed. FossilOrigin-Name: 20eeccf1f24dd762f1bee9c3fe628c70ff01627f --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/where.c | 36 ++++++++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 39d6b51064..7682ff8ad2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C High-speed\sversion\sof\sNGQP.\s\sStill\shas\ssome\sminor\sproblems. -D 2013-06-09T17:21:25.979 +C Minor\sproblems\sin\sthe\shigh-speed\sNGQP\sfixed. +D 2013-06-10T12:15:47.024 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 2dae18fe0b79aa90f213c5f2ff385a7ac56d36d5 +F src/where.c 9fff9a5f3f227857aa0590026837a78696d3bba7 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,10 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P dfbca3acaeb862f24f25e7810a16ff2066111ff4 -R e3ea6bb6c8cd62c47ea6f6e83f99515a -T *branch * nextgen-query-plan-fast -T *sym-nextgen-query-plan-fast * -T -sym-nextgen-query-plan-exp * +P db2415fa677b84cd0f6dd424283c94e98d246e3b +R 1c99bcc201a3fe7c000749ac05c30a32 U drh -Z 13597db4c2da76541af04a4f735ffed4 +Z f1d76f2fd1cf61ecde305cf79590397b diff --git a/manifest.uuid b/manifest.uuid index 3a88e72860..6bd8b33dc7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -db2415fa677b84cd0f6dd424283c94e98d246e3b \ No newline at end of file +20eeccf1f24dd762f1bee9c3fe628c70ff01627f \ No newline at end of file diff --git a/src/where.c b/src/where.c index 135633e1cf..e6b3c3a534 100644 --- a/src/where.c +++ b/src/where.c @@ -4281,6 +4281,21 @@ static int indexMightHelpWithOrderBy( return 0; } +/* +** Return a bitmask where 1s indicate that the corresponding column of +** the table is used by an index. Only the first 63 columns are considered. +*/ +static Bitmask columnsUsedByIndex(Index *pIdx){ + Bitmask m = 0; + int j; + for(j=pIdx->nColumn-1; j>=0; j--){ + int x = pIdx->aiColumn[j]; + if( xpNew->iTab. That table is guaranteed to be @@ -4388,14 +4403,7 @@ static int whereLoopAddBtree( rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; }else{ - Bitmask m = pSrc->colUsed; - int j; - for(j=pProbe->nColumn-1; j>=0; j--){ - int x = pProbe->aiColumn[j]; - if( xcolUsed & ~columnsUsedByIndex(pProbe); pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; /* Full scan via index */ @@ -5186,7 +5194,7 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ WhereTerm *pTerm; WhereLoop *pLoop; int iCur; - int i, j; + int j; int nOrderBy; Table *pTab; Index *pIdx; @@ -5202,6 +5210,11 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ pLoop = pBuilder->pNew; pWInfo->a[0].pWLoop = pLoop; pLoop->wsFlags = 0; + pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); + pWInfo->a[0].iTabCur = iCur; +#ifdef SQLITE_DEBUG + pLoop->cId = '0'; +#endif nOrderBy = pWInfo->pOrderBy ? pWInfo->pOrderBy->nExpr : 0; pTerm = findTerm(pWC, iCur, -1, 1, WO_EQ, 0); if( pTerm ){ @@ -5223,7 +5236,10 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ pLoop->aLTerm[j] = pTerm; } if( j!=pIdx->nColumn ) continue; - pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW; + pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; + if( (pItem->colUsed & ~columnsUsedByIndex(pIdx))==0 ){ + pLoop->wsFlags |= WHERE_IDX_ONLY; + } pLoop->nLTerm = j; pLoop->u.btree.nEq = j; pLoop->u.btree.pIndex = pIdx; From 43b85ef5c6c76ba34acbcb10fdd64bf53582695c Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Jun 2013 12:34:45 +0000 Subject: [PATCH 099/144] Performance improvements for whereScan methods. FossilOrigin-Name: aae14350a37ad50e4607953ab496cba006032873 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 13 +++++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 914fd84078..a55fe673ef 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\shigh-speed\sbypass\sfor\sthe\sNGQP\sfor\sthe\scommon\scase\sof\sa\ssimply\squery\nwith\squality\sconstraints\sthat\soutputs\sa\ssingle\srow. -D 2013-06-10T12:17:03.683 +C Performance\simprovements\sfor\swhereScan\smethods. +D 2013-06-10T12:34:45.199 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 9fff9a5f3f227857aa0590026837a78696d3bba7 +F src/where.c eddcadac3d6d9ec6e969e2d2c9a07c18ee8326c0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P dfbca3acaeb862f24f25e7810a16ff2066111ff4 20eeccf1f24dd762f1bee9c3fe628c70ff01627f -R 1c99bcc201a3fe7c000749ac05c30a32 +P 8d1ba309211e8afa8be5520bbc1eecf6deacae07 +R eb89dcd4fc9448ac2059e0ee34e53951 U drh -Z f19cc889e5aa39da8409c75eaebc0bb3 +Z 8ab3224e95cf812319014fdeea79f2dd diff --git a/manifest.uuid b/manifest.uuid index 493af68286..00d4b0108f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8d1ba309211e8afa8be5520bbc1eecf6deacae07 \ No newline at end of file +aae14350a37ad50e4607953ab496cba006032873 \ No newline at end of file diff --git a/src/where.c b/src/where.c index e6b3c3a534..37d1b151c8 100644 --- a/src/where.c +++ b/src/where.c @@ -231,7 +231,6 @@ struct WhereTerm { ** terms in the WHERE clause that are useful to the query planner. */ struct WhereScan { - WhereTerm *pCurrent; /* Most recent match */ WhereClause *pOrigWC; /* Original, innermost WhereClause */ WhereClause *pWC; /* WhereClause currently being scanned */ char *zCollName; /* Required collating sequence, if not NULL */ @@ -779,12 +778,13 @@ WhereTerm *whereScanNext(WhereScan *pScan){ Expr *pX; /* An expression being tested */ WhereClause *pWC; /* Shorthand for pScan->pWC */ WhereTerm *pTerm; /* The term being tested */ + int k = pScan->k; /* Where to start scanning */ while( pScan->iEquiv<=pScan->nEquiv ){ iCur = pScan->aEquiv[pScan->iEquiv-2]; iColumn = pScan->aEquiv[pScan->iEquiv-1]; while( (pWC = pScan->pWC)!=0 ){ - for(pTerm=pWC->a+pScan->k; pScan->knTerm; pScan->k++, pTerm++){ + for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaEquiv) @@ -828,20 +828,18 @@ WhereTerm *whereScanNext(WhereScan *pScan){ ){ continue; } - pScan->pCurrent = pTerm; - pScan->k++; + pScan->k = k+1; return pTerm; } } } pWC = pScan->pWC = pScan->pWC->pOuter; - pScan->k = 0; + k = 0; } pScan->pWC = pScan->pOrigWC; - pScan->k = 0; + k = 0; pScan->iEquiv += 2; } - pScan->pCurrent = 0; return 0; } @@ -867,7 +865,6 @@ WhereTerm *whereScanInit( int j; /* memset(pScan, 0, sizeof(*pScan)); */ - pScan->pCurrent = 0; pScan->pOrigWC = pWC; pScan->pWC = pWC; if( pIdx && iColumn>=0 ){ From 3b75ffaacab82d95b469ce2099df7b60b3b4a718 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Jun 2013 14:56:25 +0000 Subject: [PATCH 100/144] Simplification and performance tweak to the high-speed NGQP bypass. FossilOrigin-Name: 0f8a38ee54208d6a477aa2482cd277b4808450f0 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 32 +++++++++++++++----------------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index a55fe673ef..d8a42f44d6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Performance\simprovements\sfor\swhereScan\smethods. -D 2013-06-10T12:34:45.199 +C Simplification\sand\sperformance\stweak\sto\sthe\shigh-speed\sNGQP\sbypass. +D 2013-06-10T14:56:25.426 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c eddcadac3d6d9ec6e969e2d2c9a07c18ee8326c0 +F src/where.c 2e75418eb48dbaa675c3e0a112cbd697bd66588c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 8d1ba309211e8afa8be5520bbc1eecf6deacae07 -R eb89dcd4fc9448ac2059e0ee34e53951 +P aae14350a37ad50e4607953ab496cba006032873 +R c9c6efd382ece49dba030de75ba0bdde U drh -Z 8ab3224e95cf812319014fdeea79f2dd +Z 90f206413d760722d5039cb0107594a6 diff --git a/manifest.uuid b/manifest.uuid index 00d4b0108f..36d5135459 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aae14350a37ad50e4607953ab496cba006032873 \ No newline at end of file +0f8a38ee54208d6a477aa2482cd277b4808450f0 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 37d1b151c8..8f25d1d968 100644 --- a/src/where.c +++ b/src/where.c @@ -5192,7 +5192,6 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ WhereLoop *pLoop; int iCur; int j; - int nOrderBy; Table *pTab; Index *pIdx; @@ -5205,29 +5204,19 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ iCur = pItem->iCursor; pWC = &pWInfo->sWC; pLoop = pBuilder->pNew; - pWInfo->a[0].pWLoop = pLoop; pLoop->wsFlags = 0; - pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); - pWInfo->a[0].iTabCur = iCur; -#ifdef SQLITE_DEBUG - pLoop->cId = '0'; -#endif - nOrderBy = pWInfo->pOrderBy ? pWInfo->pOrderBy->nExpr : 0; - pTerm = findTerm(pWC, iCur, -1, 1, WO_EQ, 0); + pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0); if( pTerm ){ pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; pLoop->aLTerm[0] = pTerm; pLoop->nLTerm = 1; pLoop->u.btree.nEq = 1; pLoop->rRun = (WhereCost)10; - pLoop->nOut = (WhereCost)1; - pWInfo->nRowOut = 1; - pWInfo->nOBSat = nOrderBy; }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->onError==OE_None ) continue; for(j=0; jnColumn; j++){ - pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 1, WO_EQ, pIdx); + pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx); if( pTerm==0 ) break; whereLoopResize(pWInfo->pParse->db, pLoop, j); pLoop->aLTerm[j] = pTerm; @@ -5241,13 +5230,22 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ pLoop->u.btree.nEq = j; pLoop->u.btree.pIndex = pIdx; pLoop->rRun = (WhereCost)15; - pLoop->nOut = (WhereCost)1; - pWInfo->nRowOut = 1; - pWInfo->nOBSat = nOrderBy; break; } } - return pLoop->wsFlags!=0; + if( pLoop->wsFlags ){ + pLoop->nOut = (WhereCost)1; + pWInfo->a[0].pWLoop = pLoop; + pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); + pWInfo->a[0].iTabCur = iCur; + pWInfo->nRowOut = 1; + pWInfo->nOBSat = pWInfo->pOrderBy ? pWInfo->pOrderBy->nExpr : 0; +#ifdef SQLITE_DEBUG + pLoop->cId = '0'; +#endif + return 1; + } + return 0; } /* From b8a8e8a5d2f45c74ab624f57a333afa96fe252a1 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Jun 2013 19:12:39 +0000 Subject: [PATCH 101/144] First attempt to store costs and row counts as a logarithm. FossilOrigin-Name: 9e8109673c3a87e379f5a5a97a8b0d5a1afe853d --- manifest | 15 ++-- manifest.uuid | 2 +- src/where.c | 234 +++++++++++++++++++++++++++++--------------------- 3 files changed, 147 insertions(+), 104 deletions(-) diff --git a/manifest b/manifest index d8a42f44d6..7323ba878c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplification\sand\sperformance\stweak\sto\sthe\shigh-speed\sNGQP\sbypass. -D 2013-06-10T14:56:25.426 +C First\sattempt\sto\sstore\scosts\sand\srow\scounts\sas\sa\slogarithm. +D 2013-06-10T19:12:39.512 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 2e75418eb48dbaa675c3e0a112cbd697bd66588c +F src/where.c ae52899cfb8710b5f63c01ac64030b20f284dd5e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,7 +1094,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P aae14350a37ad50e4607953ab496cba006032873 -R c9c6efd382ece49dba030de75ba0bdde +P 0f8a38ee54208d6a477aa2482cd277b4808450f0 +R 17f9a2533926060b9b736553f681baac +T *branch * nextgen-query-plan-logcost +T *sym-nextgen-query-plan-logcost * +T -sym-nextgen-query-plan-exp * U drh -Z 90f206413d760722d5039cb0107594a6 +Z a107d2813c152067f49ec61599513e6e diff --git a/manifest.uuid b/manifest.uuid index 36d5135459..78304d046a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f8a38ee54208d6a477aa2482cd277b4808450f0 \ No newline at end of file +9e8109673c3a87e379f5a5a97a8b0d5a1afe853d \ No newline at end of file diff --git a/src/where.c b/src/where.c index 8f25d1d968..7d2f1f73bb 100644 --- a/src/where.c +++ b/src/where.c @@ -45,7 +45,7 @@ typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; -typedef float WhereCost; +typedef unsigned short int WhereCost; /* 10 times log2() of run-time */ /* ** For each nested loop in a WHERE clause implementation, the WhereInfo @@ -1820,6 +1820,48 @@ static int isDistinctRedundant( return 0; } +/* +** The sum of two WhereCosts +*/ +static WhereCost whereCostAdd(WhereCost a, WhereCost b){ + static const unsigned char x[] = { + 10, 10, /* 0,1 */ + 9, 9, /* 2,3 */ + 8, 8, /* 4,5 */ + 7, 7, 7, /* 6,7,8 */ + 6, 6, 6, /* 9,10,11 */ + 5, 5, 5, /* 12-14 */ + 4, 4, 4, 4, /* 15-18 */ + 3, 3, 3, 3, 3, 3, /* 19-24 */ + 2, 2, 2, 2, 2, 2, 2, /* 25-31 */ + }; + if( a>=b ){ + if( a>b+49 ) return a; + if( a>b+31 ) return a+1; + return a+x[a-b]; + }else{ + if( b>a+49 ) return b; + if( b>a+31 ) return b+1; + return b+x[b-a]; + } +} + +/* +** Convert an integer into a WhereCost +*/ +static WhereCost whereCostFromInt(tRowcnt x){ + static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; + WhereCost y = 40; + if( x<8 ){ + if( x<2 ) return 0; + while( x<8 ){ y -= 10; x <<= 1; } + }else{ + while( x>255 ){ y += 40; x >>= 4; } + while( x>15 ){ y += 10; x >>= 1; } + } + return a[x&7] + y - 10; +} + /* ** Prepare a crude estimate of the logarithm of the input value. ** The results need not be exact. This is only used for estimating @@ -1828,11 +1870,7 @@ static int isDistinctRedundant( ** logN is a little off. */ static WhereCost estLog(WhereCost N){ - u32 a; - assert( sizeof(WhereCost)==4 ); /* 32-bit float input */ - if( N<=0.0 ) return 0.0; - memcpy(&a, &N, 4); - return ((a >>= 23)-127)*0.3; + return whereCostFromInt(N) - 33; } /* @@ -2240,7 +2278,7 @@ static int whereKeyStats( int i, eType; int isEq = 0; i64 v; - WhereCost r, rS; + double r, rS; assert( roundUp==0 || roundUp==1 ); assert( pIdx->nSample>0 ); @@ -2496,11 +2534,11 @@ static int whereRangeScanEst( sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK ){ - if( iUpper<=iLower ){ - *pRangeDiv = (WhereCost)p->aiRowEst[0]; - }else{ - *pRangeDiv = (WhereCost)p->aiRowEst[0]/(WhereCost)(iUpper - iLower); + WhereCost iBase = whereCostFromInt(p->aiRowEst[0]); + if( iUpper>iLower ){ + iBase -= whereCostFromInt(iUpper - iLower); } + *pRangeDiv = iBase; /*WHERETRACE(("range scan regions: %u..%u div=%g\n", (u32)iLower, (u32)iUpper, *pRangeDiv));*/ return SQLITE_OK; @@ -2512,9 +2550,13 @@ static int whereRangeScanEst( UNUSED_PARAMETER(nEq); #endif assert( pLower || pUpper ); - *pRangeDiv = (WhereCost)1; - if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= (WhereCost)4; - if( pUpper ) *pRangeDiv *= (WhereCost)4; + *pRangeDiv = 0; + if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){ + *pRangeDiv += 20; assert( 20==whereCostFromInt(4) ); + } + if( pUpper ){ + *pRangeDiv += 20; assert( 20==whereCostFromInt(4) ); + } return rc; } @@ -2540,7 +2582,7 @@ static int whereEqualScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ - WhereCost *pnRow /* Write the revised row estimate here */ + tRowcnt *pnRow /* Write the revised row estimate here */ ){ sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */ u8 aff; /* Column affinity */ @@ -2589,12 +2631,12 @@ static int whereInScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ - WhereCost *pnRow /* Write the revised row estimate here */ + tRowcnt *pnRow /* Write the revised row estimate here */ ){ - int rc = SQLITE_OK; /* Subfunction return code */ - WhereCost nEst; /* Number of rows for a single term */ - WhereCost nRowEst = (WhereCost)0; /* New estimate of the number of rows */ - int i; /* Loop counter */ + int rc = SQLITE_OK; /* Subfunction return code */ + tRowcnt nEst; /* Number of rows for a single term */ + tRowcnt nRowEst = 0; /* New estimate of the number of rows */ + int i; /* Loop counter */ assert( p->aSample!=0 ); for(i=0; rc==SQLITE_OK && inExpr; i++){ @@ -2982,7 +3024,6 @@ static void explainOneScan( Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ char *zMsg; /* Text to add to EQP output */ - sqlite3_int64 nRow; /* Expected number of rows visited by scan */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ @@ -3037,13 +3078,7 @@ static void explainOneScan( pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif - if( wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ){ - testcase( wctrlFlags & WHERE_ORDERBY_MIN ); - nRow = 1; - }else{ - nRow = (sqlite3_int64)pLoop->nOut; - } - zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow); + zMsg = sqlite3MAppendf(db, zMsg, "%s", zMsg); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } } @@ -3828,7 +3863,7 @@ static Bitmask codeOneLoopStart( ** Print a WhereLoop object for debugging purposes */ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ - int nb = 2*((pTabList->nSrc+15)/16); + int nb = 1+(pTabList->nSrc+7)/8; struct SrcList_item *pItem = pTabList->a + p->iTab; Table *pTab = pItem->pTab; sqlite3DebugPrintf("%c %2d.%0*llx.%0*llx", p->cId, @@ -3860,8 +3895,7 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ sqlite3_free(z); } sqlite3DebugPrintf(" fg %05x N %d", p->wsFlags, p->nLTerm); - sqlite3DebugPrintf(" cost %.2g,%.2g,%.2g\n", - p->prereq, p->rSetup, p->rRun, p->nOut); + sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); } #endif @@ -3995,8 +4029,8 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ */ if( (p = pBuilder->pBest)!=0 ){ if( p->maskSelf!=0 ){ - WhereCost rCost = p->rRun + p->rSetup; - WhereCost rTemplate = pTemplate->rRun + pTemplate->rSetup; + WhereCost rCost = whereCostAdd(p->rRun,p->rSetup); + WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup); if( rCost < rTemplate ){ goto whereLoopInsert_noop; } @@ -4102,7 +4136,7 @@ static int whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ struct SrcList_item *pSrc, /* FROM clause term being analyzed */ Index *pProbe, /* An index on pSrc */ - int nInMul /* Number of iterations due to IN */ + WhereCost nInMul /* log(Number of iterations due to IN) */ ){ WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */ Parse *pParse = pWInfo->pParse; /* Parsing context */ @@ -4118,7 +4152,7 @@ static int whereLoopAddBtreeIndex( WhereCost saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ - tRowcnt iRowEst; /* Estimated index selectivity */ + WhereCost nRowEst; /* Estimated index selectivity */ WhereCost rLogSize; /* Logarithm of table size */ WhereTerm *pTop, *pBtm; /* Top and bottom range constraints */ @@ -4139,10 +4173,10 @@ static int whereLoopAddBtreeIndex( if( pNew->u.btree.nEq < pProbe->nColumn ){ iCol = pProbe->aiColumn[pNew->u.btree.nEq]; - iRowEst = pProbe->aiRowEst[pNew->u.btree.nEq+1]; + nRowEst = whereCostFromInt(pProbe->aiRowEst[pNew->u.btree.nEq+1]); }else{ iCol = -1; - iRowEst = 1; + nRowEst = 0; } pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, pProbe); @@ -4151,10 +4185,10 @@ static int whereLoopAddBtreeIndex( saved_wsFlags = pNew->wsFlags; saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; - pNew->rSetup = (WhereCost)0; - rLogSize = estLog(pProbe->aiRowEst[0]); + pNew->rSetup = 0; + rLogSize = estLog(whereCostFromInt(pProbe->aiRowEst[0])); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ - int nIn = 1; + int nIn = 0; if( pTerm->prereqRight & pNew->maskSelf ) continue; pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; @@ -4168,32 +4202,32 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */ - nIn = 25; + nIn = 46; /* whereCostFromInt(25) */ }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ - nIn = pExpr->x.pList->nExpr; + nIn = whereCostFromInt(pExpr->x.pList->nExpr); } - pNew->rRun *= nIn; + pNew->rRun += nIn; pNew->u.btree.nEq++; - pNew->nOut = (WhereCost)iRowEst * nInMul * nIn; + pNew->nOut = nRowEst + nInMul + nIn; }else if( pTerm->eOperator & (WO_EQ) ){ assert( (pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 - || nInMul==1 ); + || nInMul==0 ); pNew->wsFlags |= WHERE_COLUMN_EQ; if( iCol<0 - || (pProbe->onError!=OE_None && nInMul==1 + || (pProbe->onError!=OE_None && nInMul==0 && pNew->u.btree.nEq==pProbe->nColumn-1) ){ testcase( pNew->wsFlags & WHERE_COLUMN_IN ); pNew->wsFlags |= WHERE_ONEROW; } pNew->u.btree.nEq++; - pNew->nOut = (WhereCost)iRowEst * nInMul; + pNew->nOut = nRowEst + nInMul; }else if( pTerm->eOperator & (WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_NULL; pNew->u.btree.nEq++; - nIn = 2; /* Assume IS NULL matches two rows */ - pNew->nOut = (WhereCost)iRowEst * nInMul * nIn; + nIn = 10; /* Assume IS NULL matches two rows */ + pNew->nOut = nRowEst + nInMul + nIn; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; @@ -4209,27 +4243,29 @@ static int whereLoopAddBtreeIndex( WhereCost rDiv; whereRangeScanEst(pParse, pProbe, pNew->u.btree.nEq, pBtm, pTop, &rDiv); - pNew->nOut = saved_nOut/rDiv; + pNew->nOut = saved_nOut - rDiv; } #ifdef SQLITE_ENABLE_STAT3 if( pNew->u.btree.nEq==1 && pProbe->nSample ){ + tRowcnt nOut = 0; if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ - rc = whereEqualScanEst(pParse, pProbe, pTerm->pExpr->pRight, - &pNew->nOut); + rc = whereEqualScanEst(pParse, pProbe, pTerm->pExpr->pRight, &nOut); }else if( (pTerm->eOperator & WO_IN) && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ - rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, - &pNew->nOut); - + rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut); } + pNew->nOut = whereCostFromInt(nOut); } #endif if( pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK) ){ - pNew->rRun += pNew->nOut; /* Unit step cost to reach each row */ + /* Step cost for each output row */ + pNew->rRun = whereCostAdd(pNew->rRun, pNew->nOut); }else{ /* Each row involves a step of the index, then a binary search of ** the main table */ - pNew->rRun += pNew->nOut*(1 + rLogSize); + pNew->rRun = rLogSize>90 ? + whereCostAdd(pNew->rRun, pNew->nOut+rLogSize-90) : + pNew->rRun; } /* TBD: Adjust nOut for additional constraints */ rc = whereLoopInsert(pBuilder, pNew); @@ -4237,7 +4273,7 @@ static int whereLoopAddBtreeIndex( && pNew->u.btree.nEq<=pProbe->nColumn && pProbe->zName!=0 ){ - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul*nIn); + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } } pNew->prereq = saved_prereq; @@ -4313,8 +4349,8 @@ static int whereLoopAddBtree( int rc = SQLITE_OK; /* Return code */ int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ - WhereCost rSize; /* number of rows in the table */ - WhereCost rLogSize; /* Logarithm of the number of rows in the table */ + WhereCost rSize; /* number of rows in the table */ + WhereCost rLogSize; /* Logarithm of the number of rows in the table */ pNew = pBuilder->pNew; pWInfo = pBuilder->pWInfo; @@ -4347,7 +4383,7 @@ static int whereLoopAddBtree( } pProbe = &sPk; } - rSize = (WhereCost)pSrc->pTab->nRowEst; + rSize = whereCostFromInt(pSrc->pTab->nRowEst); rLogSize = estLog(rSize); /* Automatic indexes */ @@ -4369,9 +4405,10 @@ static int whereLoopAddBtree( pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; - pNew->rSetup = 20*rLogSize*pSrc->pTab->nRowEst; - pNew->nOut = (WhereCost)10; - pNew->rRun = rLogSize + pNew->nOut; + assert( 43==whereCostFromInt(20) ); + pNew->rSetup = 43 + rLogSize + rSize; + pNew->nOut = 33; assert( 33==whereCostFromInt(10) ); + pNew->rRun = whereCostAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_TEMP_INDEX; pNew->prereq = mExtra | pTerm->prereqRight; rc = whereLoopInsert(pBuilder, pNew); @@ -4385,7 +4422,7 @@ static int whereLoopAddBtree( pNew->u.btree.nEq = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; - pNew->rSetup = (WhereCost)0; + pNew->rSetup = 0; pNew->prereq = mExtra; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); @@ -4396,7 +4433,7 @@ static int whereLoopAddBtree( /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; - pNew->rRun = (rSize + rLogSize)*(3+b); /* 4x penalty for a full-scan */ + pNew->rRun = whereCostAdd(rSize,rLogSize) + 16 + b*4; rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; }else{ @@ -4412,12 +4449,12 @@ static int whereLoopAddBtree( ){ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; - pNew->rRun = (m==0) ? (rSize + rLogSize)*(1+b) : (rSize*rLogSize); + pNew->rRun = whereCostAdd(rSize,rLogSize) + ((m==0 && b) ? 10 : 0); rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; } } - rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 1); + rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0); /* If there was an INDEXED BY clause, then only that one index is ** considered. */ @@ -4567,9 +4604,9 @@ static int whereLoopAddVirtual( pNew->u.vtab.idxStr = pIdxInfo->idxStr; pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0) && pIdxInfo->orderByConsumed); - pNew->rSetup = (WhereCost)0; - pNew->rRun = pIdxInfo->estimatedCost; - pNew->nOut = (WhereCost)25; + pNew->rSetup = 0; + pNew->rRun = whereCostFromInt((tRowcnt)pIdxInfo->estimatedCost); + pNew->nOut = 46; assert( 46 == whereCostFromInt(25) ); whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); @@ -4645,16 +4682,16 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ rc = whereLoopAddBtree(&sSubBuild, mExtra); } if( sBest.maskSelf==0 ) break; - assert( sBest.rSetup==(WhereCost)0 ); - rTotal += sBest.rRun; - nRow += sBest.nOut; + assert( sBest.rSetup==0 ); + rTotal = whereCostAdd(rTotal, sBest.rRun); + nRow = whereCostAdd(nRow, sBest.nOut); prereq |= sBest.prereq; } assert( pNew->nLSlot>=1 ); pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; pNew->wsFlags = WHERE_MULTI_OR; - pNew->rSetup = (WhereCost)0; + pNew->rSetup = 0; pNew->rRun = rTotal; pNew->nOut = nRow; pNew->prereq = prereq; @@ -4679,10 +4716,10 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pWInfo->pParse->db; int nTabList = pWInfo->nLevel; int rc = SQLITE_OK; - WhereLoop *pNew, sNew; + WhereLoop *pNew; /* Loop over the tables in the join, from left to right */ - pBuilder->pNew = pNew = &sNew; + pNew = pBuilder->pNew; whereLoopInit(pNew); for(iTab=0, pItem=pTabList->a; iTabiTab = iTab; @@ -4702,7 +4739,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ if( rc || db->mallocFailed ) break; } whereLoopClear(db, pNew); - pBuilder->pNew = 0; return rc; } @@ -4988,20 +5024,20 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ } /* Seed the search with a single WherePath containing zero WhereLoops */ - aFrom[0].nRow = (WhereCost)1; + aFrom[0].nRow = 0; nFrom = 1; /* Precompute the cost of sorting the final result set, if the caller ** to sqlite3WhereBegin() was concerned about sorting */ - rSortCost = (WhereCost)0; - if( pWInfo->pOrderBy==0 || nRowEst<=0.0 ){ + rSortCost = 0; + if( pWInfo->pOrderBy==0 || nRowEst==0 ){ aFrom[0].isOrderedValid = 1; }else{ /* Compute an estimate on the cost to sort the entire result set */ - rSortCost = nRowEst*estLog(nRowEst); + rSortCost = nRowEst + estLog(nRowEst); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace>=2 ){ - sqlite3DebugPrintf("---- sort cost=%-7.2g\n", rSortCost); + sqlite3DebugPrintf("---- sort cost=%-3d\n", rSortCost); } #endif } @@ -5021,7 +5057,8 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ - rCost = pWLoop->rSetup + pWLoop->rRun*pFrom->nRow + pFrom->rCost; + rCost = whereCostAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); + rCost = whereCostAdd(rCost, pFrom->rCost); maskNew = pFrom->maskLoop | pWLoop->maskSelf; if( !isOrderedValid ){ switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, iLoop==nLoop-1, @@ -5033,7 +5070,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ case 0: /* No. pFrom+pWLoop will require a separate sort */ isOrdered = 0; isOrderedValid = 1; - rCost += rSortCost; + rCost = whereCostAdd(rCost, rSortCost); break; default: /* Cannot tell yet. Try again on the next iteration */ break; @@ -5051,7 +5088,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ if( nTo>=mxChoice && rCost>=mxCost ){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("Skip %s cost=%-7.2g order=%c\n", + sqlite3DebugPrintf("Skip %s cost=%3d order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); } @@ -5069,7 +5106,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ pTo = &aTo[jj]; #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("New %s cost=%-7.2g order=%c\n", + sqlite3DebugPrintf("New %s cost=%-3d order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); } @@ -5079,10 +5116,10 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Skip %s cost=%-7.2g order=%c", + "Skip %s cost=%-3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); - sqlite3DebugPrintf(" vs %s cost=%-7.2g order=%c\n", + sqlite3DebugPrintf(" vs %s cost=%-3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } @@ -5093,10 +5130,10 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Update %s cost=%-7.2g order=%c", + "Update %s cost=%-3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); - sqlite3DebugPrintf(" was %s cost=%-7.2g order=%c\n", + sqlite3DebugPrintf(" was %s cost=%-3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } @@ -5105,7 +5142,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; pTo->revLoop = revMask; - pTo->nRow = pFrom->nRow * pWLoop->nOut; + pTo->nRow = pFrom->nRow + pWLoop->nOut; pTo->rCost = rCost; pTo->isOrderedValid = isOrderedValid; pTo->isOrdered = isOrdered; @@ -5124,7 +5161,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ if( sqlite3WhereTrace>=2 ){ sqlite3DebugPrintf("---- after round %d ----\n", iLoop); for(ii=0, pTo=aTo; iirCost, pTo->nRow, pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); if( pTo->isOrderedValid && pTo->isOrdered ){ @@ -5184,7 +5221,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ ** no-frills query planner. Return zero if this query needs the ** general-purpose query planner. */ -static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ +static int whereShortCut(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo; struct SrcList_item *pItem; WhereClause *pWC; @@ -5211,7 +5248,7 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ pLoop->aLTerm[0] = pTerm; pLoop->nLTerm = 1; pLoop->u.btree.nEq = 1; - pLoop->rRun = (WhereCost)10; + pLoop->rRun = 33; /* 33 == whereCostFromInt(10) */ }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->onError==OE_None ) continue; @@ -5229,7 +5266,7 @@ static int whereSimpleFastCase(WhereLoopBuilder *pBuilder){ pLoop->nLTerm = j; pLoop->u.btree.nEq = j; pLoop->u.btree.pIndex = pIdx; - pLoop->rRun = (WhereCost)15; + pLoop->rRun = 39; /* 39 == whereCostFromInt(15) */ break; } } @@ -5406,6 +5443,9 @@ WhereInfo *sqlite3WhereBegin( sWLB.pWC = &pWInfo->sWC; sWLB.pNew = (WhereLoop*)&pWInfo->a[nTabList]; whereLoopInit(sWLB.pNew); +#ifdef SQLITE_DEBUG + sWLB.pNew->cId = '*'; +#endif /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ @@ -5478,7 +5518,7 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(("*** Optimizer Start ***\n")); - if( nTabList!=1 || whereSimpleFastCase(&sWLB)==0 ){ + if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; From c63367ef6848896d8fc602c7aba12977089c72e0 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Jun 2013 20:46:50 +0000 Subject: [PATCH 102/144] Fix some minor issues with logarithmic cost in NGQP. FossilOrigin-Name: 69cf877283d362915edddf1822fbf7a9f86278b3 --- manifest | 19 ++++++++----------- manifest.uuid | 2 +- src/select.c | 12 ++++++------ src/sqliteInt.h | 6 +++--- src/where.c | 30 ++++++++++++++++++++++++++---- 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 7323ba878c..739f017f0f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C First\sattempt\sto\sstore\scosts\sand\srow\scounts\sas\sa\slogarithm. -D 2013-06-10T19:12:39.512 +C Fix\ssome\sminor\sissues\swith\slogarithmic\scost\sin\sNGQP. +D 2013-06-10T20:46:50.026 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -215,12 +215,12 @@ F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c 5e8fe15b1c5b2cc592880d3f039c6a6da55bf253 +F src/select.c ddcf0c795f690968de66ab21051e764ca1c13f09 F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 7b85b09d746cde295c7a0f60711421a28f5c4905 +F src/sqliteInt.h 4284f3a915d6ee86656aa0d47649855e8df8081e F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c ae52899cfb8710b5f63c01ac64030b20f284dd5e +F src/where.c 402d3f74aa8f72bd0d77df6d414cd0ad538411e8 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1094,10 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 0f8a38ee54208d6a477aa2482cd277b4808450f0 -R 17f9a2533926060b9b736553f681baac -T *branch * nextgen-query-plan-logcost -T *sym-nextgen-query-plan-logcost * -T -sym-nextgen-query-plan-exp * +P 9e8109673c3a87e379f5a5a97a8b0d5a1afe853d +R 6b6adbb839b36bd753eb8d10af218a35 U drh -Z a107d2813c152067f49ec61599513e6e +Z 0c1be235257af3633fe6569a03c10208 diff --git a/manifest.uuid b/manifest.uuid index 78304d046a..98fac7263e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9e8109673c3a87e379f5a5a97a8b0d5a1afe853d \ No newline at end of file +69cf877283d362915edddf1822fbf7a9f86278b3 \ No newline at end of file diff --git a/src/select.c b/src/select.c index d160513bd3..ee994a8c20 100644 --- a/src/select.c +++ b/src/select.c @@ -1539,7 +1539,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ if( n==0 ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); }else{ - if( p->nSelectRow > (double)n ) p->nSelectRow = (double)n; + if( p->nSelectRow > n ) p->nSelectRow = n; } }else{ sqlite3ExprCode(pParse, p->pLimit, iLimit); @@ -1733,9 +1733,9 @@ static int multiSelect( p->nSelectRow += pPrior->nSelectRow; if( pPrior->pLimit && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit) - && p->nSelectRow > (double)nLimit + && p->nSelectRow > nLimit ){ - p->nSelectRow = (double)nLimit; + p->nSelectRow = nLimit; } if( addr ){ sqlite3VdbeJumpHere(v, addr); @@ -4239,7 +4239,7 @@ int sqlite3Select( /* Set the limiter. */ iEnd = sqlite3VdbeMakeLabel(v); - p->nSelectRow = (double)LARGEST_INT64; + p->nSelectRow = LARGEST_INT64; computeLimitRegisters(pParse, p, iEnd); if( p->iLimit==0 && addrSortIndex>=0 ){ sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen; @@ -4320,9 +4320,9 @@ int sqlite3Select( for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){ pItem->iAlias = 0; } - if( p->nSelectRow>(double)100 ) p->nSelectRow = (double)100; + if( p->nSelectRow>100 ) p->nSelectRow = 100; }else{ - p->nSelectRow = (double)1; + p->nSelectRow = 1; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 76835385fb..aa1ea51011 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2042,7 +2042,7 @@ struct Select { u16 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ - double nSelectRow; /* Estimated number of result rows */ + u64 nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ @@ -2226,7 +2226,7 @@ struct Parse { /* Information used while coding trigger programs. */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - double nQueryLoop; /* Estimated number of iterations of a query */ + u32 nQueryLoop; /* Estimated number of iterations of a query */ u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ @@ -2796,7 +2796,7 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); -double sqlite3WhereOutputRowCount(WhereInfo*); +u64 sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); diff --git a/src/where.c b/src/where.c index 7d2f1f73bb..4ddb370124 100644 --- a/src/where.c +++ b/src/where.c @@ -45,7 +45,13 @@ typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; -typedef unsigned short int WhereCost; /* 10 times log2() of run-time */ + +/* +** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The +** maximum cost is 64*(2**63) which becomes 6900. So all costs can be +** be stored in a 16-bit unsigned integer without risk of overflow. +*/ +typedef unsigned short int WhereCost; /* ** For each nested loop in a WHERE clause implementation, the WhereInfo @@ -401,11 +407,25 @@ struct WhereInfo { #define WHERE_TEMP_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_COVER_SCAN 0x00008000 /* Full scan of a covering index */ + +/* Convert a WhereCost value (10 times log2(X)) into its integer value X. +*/ +static u64 whereCostToInt(WhereCost x){ + u64 n; + if( x<=10 ) return 1; + n = x%10; + x /= 10; + if( n>=5 ) n -= 2; + else if( n>=1 ) n -= 1; + if( x>=3 ) return (n+8)<<(x-3); + return (n+8)>>(3-x); +} + /* ** Return the estimated number of output rows from a WHERE clause */ -double sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ - return (double)pWInfo->nRowOut; +u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ + return whereCostToInt(pWInfo->nRowOut); } /* @@ -4716,6 +4736,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pWInfo->pParse->db; int nTabList = pWInfo->nLevel; int rc = SQLITE_OK; + u8 priorJoinType = 0; WhereLoop *pNew; /* Loop over the tables in the join, from left to right */ @@ -4724,9 +4745,10 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ for(iTab=0, pItem=pTabList->a; iTabiTab = iTab; pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor); - if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ + if( ((pItem->jointype|priorJoinType) & (JT_LEFT|JT_CROSS))!=0 ){ mExtra = mPrior; } + priorJoinType = pItem->jointype; if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(pBuilder, mExtra); }else{ From 5822d6feb28aa9023abe7133b32d40e91eb3e943 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Jun 2013 23:30:09 +0000 Subject: [PATCH 103/144] Fix test cases for the new EXPLAIN QUERY PLAN format. Add the wherecosttest tool. Other fixes to logarithm cost. FossilOrigin-Name: aa580e368e3c398b8377b80342dfdd906324c248 --- ext/rtree/rtree6.test | 20 +-- ext/rtree/rtree8.test | 1 - manifest | 177 +++++++++++++------------- manifest.uuid | 2 +- src/where.c | 12 +- test/all.test | 2 - test/analyze3.test | 18 +-- test/analyze4.test | 2 +- test/analyze6.test | 22 ++-- test/analyze7.test | 32 ++--- test/analyze8.test | 22 ++-- test/async5.test | 1 - test/autoindex1.test | 24 ++-- test/backup4.test | 1 - test/btreefault.test | 1 - test/capi3e.test | 2 +- test/close.test | 1 - test/corruptF.test | 1 - test/e_createtable.test | 6 +- test/e_fkey.test | 18 +-- test/eqp.test | 256 +++++++++++++++++++------------------- test/exclusive.test | 1 - test/fallocate.test | 1 - test/filefmt.test | 1 - test/fts3aa.test | 1 - test/fts3ao.test | 1 - test/fts3atoken.test | 2 - test/fts3auto.test | 1 - test/fts3aux1.test | 34 ++--- test/fts3corrupt.test | 1 - test/fts3defer2.test | 1 - test/fts3expr3.test | 4 - test/fts3malloc.test | 1 - test/fts3matchinfo.test | 1 - test/fts3prefix2.test | 1 - test/fts3query.test | 16 +-- test/fts3shared.test | 1 - test/fts3snippet.test | 8 +- test/fts3sort.test | 1 - test/fts3tok1.test | 2 - test/fts3tok_err.test | 2 - test/fts4content.test | 1 - test/incrblob3.test | 1 - test/incrblob4.test | 1 - test/incrblobfault.test | 1 - test/incrvacuum3.test | 1 - test/indexedby.test | 54 ++++---- test/io.test | 1 - test/ioerr6.test | 1 - test/lock7.test | 1 - test/misc7.test | 6 +- test/notify3.test | 1 - test/pager1.test | 1 - test/pagerfault.test | 1 - test/pagerfault2.test | 1 - test/pagerfault3.test | 1 - test/securedel2.test | 1 - test/shared8.test | 1 - test/sharedlock.test | 1 - test/tkt-385a5b56b9.test | 8 +- test/tkt-3a77c9714e.test | 1 - test/tkt-3fe897352e.test | 6 +- test/tkt-78e04e52ea.test | 6 +- test/tkt-7a31705a7e6.test | 1 - test/tkt-7bbfb7d442.test | 2 - test/tkt-c48d99d690.test | 1 - test/tkt-d11f09d36e.test | 1 - test/tkt-f3e5abed55.test | 1 - test/tkt-f973c7ac31.test | 1 - test/tkt3442.test | 6 +- test/tkt3918.test | 1 - test/tkt3929.test | 1 - test/unordered.test | 26 ++-- test/veryquick.test | 1 - test/wal8.test | 1 - test/walcksum.test | 1 - test/walcrash.test | 1 - test/walcrash2.test | 1 - test/walcrash3.test | 1 - test/walro.test | 2 - test/walshared.test | 1 - test/where3.test | 42 +++---- test/where7.test | 6 +- test/where9.test | 20 +-- test/whereC.test | 1 - tool/wherecosttest.c | 111 +++++++++++++++++ 86 files changed, 537 insertions(+), 492 deletions(-) create mode 100644 tool/wherecosttest.c diff --git a/ext/rtree/rtree6.test b/ext/rtree/rtree6.test index 320b993368..17985ee525 100644 --- a/ext/rtree/rtree6.test +++ b/ext/rtree/rtree6.test @@ -74,36 +74,36 @@ do_test rtree6-1.5 { do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca (~25 rows)} - 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca} + 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test rtree6.2.2 { SELECT * FROM t1,t2 WHERE k=ii AND x1<10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca (~25 rows)} - 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca} + 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test rtree6.2.3 { SELECT * FROM t1,t2 WHERE k=ii } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2: (~25 rows)} - 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:} + 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test rtree6.2.4 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb (~25 rows)} - 0 1 1 {SCAN TABLE t2 (~100000 rows)} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb} + 0 1 1 {SCAN TABLE t2} } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x1maskSelf==0 ? "ins-init: " : "ins-best: "); whereLoopPrint(pTemplate, pWInfo->pTabList); } #endif + whereLoopXfer(db, p, pTemplate); return SQLITE_OK; } @@ -4138,7 +4138,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ whereLoopInsert_noop: #if WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-noop: "); + sqlite3DebugPrintf(pBuilder->pBest ? "ins-skip: " : "ins-noop: "); whereLoopPrint(pTemplate, pWInfo->pTabList); } #endif @@ -4283,9 +4283,8 @@ static int whereLoopAddBtreeIndex( }else{ /* Each row involves a step of the index, then a binary search of ** the main table */ - pNew->rRun = rLogSize>90 ? - whereCostAdd(pNew->rRun, pNew->nOut+rLogSize-90) : - pNew->rRun; + WhereCost rStepAndSearch = rLogSize>80 ? rLogSize-80 : 1; + pNew->rRun = whereCostAdd(pNew->rRun, rStepAndSearch); } /* TBD: Adjust nOut for additional constraints */ rc = whereLoopInsert(pBuilder, pNew); @@ -5255,6 +5254,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ Index *pIdx; pWInfo = pBuilder->pWInfo; + if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; diff --git a/test/all.test b/test/all.test index cd2a430390..f6e722f2df 100644 --- a/test/all.test +++ b/test/all.test @@ -48,5 +48,3 @@ if {$::tcl_platform(platform)=="unix"} { } finish_test - - diff --git a/test/analyze3.test b/test/analyze3.test index f705bc6661..c25d04422e 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -97,10 +97,10 @@ do_test analyze3-1.1.1 { do_eqp_test analyze3-1.1.2 { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x? AND x0 AND x<1100 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x? AND x200 AND x<300 } @@ -146,10 +146,10 @@ do_test analyze3-1.2.1 { } {} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 -} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x? AND x0 AND x<99 -} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x? AND x12 AND x<20 } } {161 0 4760} @@ -193,10 +193,10 @@ do_test analyze3-1.3.1 { } {} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 -} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x? AND x0 AND x<1100 -} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x? AND x200 AND x<300 } @@ -248,10 +248,10 @@ do_test analyze3-2.1 { } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b? AND b? AND b? AND b? AND b? AND b? AND c? AND c? AND c? AND c? AND owner_change_date? AND owner_change_date= 0} {incr i -1} { } finish_test - diff --git a/test/e_createtable.test b/test/e_createtable.test index 351a0f7220..249b5b0e77 100644 --- a/test/e_createtable.test +++ b/test/e_createtable.test @@ -1368,13 +1368,13 @@ do_execsql_test 4.10.0 { } do_createtable_tests 4.10 { 1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5" - {0 0 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?) (~1 rows)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)}} 2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c" - {0 0 0 {SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1 (~1000000 rows)}} + {0 0 0 {SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1}} 3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10" - {0 0 0 {SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?) (~2 rows)}} + {0 0 0 {SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)}} } # EVIDENCE-OF: R-45493-35653 A CHECK constraint may be attached to a diff --git a/test/e_fkey.test b/test/e_fkey.test index 001ba6c386..976ed16325 100644 --- a/test/e_fkey.test +++ b/test/e_fkey.test @@ -974,15 +974,15 @@ do_execsql_test e_fkey-25.2 { EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?; } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SCAN TABLE track (~100000 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SCAN TABLE track} } do_execsql_test e_fkey-25.3 { PRAGMA foreign_keys = ON; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SCAN TABLE track (~100000 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SCAN TABLE track} } do_test e_fkey-25.4 { execsql { @@ -1099,15 +1099,15 @@ do_test e_fkey-27.2 { do_execsql_test e_fkey-27.3 { EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ? } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)} - 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} + 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} } do_execsql_test e_fkey-27.4 { EXPLAIN QUERY PLAN DELETE FROM artist } { - 0 0 0 {SCAN TABLE artist (~1000000 rows)} - 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?) (~10 rows)} + 0 0 0 {SCAN TABLE artist} + 0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} } diff --git a/test/eqp.test b/test/eqp.test index 454f2afbdd..f137920309 100644 --- a/test/eqp.test +++ b/test/eqp.test @@ -43,37 +43,37 @@ do_execsql_test 1.1 { do_eqp_test 1.2 { SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; } { - 0 0 1 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} - 0 0 1 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)} - 0 1 0 {SCAN TABLE t2 (~1000000 rows)} + 0 0 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)} + 0 0 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)} + 0 1 0 {SCAN TABLE t2} } do_eqp_test 1.3 { SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; } { - 0 0 0 {SCAN TABLE t2 (~1000000 rows)} - 0 1 1 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} - 0 1 1 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)} + 0 0 0 {SCAN TABLE t2} + 0 1 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)} + 0 1 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)} } do_eqp_test 1.3 { SELECT a FROM t1 ORDER BY a } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} } do_eqp_test 1.4 { SELECT a FROM t1 ORDER BY +a } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 1.5 { SELECT a FROM t1 WHERE a=4 } { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)} } do_eqp_test 1.6 { SELECT DISTINCT count(*) FROM t3 GROUP BY a; } { - 0 0 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 0 {SCAN TABLE t3} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } @@ -81,40 +81,40 @@ do_eqp_test 1.6 { do_eqp_test 1.7 { SELECT * FROM t3 JOIN (SELECT 1) } { - 0 0 1 {SCAN SUBQUERY 1 (~1 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)} - 0 0 1 {SCAN SUBQUERY 1 (~2 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.9 { SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) } { - 3 0 0 {SCAN TABLE t3 (~1000000 rows)} + 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (EXCEPT)} - 0 0 1 {SCAN SUBQUERY 1 (~17 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.10 { SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) } { - 3 0 0 {SCAN TABLE t3 (~1000000 rows)} + 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (INTERSECT)} - 0 0 1 {SCAN SUBQUERY 1 (~1 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.11 { SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) } { - 3 0 0 {SCAN TABLE t3 (~1000000 rows)} + 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)} - 0 0 1 {SCAN SUBQUERY 1 (~17 rows)} - 0 1 0 {SCAN TABLE t3 (~1000000 rows)} + 0 0 1 {SCAN SUBQUERY 1} + 0 1 0 {SCAN TABLE t3} } #------------------------------------------------------------------------- @@ -129,48 +129,48 @@ do_execsql_test 2.1 { } det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.3 "SELECT DISTINCT * FROM t1" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } det 2.2.4 "SELECT DISTINCT * FROM t1, t2" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} - 0 1 1 {SCAN TABLE t2 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} - 0 1 1 {SCAN TABLE t2 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" { - 0 0 1 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} - 0 1 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 1 {SCAN TABLE t2 USING COVERING INDEX t2i1} + 0 1 0 {SCAN TABLE t1} } det 2.3.1 "SELECT max(x) FROM t2" { - 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1 (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1} } det 2.3.2 "SELECT min(x) FROM t2" { - 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1 (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1} } det 2.3.3 "SELECT min(x), max(x) FROM t2" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} } det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { - 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} } @@ -181,39 +181,39 @@ det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { do_eqp_test 3.1.1 { SELECT (SELECT x FROM t1 AS sub) FROM t1; } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 AS sub} } do_eqp_test 3.1.2 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub); } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 AS sub} } do_eqp_test 3.1.3 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y); } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 AS sub} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 3.1.4 { SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x); } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} } det 3.2.1 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 0 0 0 {SCAN SUBQUERY 1 (~10 rows)} + 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 3.2.2 { @@ -222,34 +222,34 @@ det 3.2.2 { (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2 ORDER BY x2.y LIMIT 5 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 USING INDEX t2i1 (~1000000 rows)} - 0 0 0 {SCAN SUBQUERY 1 AS x1 (~10 rows)} - 0 1 1 {SCAN SUBQUERY 2 AS x2 (~10 rows)} + 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} + 0 0 0 {SCAN SUBQUERY 1 AS x1} + 0 1 1 {SCAN SUBQUERY 2 AS x2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 3.3.1 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2) } { - 0 0 0 {SCAN TABLE t1 (~100000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE LIST SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 (~1000000 rows)} + 1 0 0 {SCAN TABLE t2} } det 3.3.2 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x) } { - 0 0 0 {SCAN TABLE t1 (~500000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 (~500000 rows)} + 1 0 0 {SCAN TABLE t2} } det 3.3.3 { SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x) } { - 0 0 0 {SCAN TABLE t1 (~500000 rows)} + 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1} - 1 0 0 {SCAN TABLE t2 (~500000 rows)} + 1 0 0 {SCAN TABLE t2} } #------------------------------------------------------------------------- @@ -258,43 +258,43 @@ det 3.3.3 { do_eqp_test 4.1.1 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} + 2 0 0 {SCAN TABLE t2} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.1.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.1.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)} } do_eqp_test 4.1.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)} } do_eqp_test 4.1.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } @@ -302,35 +302,35 @@ do_eqp_test 4.1.5 { do_eqp_test 4.2.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 USING INDEX t2i1 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.2.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)} } do_eqp_test 4.2.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)} } do_eqp_test 4.2.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } @@ -338,28 +338,28 @@ do_eqp_test 4.2.5 { do_eqp_test 4.3.1 { SELECT x FROM t1 UNION SELECT x FROM t2 } { - 1 0 0 {SCAN TABLE t1 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1} + 2 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } do_eqp_test 4.3.2 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 } { - 2 0 0 {SCAN TABLE t1 (~1000000 rows)} - 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 2 0 0 {SCAN TABLE t1} + 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)} - 4 0 0 {SCAN TABLE t1 (~1000000 rows)} + 4 0 0 {SCAN TABLE t1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 4 USING TEMP B-TREE (UNION)} } do_eqp_test 4.3.3 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1 } { - 2 0 0 {SCAN TABLE t1 (~1000000 rows)} + 2 0 0 {SCAN TABLE t1} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} - 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1 (~1000000 rows)} + 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION)} - 4 0 0 {SCAN TABLE t1 (~1000000 rows)} + 4 0 0 {SCAN TABLE t1} 4 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 4 (UNION)} } @@ -371,127 +371,127 @@ do_eqp_test 4.3.3 { drop_all_tables # EVIDENCE-OF: R-64208-08323 sqlite> EXPLAIN QUERY PLAN SELECT a, b -# FROM t1 WHERE a=1; 0|0|0|SCAN TABLE t1 (~100000 rows) +# FROM t1 WHERE a=1; 0|0|0|SCAN TABLE t1 do_execsql_test 5.1.0 { CREATE TABLE t1(a, b) } det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SCAN TABLE t1 (~100000 rows)} + 0 0 0 {SCAN TABLE t1} } # EVIDENCE-OF: R-09022-44606 sqlite> CREATE INDEX i1 ON t1(a); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; -# 0|0|0|SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows) +# 0|0|0|SEARCH TABLE t1 USING INDEX i1 (a=?) do_execsql_test 5.2.0 { CREATE INDEX i1 ON t1(a) } det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } # EVIDENCE-OF: R-62228-34103 sqlite> CREATE INDEX i2 ON t1(a, b); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; -# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows) +# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) do_execsql_test 5.3.0 { CREATE INDEX i2 ON t1(a, b) } det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} } # EVIDENCE-OF: R-22253-05302 sqlite> EXPLAIN QUERY PLAN SELECT t1.*, # t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2; 0|0|0|SEARCH TABLE t1 -# USING COVERING INDEX i2 (a=? AND b>?) (~3 rows) 0|1|1|SCAN TABLE t2 -# (~1000000 rows) +# USING COVERING INDEX i2 (a=? AND b>?) 0|1|1|SCAN TABLE t2 +# do_execsql_test 5.4.0 {CREATE TABLE t2(c, d)} det 5.4.1 "SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) (~2 rows)} - 0 1 1 {SCAN TABLE t2 (~1000000 rows)} + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} + 0 1 1 {SCAN TABLE t2} } # EVIDENCE-OF: R-21040-07025 sqlite> EXPLAIN QUERY PLAN SELECT t1.*, # t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2; 0|0|1|SEARCH TABLE t1 -# USING COVERING INDEX i2 (a=? AND b>?) (~3 rows) 0|1|0|SCAN TABLE t2 -# (~1000000 rows) +# USING COVERING INDEX i2 (a=? AND b>?) 0|1|0|SCAN TABLE t2 +# det 5.5 "SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { - 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) (~2 rows)} - 0 1 0 {SCAN TABLE t2 (~1000000 rows)} + 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} + 0 1 0 {SCAN TABLE t2} } # EVIDENCE-OF: R-39007-61103 sqlite> CREATE INDEX i3 ON t1(b); # sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2; -# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows) -# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) (~10 rows) +# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) +# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)} det 5.6.1 "SELECT * FROM t1 WHERE a=1 OR b=2" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows)} - 0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} + 0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } # EVIDENCE-OF: R-33025-54904 sqlite> EXPLAIN QUERY PLAN SELECT c, d -# FROM t2 ORDER BY c; 0|0|0|SCAN TABLE t2 (~1000000 rows) 0|0|0|USE TEMP +# FROM t2 ORDER BY c; 0|0|0|SCAN TABLE t2 0|0|0|USE TEMP # B-TREE FOR ORDER BY det 5.7 "SELECT c, d FROM t2 ORDER BY c" { - 0 0 0 {SCAN TABLE t2 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # EVIDENCE-OF: R-38854-22809 sqlite> CREATE INDEX i4 ON t2(c); # sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; -# 0|0|0|SCAN TABLE t2 USING INDEX i4 (~1000000 rows) +# 0|0|0|SCAN TABLE t2 USING INDEX i4 do_execsql_test 5.8.0 {CREATE INDEX i4 ON t2(c)} det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" { - 0 0 0 {SCAN TABLE t2 USING INDEX i4 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING INDEX i4} } # EVIDENCE-OF: R-29884-43993 sqlite> EXPLAIN QUERY PLAN SELECT # (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2; -# 0|0|0|SCAN TABLE t2 (~1000000 rows) 0|0|0|EXECUTE SCALAR SUBQUERY 1 -# 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows) +# 0|0|0|SCAN TABLE t2 0|0|0|EXECUTE SCALAR SUBQUERY 1 +# 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 2|0|0|SEARCH TABLE t1 USING -# INDEX i3 (b=?) (~10 rows) +# INDEX i3 (b=?) det 5.9 { SELECT (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2 } { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i4 (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) (~10 rows)} + 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} - 2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?) (~10 rows)} + 2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } # EVIDENCE-OF: R-17911-16445 sqlite> EXPLAIN QUERY PLAN SELECT # count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x; -# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows) 0|0|0|SCAN -# SUBQUERY 1 (~1000000 rows) 0|0|0|USE TEMP B-TREE FOR GROUP BY +# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 0|0|0|SCAN +# SUBQUERY 1 0|0|0|USE TEMP B-TREE FOR GROUP BY det 5.10 { SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x } { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows)} - 0 0 0 {SCAN SUBQUERY 1 (~100 rows)} + 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} + 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } # EVIDENCE-OF: R-18544-33103 sqlite> EXPLAIN QUERY PLAN SELECT * FROM # (SELECT * FROM t2 WHERE c=1), t1; 0|0|0|SEARCH TABLE t2 USING INDEX i4 -# (c=?) (~10 rows) 0|1|1|SCAN TABLE t1 (~1000000 rows) +# (c=?) 0|1|1|SCAN TABLE t1 det 5.11 "SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1" { - 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?) (~10 rows)} - 0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows)} + 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} + 0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2} } # EVIDENCE-OF: R-40701-42164 sqlite> EXPLAIN QUERY PLAN SELECT a FROM -# t1 UNION SELECT c FROM t2; 1|0|0|SCAN TABLE t1 (~1000000 rows) -# 2|0|0|SCAN TABLE t2 (~1000000 rows) 0|0|0|COMPOUND SUBQUERIES 1 AND 2 +# t1 UNION SELECT c FROM t2; 1|0|0|SCAN TABLE t1 +# 2|0|0|SCAN TABLE t2 0|0|0|COMPOUND SUBQUERIES 1 AND 2 # USING TEMP B-TREE (UNION) det 5.12 "SELECT a FROM t1 UNION SELECT c FROM t2" { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} + 2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } # EVIDENCE-OF: R-61538-24748 sqlite> EXPLAIN QUERY PLAN SELECT a FROM # t1 EXCEPT SELECT d FROM t2 ORDER BY 1; 1|0|0|SCAN TABLE t1 USING -# COVERING INDEX i2 (~1000000 rows) 2|0|0|SCAN TABLE t2 (~1000000 rows) +# COVERING INDEX i2 2|0|0|SCAN TABLE t2 # 2|0|0|USE TEMP B-TREE FOR ORDER BY 0|0|0|COMPOUND SUBQUERIES 1 AND 2 # (EXCEPT) det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows)} - 2 0 0 {SCAN TABLE t2 (~1000000 rows)} + 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} + 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } @@ -531,8 +531,8 @@ proc do_peqp_test {tn sql res} { do_peqp_test 6.1 { SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1 } [string trimleft { -1 0 0 SCAN TABLE t1 USING COVERING INDEX i2 (~1000000 rows) -2 0 0 SCAN TABLE t2 (~1000000 rows) +1 0 0 SCAN TABLE t1 USING COVERING INDEX i2 +2 0 0 SCAN TABLE t2 2 0 0 USE TEMP B-TREE FOR ORDER BY 0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) }] @@ -550,7 +550,7 @@ do_execsql_test 7.0 { } det 7.1 "SELECT count(*) FROM t1" { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 0 {SCAN TABLE t1} } det 7.2 "SELECT count(*) FROM t2" { @@ -572,7 +572,7 @@ db close sqlite3 db test.db det 7.4 "SELECT count(*) FROM t1" { - 0 0 0 {SCAN TABLE t1 (~2 rows)} + 0 0 0 {SCAN TABLE t1} } det 7.5 "SELECT count(*) FROM t2" { diff --git a/test/exclusive.test b/test/exclusive.test index ffde891533..c000dfefa4 100644 --- a/test/exclusive.test +++ b/test/exclusive.test @@ -506,4 +506,3 @@ do_execsql_test exclusive-6.5 { } {exclusive} finish_test - diff --git a/test/fallocate.test b/test/fallocate.test index 8a5fa32360..f523c2cc4a 100644 --- a/test/fallocate.test +++ b/test/fallocate.test @@ -143,4 +143,3 @@ if {!$skipwaltests} { finish_test - diff --git a/test/filefmt.test b/test/filefmt.test index bc1af18e8b..2df1424436 100644 --- a/test/filefmt.test +++ b/test/filefmt.test @@ -248,4 +248,3 @@ do_test filefmt-4.4 { db2 close finish_test - diff --git a/test/fts3aa.test b/test/fts3aa.test index 5d79e9318f..bde38af553 100644 --- a/test/fts3aa.test +++ b/test/fts3aa.test @@ -224,4 +224,3 @@ do_catchsql_test fts3aa-7.5 { finish_test - diff --git a/test/fts3ao.test b/test/fts3ao.test index 786667a7f3..91693094db 100644 --- a/test/fts3ao.test +++ b/test/fts3ao.test @@ -220,4 +220,3 @@ do_execsql_test 5.2 { } {0 6} finish_test - diff --git a/test/fts3atoken.test b/test/fts3atoken.test index 9277bfb8e6..b7722c7d04 100644 --- a/test/fts3atoken.test +++ b/test/fts3atoken.test @@ -193,5 +193,3 @@ do_test fts3token-internal { finish_test - - diff --git a/test/fts3auto.test b/test/fts3auto.test index 20b2812dcc..20640d29ac 100644 --- a/test/fts3auto.test +++ b/test/fts3auto.test @@ -707,4 +707,3 @@ foreach {tn create} { set sqlite_fts3_enable_parentheses $sfep finish_test - diff --git a/test/fts3aux1.test b/test/fts3aux1.test index f421b7f6ef..d17ac85df5 100644 --- a/test/fts3aux1.test +++ b/test/fts3aux1.test @@ -105,10 +105,10 @@ db func rec rec # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~25 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} } do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' -} {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)}} +} {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}} # Now show that using "term='braid'" means the virtual table returns # only 1 row to SQLite, but "+term='braid'" means all 19 are returned. @@ -154,24 +154,24 @@ do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2: (~25 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2:} } do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4: (~25 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4:} } do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_execsql_test 2.2.1.5 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6: (~25 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6:} } do_execsql_test 2.2.1.6 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain' -} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} } +} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_test 2.2.2.1 { set cnt 0 @@ -335,7 +335,7 @@ foreach {tn sort orderby} { 9 1 "ORDER BY occurrences DESC" } { - set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)}] + set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}] if {$sort} { lappend res 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } set sql "SELECT * FROM terms $orderby" @@ -410,32 +410,32 @@ proc do_plansql_test {tn sql r} { do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { - 0 0 0 {SCAN TABLE x2 (~1000000 rows)} - 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~25 rows)} + 0 0 0 {SCAN TABLE x2} + 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} a b c d e f g h i j k l } do_plansql_test 4.3 { SELECT y FROM terms, x2 WHERE y = term AND col = '*' } { - 0 0 1 {SCAN TABLE x2 (~1000000 rows)} - 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1: (~25 rows)} + 0 0 1 {SCAN TABLE x2} + 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} a b c d e f g h i j k l } do_plansql_test 4.4 { SELECT y FROM x3, terms WHERE y = term AND col = '*' } { - 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} - 0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)} + 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} + 0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)} a b c d e f g h i j k l } do_plansql_test 4.5 { SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*' } { - 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0: (~25 rows)} - 0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) (~10 rows)} + 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} + 0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)} a k l } diff --git a/test/fts3corrupt.test b/test/fts3corrupt.test index ea4c9a9d3b..cb50e3e46a 100644 --- a/test/fts3corrupt.test +++ b/test/fts3corrupt.test @@ -166,4 +166,3 @@ do_test 5.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB finish_test - diff --git a/test/fts3defer2.test b/test/fts3defer2.test index 337359af6e..608371f15d 100644 --- a/test/fts3defer2.test +++ b/test/fts3defer2.test @@ -153,4 +153,3 @@ foreach {tn sql} { finish_test - diff --git a/test/fts3expr3.test b/test/fts3expr3.test index e3cc2619c6..a8d7319266 100644 --- a/test/fts3expr3.test +++ b/test/fts3expr3.test @@ -204,7 +204,3 @@ do_faultsim_test fts3expr3-fault-1 -faults oom-* -body { set sqlite_fts3_enable_parentheses 0 finish_test - - - - diff --git a/test/fts3malloc.test b/test/fts3malloc.test index 7eeee7fe0d..efd1e062f6 100644 --- a/test/fts3malloc.test +++ b/test/fts3malloc.test @@ -301,4 +301,3 @@ do_write_test fts3_malloc-5.3 ft_content { finish_test - diff --git a/test/fts3matchinfo.test b/test/fts3matchinfo.test index 3998c9a40c..3da3a77427 100644 --- a/test/fts3matchinfo.test +++ b/test/fts3matchinfo.test @@ -427,4 +427,3 @@ do_execsql_test 8.3 { } finish_test - diff --git a/test/fts3prefix2.test b/test/fts3prefix2.test index e3da3b7593..e033fb6bcb 100644 --- a/test/fts3prefix2.test +++ b/test/fts3prefix2.test @@ -59,4 +59,3 @@ do_execsql_test 1.3 { } finish_test - diff --git a/test/fts3query.test b/test/fts3query.test index 51b84be906..2d12351ae9 100644 --- a/test/fts3query.test +++ b/test/fts3query.test @@ -118,26 +118,26 @@ do_test fts3query-4.1 { do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~25 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:} } do_eqp_test fts3query-4.3 { SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date } { - 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1: (~25 rows)} + 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:} } do_eqp_test fts3query-4.4 { SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date } { - 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 1 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 1 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test fts3query-4.5 { SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date } { - 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1 (~1000000 rows)} - 0 1 0 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} + 0 1 0 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)} } diff --git a/test/fts3shared.test b/test/fts3shared.test index a587a437bf..0943c0510f 100644 --- a/test/fts3shared.test +++ b/test/fts3shared.test @@ -174,4 +174,3 @@ dbW close dbR close sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/fts3snippet.test b/test/fts3snippet.test index b8646cdfaa..f19db925ba 100644 --- a/test/fts3snippet.test +++ b/test/fts3snippet.test @@ -432,10 +432,10 @@ foreach {DO_MALLOC_TEST enc} { {2 2 1 3 3 3 6 3 0 0 0 2 3 2} }] - # EVIDENCE-OF: R-40630-02268 If used within a SELECT that uses the - # "query by rowid" or "linear scan" strategies, then the snippet and - # offsets both return an empty string, and the matchinfo function - # returns a blob value zero bytes in size. + # EVIDENCE-OF: R-40630-02268 If used within a SELECT that uses the + # "query by rowid" or "linear scan" strategies, then the snippet and + # offsets both return an empty string, and the matchinfo function + # returns a blob value zero bytes in size. # set r 1000000 ;# A rowid that exists in table ft do_select_test $T.10.0 { SELECT rowid FROM ft WHERE rowid = $r } $r diff --git a/test/fts3sort.test b/test/fts3sort.test index be7560432b..218bf3e827 100644 --- a/test/fts3sort.test +++ b/test/fts3sort.test @@ -182,4 +182,3 @@ do_execsql_test 3.2 { finish_test - diff --git a/test/fts3tok1.test b/test/fts3tok1.test index 98e55a06c1..4faed34d12 100644 --- a/test/fts3tok1.test +++ b/test/fts3tok1.test @@ -113,5 +113,3 @@ do_catchsql_test 2.1 { finish_test - - diff --git a/test/fts3tok_err.test b/test/fts3tok_err.test index aaa7272b7b..df0d4beebd 100644 --- a/test/fts3tok_err.test +++ b/test/fts3tok_err.test @@ -45,5 +45,3 @@ do_faultsim_test fts3tok_err-2 -faults oom* -prep { finish_test - - diff --git a/test/fts4content.test b/test/fts4content.test index 302f14e510..6b2cd3cc8e 100644 --- a/test/fts4content.test +++ b/test/fts4content.test @@ -623,4 +623,3 @@ do_execsql_test 10.7 { } finish_test - diff --git a/test/incrblob3.test b/test/incrblob3.test index 4c49f1563c..5f2e860d08 100644 --- a/test/incrblob3.test +++ b/test/incrblob3.test @@ -269,4 +269,3 @@ db close tvfs delete finish_test - diff --git a/test/incrblob4.test b/test/incrblob4.test index a96356b06f..a92e373536 100644 --- a/test/incrblob4.test +++ b/test/incrblob4.test @@ -87,4 +87,3 @@ do_test 3.3 { } {} finish_test - diff --git a/test/incrblobfault.test b/test/incrblobfault.test index d125471c4b..0c1d93d460 100644 --- a/test/incrblobfault.test +++ b/test/incrblobfault.test @@ -67,4 +67,3 @@ do_faultsim_test 3 -prep { } finish_test - diff --git a/test/incrvacuum3.test b/test/incrvacuum3.test index f01dc100b8..e901bfe1f5 100644 --- a/test/incrvacuum3.test +++ b/test/incrvacuum3.test @@ -151,4 +151,3 @@ foreach {T jrnl_mode} { } finish_test - diff --git a/test/indexedby.test b/test/indexedby.test index 7ccc4de24a..955d185619 100644 --- a/test/indexedby.test +++ b/test/indexedby.test @@ -42,15 +42,15 @@ proc EQP {sql} { # do_execsql_test indexedby-1.2 { EXPLAIN QUERY PLAN select * from t1 WHERE a = 10; -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-1.3 { EXPLAIN QUERY PLAN select * from t1 ; -} {0 0 0 {SCAN TABLE t1 (~1000000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-1.4 { EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10; } { - 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)} - 0 1 0 {SCAN TABLE t1 (~1000000 rows)} + 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} + 0 1 0 {SCAN TABLE t1} } # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be @@ -85,15 +85,15 @@ do_test indexedby-2.7 { # do_execsql_test indexedby-3.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' -} {0 0 0 {SCAN TABLE t1 (~10000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-3.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-3.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-3.4 { catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } } {1 {cannot use index: i2}} @@ -110,11 +110,11 @@ do_test indexedby-3.7 { do_execsql_test indexedby-3.8 { EXPLAIN QUERY PLAN SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e -} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1 (~1000000 rows)}} +} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}} do_execsql_test indexedby-3.9 { EXPLAIN QUERY PLAN SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 -} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?) (~1 rows)}} +} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}} do_test indexedby-3.10 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } } {1 {cannot use index: sqlite_autoindex_t3_1}} @@ -127,14 +127,14 @@ do_test indexedby-3.11 { do_execsql_test indexedby-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c } { - 0 0 0 {SCAN TABLE t1 (~1000000 rows)} - 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?) (~10 rows)} + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} } do_execsql_test indexedby-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } { - 0 0 1 {SCAN TABLE t2 (~1000000 rows)} - 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~10 rows)} + 0 0 1 {SCAN TABLE t2} + 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } do_test indexedby-4.3 { catchsql { @@ -154,10 +154,10 @@ do_test indexedby-4.4 { do_execsql_test indexedby-5.1 { CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; EXPLAIN QUERY PLAN SELECT * FROM v2 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~250000 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} do_execsql_test indexedby-5.2 { EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~25000 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} do_test indexedby-5.3 { execsql { DROP INDEX i1 } catchsql { SELECT * FROM v2 } @@ -178,28 +178,28 @@ do_test indexedby-5.5 { # do_execsql_test indexedby-6.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_execsql_test indexedby-6.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid -} {0 0 0 {SCAN TABLE t1 USING INTEGER PRIMARY KEY (~100000 rows)}} +} {0 0 0 {SCAN TABLE t1 USING INTEGER PRIMARY KEY}} # Test that "INDEXED BY" can be used in a DELETE statement. # do_execsql_test indexedby-7.1 { EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-7.2 { EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5 -} {0 0 0 {SCAN TABLE t1 (~100000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-7.3 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-7.4 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-7.5 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-7.6 { catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} } {1 {cannot use index: i2}} @@ -208,21 +208,21 @@ do_test indexedby-7.6 { # do_execsql_test indexedby-8.1 { EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-8.2 { EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 -} {0 0 0 {SCAN TABLE t1 (~100000 rows)}} +} {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-8.3 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 -} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-8.4 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-8.5 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?) (~2 rows)}} +} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-8.6 { catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} } {1 {cannot use index: i2}} diff --git a/test/io.test b/test/io.test index 11f9cc8422..c5086c10ec 100644 --- a/test/io.test +++ b/test/io.test @@ -641,4 +641,3 @@ foreach {tn sql} { sqlite3_simulate_device -char {} -sectorsize 0 finish_test - diff --git a/test/ioerr6.test b/test/ioerr6.test index 66c48ad2e8..d1847b2877 100644 --- a/test/ioerr6.test +++ b/test/ioerr6.test @@ -89,4 +89,3 @@ do_faultsim_test 3 -faults full* -prep { } finish_test - diff --git a/test/lock7.test b/test/lock7.test index 49bc147a22..02f2c6c630 100644 --- a/test/lock7.test +++ b/test/lock7.test @@ -58,4 +58,3 @@ db1 close db2 close finish_test - diff --git a/test/misc7.test b/test/misc7.test index 72c1cd64ff..96062a93b9 100644 --- a/test/misc7.test +++ b/test/misc7.test @@ -269,17 +269,17 @@ ifcapable explain { CREATE TABLE abc(a PRIMARY KEY, b, c); EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid = 1; } { - 0 0 0 {SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test misc7-14.2 { EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE a = 1; } {0 0 0 - {SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?) (~1 rows)} + {SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?)} } do_execsql_test misc7-14.3 { EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 ORDER BY a; } {0 0 0 - {SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (~1000000 rows)} + {SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1} } } diff --git a/test/notify3.test b/test/notify3.test index 446f010780..4b5e8016b4 100644 --- a/test/notify3.test +++ b/test/notify3.test @@ -150,4 +150,3 @@ catch { db2 close } sqlite3_enable_shared_cache $esc finish_test - diff --git a/test/pager1.test b/test/pager1.test index 72e47805a4..4a3b6fa2d8 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -2815,4 +2815,3 @@ do_test 43.3 { } {0 1 0} finish_test - diff --git a/test/pagerfault.test b/test/pagerfault.test index 23754fa9de..796f531c37 100644 --- a/test/pagerfault.test +++ b/test/pagerfault.test @@ -1546,4 +1546,3 @@ sqlite3_shutdown sqlite3_config_uri 0 finish_test - diff --git a/test/pagerfault2.test b/test/pagerfault2.test index 6cdb99a3ed..7f6c995efd 100644 --- a/test/pagerfault2.test +++ b/test/pagerfault2.test @@ -96,4 +96,3 @@ do_faultsim_test pagerfault2-2 -faults oom-transient -prep { sqlite3_memdebug_vfs_oom_test 1 finish_test - diff --git a/test/pagerfault3.test b/test/pagerfault3.test index 3d192e6d43..a4301cd17d 100644 --- a/test/pagerfault3.test +++ b/test/pagerfault3.test @@ -61,4 +61,3 @@ do_faultsim_test pagerfault3-1 -faults ioerr-transient -prep { } finish_test - diff --git a/test/securedel2.test b/test/securedel2.test index b20f4f9212..9badc560d4 100644 --- a/test/securedel2.test +++ b/test/securedel2.test @@ -92,4 +92,3 @@ do_test 1.6.2 { } {0} finish_test - diff --git a/test/shared8.test b/test/shared8.test index 600e02bf7e..73f0d47627 100644 --- a/test/shared8.test +++ b/test/shared8.test @@ -110,4 +110,3 @@ do_test 1.8 { foreach db {db1 db2 db3 db4} { catch { $db close } } sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/sharedlock.test b/test/sharedlock.test index 1e78eeafdf..9dd7fe2bff 100644 --- a/test/sharedlock.test +++ b/test/sharedlock.test @@ -52,4 +52,3 @@ db2 close sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/tkt-385a5b56b9.test b/test/tkt-385a5b56b9.test index 8184864865..1338435ed6 100644 --- a/test/tkt-385a5b56b9.test +++ b/test/tkt-385a5b56b9.test @@ -35,19 +35,19 @@ do_execsql_test 2.0 { } do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2x (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2x} } do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2y (~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2y} } do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } { - 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?) (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)} } do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } { - 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x=?) (~1 rows)} + 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x=?)} } finish_test diff --git a/test/tkt-3a77c9714e.test b/test/tkt-3a77c9714e.test index 6eaec16cdd..b7d366f36e 100644 --- a/test/tkt-3a77c9714e.test +++ b/test/tkt-3a77c9714e.test @@ -70,4 +70,3 @@ do_execsql_test 2.2 { finish_test - diff --git a/test/tkt-3fe897352e.test b/test/tkt-3fe897352e.test index deafe48e0e..bc2b2033e7 100644 --- a/test/tkt-3fe897352e.test +++ b/test/tkt-3fe897352e.test @@ -16,9 +16,9 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl - -# The following tests use hex_to_utf16be() and hex_to_utf16le() which -# which are only available if SQLite is built with UTF16 support. + +# The following tests use hex_to_utf16be() and hex_to_utf16le() which +# which are only available if SQLite is built with UTF16 support. ifcapable {!utf16} { finish_test return diff --git a/test/tkt-78e04e52ea.test b/test/tkt-78e04e52ea.test index a664ceb9e6..e906d3b7f9 100644 --- a/test/tkt-78e04e52ea.test +++ b/test/tkt-78e04e52ea.test @@ -44,7 +44,7 @@ do_test tkt-78e04-1.4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM "" WHERE "" LIKE 'abc%'; } -} {0 0 0 {SCAN TABLE USING COVERING INDEX i1 (~500000 rows)}} +} {0 0 0 {SCAN TABLE USING COVERING INDEX i1}} do_test tkt-78e04-1.5 { execsql { DROP TABLE ""; @@ -57,12 +57,12 @@ do_test tkt-78e04-2.1 { CREATE INDEX "" ON t2(x); EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=5; } -} {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX (x=?) (~10 rows)}} +} {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX (x=?)}} do_test tkt-78e04-2.2 { execsql { DROP INDEX ""; EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=2; } -} {0 0 0 {SCAN TABLE t2 (~100000 rows)}} +} {0 0 0 {SCAN TABLE t2}} finish_test diff --git a/test/tkt-7a31705a7e6.test b/test/tkt-7a31705a7e6.test index 64701220a8..e3e402917d 100644 --- a/test/tkt-7a31705a7e6.test +++ b/test/tkt-7a31705a7e6.test @@ -23,4 +23,3 @@ do_execsql_test tkt-7a31705a7e6-1.1 { CREATE TABLE t2x (b INTEGER PRIMARY KEY); SELECT t1.a FROM ((t1 JOIN t2 ON t1.a=t2.a) AS x JOIN t2x ON x.b=t2x.b) as y; } {} - diff --git a/test/tkt-7bbfb7d442.test b/test/tkt-7bbfb7d442.test index dcb9b16058..56d4caeb3e 100644 --- a/test/tkt-7bbfb7d442.test +++ b/test/tkt-7bbfb7d442.test @@ -152,5 +152,3 @@ do_execsql_test 2.3 { finish_test - - diff --git a/test/tkt-c48d99d690.test b/test/tkt-c48d99d690.test index 9b40579917..6d1b9dbe61 100644 --- a/test/tkt-c48d99d690.test +++ b/test/tkt-c48d99d690.test @@ -23,4 +23,3 @@ do_test 1.1 { do_test 1.2 { execsql VACUUM } {} finish_test - diff --git a/test/tkt-d11f09d36e.test b/test/tkt-d11f09d36e.test index 70657706c4..ffd3d21928 100644 --- a/test/tkt-d11f09d36e.test +++ b/test/tkt-d11f09d36e.test @@ -59,4 +59,3 @@ do_test tkt-d11f09d36e.5 { } {ok} finish_test - diff --git a/test/tkt-f3e5abed55.test b/test/tkt-f3e5abed55.test index b3f5d5656c..3c793d4f4d 100644 --- a/test/tkt-f3e5abed55.test +++ b/test/tkt-f3e5abed55.test @@ -114,4 +114,3 @@ if {[permutation]!="inmemory_journal"} { finish_test - diff --git a/test/tkt-f973c7ac31.test b/test/tkt-f973c7ac31.test index 882e86a0a0..454309057f 100644 --- a/test/tkt-f973c7ac31.test +++ b/test/tkt-f973c7ac31.test @@ -84,4 +84,3 @@ foreach {tn sql} { finish_test - diff --git a/test/tkt3442.test b/test/tkt3442.test index ae03949d54..ee9169ce2c 100644 --- a/test/tkt3442.test +++ b/test/tkt3442.test @@ -49,10 +49,10 @@ proc EQP {sql} { ifcapable explain { do_test tkt3442-1.2 { EQP { SELECT node FROM listhash WHERE id='5000' LIMIT 1; } - } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}} + } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} do_test tkt3442-1.3 { EQP { SELECT node FROM listhash WHERE id="5000" LIMIT 1; } - } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}} + } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} } @@ -61,7 +61,7 @@ ifcapable explain { ifcapable explain { do_test tkt3442-1.4 { EQP { SELECT node FROM listhash WHERE id=5000 LIMIT 1; } - } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?) (~1 rows)}} + } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} } do_test tkt3442-1.5 { catchsql { diff --git a/test/tkt3918.test b/test/tkt3918.test index c46ad8f6c1..e20ee152fc 100644 --- a/test/tkt3918.test +++ b/test/tkt3918.test @@ -57,4 +57,3 @@ do_test tkt3918.5 { } {} finish_test - diff --git a/test/tkt3929.test b/test/tkt3929.test index 3ed4d288c4..db02bb841e 100644 --- a/test/tkt3929.test +++ b/test/tkt3929.test @@ -50,4 +50,3 @@ do_test tkt3930-1.2 { integrity_check tkt3930-1.3 finish_test - diff --git a/test/unordered.test b/test/unordered.test index 4aa8310f89..78183b4923 100644 --- a/test/unordered.test +++ b/test/unordered.test @@ -40,28 +40,28 @@ foreach idxmode {ordered unordered} { sqlite3 db test.db foreach {tn sql r(ordered) r(unordered)} { 1 "SELECT * FROM t1 ORDER BY a" - {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}} - {0 0 0 {SCAN TABLE t1 (~128 rows)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} + {0 0 0 {SCAN TABLE t1 USING INDEX i1}} + {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} 2 "SELECT * FROM t1 WHERE a >?" - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~32 rows)}} - {0 0 0 {SCAN TABLE t1 (~42 rows)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} + {0 0 0 {SCAN TABLE t1}} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}} - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} 4 "SELECT max(a) FROM t1" - {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}} - {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}} + {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1}} + {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1}} 5 "SELECT group_concat(b) FROM t1 GROUP BY a" - {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}} - {0 0 0 {SCAN TABLE t1 (~128 rows)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}} + {0 0 0 {SCAN TABLE t1 USING INDEX i1}} + {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}} 6 "SELECT * FROM t1 WHERE a = ?" - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}} - {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} + {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} 7 "SELECT count(*) FROM t1" {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1(~128 rows)}} - {0 0 0 {SCAN TABLE t1 (~128 rows)}} + {0 0 0 {SCAN TABLE t1}} } { do_eqp_test 1.$idxmode.$tn $sql $r($idxmode) } diff --git a/test/veryquick.test b/test/veryquick.test index ca82b22b92..c8d6ce8f8b 100644 --- a/test/veryquick.test +++ b/test/veryquick.test @@ -16,4 +16,3 @@ source $testdir/permutations.test run_test_suite veryquick finish_test - diff --git a/test/wal8.test b/test/wal8.test index 339953895c..0682fce35b 100644 --- a/test/wal8.test +++ b/test/wal8.test @@ -88,4 +88,3 @@ do_execsql_test 3.1 { } {t1} finish_test - diff --git a/test/walcksum.test b/test/walcksum.test index 08278dd054..3005a758ac 100644 --- a/test/walcksum.test +++ b/test/walcksum.test @@ -390,4 +390,3 @@ foreach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} { } finish_test - diff --git a/test/walcrash.test b/test/walcrash.test index adc4841dd1..2a647188b0 100644 --- a/test/walcrash.test +++ b/test/walcrash.test @@ -293,4 +293,3 @@ for {set i 1} {$i < $REPEATS} {incr i} { } finish_test - diff --git a/test/walcrash2.test b/test/walcrash2.test index 7116281c2d..9c93bcdef3 100644 --- a/test/walcrash2.test +++ b/test/walcrash2.test @@ -96,4 +96,3 @@ do_test walcrash2-1.3 { catch { db2 close } finish_test - diff --git a/test/walcrash3.test b/test/walcrash3.test index c2c9a6d518..71dfb4555a 100644 --- a/test/walcrash3.test +++ b/test/walcrash3.test @@ -126,4 +126,3 @@ for {set i 2} {$i<10000 && [set_test_counter errors]==$nInitialErr} {incr i} { } finish_test - diff --git a/test/walro.test b/test/walro.test index 465ce838c2..f1ed275a1d 100644 --- a/test/walro.test +++ b/test/walro.test @@ -291,5 +291,3 @@ do_multiclient_test tn { } finish_test - - diff --git a/test/walshared.test b/test/walshared.test index 73a3fb8bc1..fbbdeb4de3 100644 --- a/test/walshared.test +++ b/test/walshared.test @@ -60,4 +60,3 @@ do_test walshared-1.4 { sqlite3_enable_shared_cache $::enable_shared_cache finish_test - diff --git a/test/where3.test b/test/where3.test index 842f683749..cee74ba434 100644 --- a/test/where3.test +++ b/test/where3.test @@ -236,15 +236,15 @@ do_execsql_test where3-3.0 { ANALYZE; explain query plan SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y; } { - 0 0 0 {SCAN TABLE t302 (~1 rows)} - 0 1 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SCAN TABLE t302} + 0 1 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test where3-3.1 { explain query plan SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y; } { - 0 0 1 {SCAN TABLE t302 (~1 rows)} - 0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SCAN TABLE t302} + 0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} } # Verify that when there are multiple tables in a join which must be @@ -258,25 +258,25 @@ do_execsql_test where3-4.0 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t402.z GLOB 'abc*'; } { - 0 0 2 {SCAN TABLE t402 (~500000 rows)} - 0 1 0 {SCAN TABLE t400 (~1000000 rows)} - 0 2 1 {SCAN TABLE t401 (~1000000 rows)} + 0 0 2 {SCAN TABLE t402} + 0 1 0 {SCAN TABLE t400} + 0 2 1 {SCAN TABLE t401} } do_execsql_test where3-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t401.r GLOB 'abc*'; } { - 0 0 1 {SCAN TABLE t401 (~500000 rows)} - 0 1 0 {SCAN TABLE t400 (~1000000 rows)} - 0 2 2 {SCAN TABLE t402 (~1000000 rows)} + 0 0 1 {SCAN TABLE t401} + 0 1 0 {SCAN TABLE t400} + 0 2 2 {SCAN TABLE t402} } do_execsql_test where3-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t400.c GLOB 'abc*'; } { - 0 0 0 {SCAN TABLE t400 (~500000 rows)} - 0 1 1 {SCAN TABLE t401 (~1000000 rows)} - 0 2 2 {SCAN TABLE t402 (~1000000 rows)} + 0 0 0 {SCAN TABLE t400} + 0 1 1 {SCAN TABLE t401} + 0 2 2 {SCAN TABLE t402} } # Verify that a performance regression encountered by firefox @@ -308,8 +308,8 @@ do_execsql_test where3-5.0 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 1 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 1 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.1 { @@ -321,8 +321,8 @@ do_execsql_test where3-5.1 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 1 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 1 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.2 { @@ -334,8 +334,8 @@ do_execsql_test where3-5.2 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 0 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 0 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.3 { @@ -347,8 +347,8 @@ do_execsql_test where3-5.3 { AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { - 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) (~10 rows)} - 0 1 0 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} + 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} + 0 1 0 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } diff --git a/test/where7.test b/test/where7.test index b6cd7ccbbc..3cb8781200 100644 --- a/test/where7.test +++ b/test/where7.test @@ -23339,9 +23339,9 @@ do_execsql_test where7-3.1 { OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { - 0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?) (~10 rows)} - 0 0 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} - 0 1 0 {SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?) (~2 rows)} + 0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?)} + 0 0 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} + 0 1 0 {SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } diff --git a/test/where9.test b/test/where9.test index 1e94fdff78..d6a8c597b4 100644 --- a/test/where9.test +++ b/test/where9.test @@ -362,9 +362,9 @@ ifcapable explain { SELECT t2.a FROM t1, t2 WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f) } { - 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} - 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)} - 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} + 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} + 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)} } do_execsql_test where9-3.2 { EXPLAIN QUERY PLAN @@ -372,9 +372,9 @@ ifcapable explain { FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f WHERE t1.a=80 } { - 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} - 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?) (~2 rows)} - 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) (~10 rows)} + 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} + 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} + 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)} } } @@ -453,8 +453,8 @@ ifcapable explain { do_execsql_test where9-5.1 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL) } { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?) (~3 rows)} - 0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?) (~3 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?)} } # In contrast, b=1000 is preferred over any OR-clause. @@ -462,7 +462,7 @@ ifcapable explain { do_execsql_test where9-5.2 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL) } { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~5 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)} } # Likewise, inequalities in an AND are preferred over inequalities in @@ -471,7 +471,7 @@ ifcapable explain { do_execsql_test where9-5.3 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL) } { - 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>?) (~125000 rows)} + 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>?)} } } diff --git a/test/whereC.test b/test/whereC.test index 9fa1bbaf95..bd7fe9ad82 100644 --- a/test/whereC.test +++ b/test/whereC.test @@ -67,4 +67,3 @@ foreach {tn sql res} { finish_test - diff --git a/tool/wherecosttest.c b/tool/wherecosttest.c new file mode 100644 index 0000000000..3055358fc2 --- /dev/null +++ b/tool/wherecosttest.c @@ -0,0 +1,111 @@ +/* +** 2013-06-10 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains a simple command-line utility for converting from +** integers and WhereCost values and back again and for doing simple +** arithmetic operations (multiple and add) on WhereCost values. +** +** Usage: +** +** ./wherecosttest ARGS +** +** Arguments: +** +** 'x' Multiple the top two elements of the stack +** '+' Add the top two elements of the stack +** NUM Convert NUM from integer to WhereCost and push onto the stack +** ^NUM Interpret NUM as a WhereCost and push onto stack. +** +** Examples: +** +** To convert 123 from WhereCost to integer: +** +** ./wherecosttest ^123 +** +** To convert 123456 from integer to WhereCost: +** +** ./wherecosttest 123456 +** +*/ +#include +#include +#include + +typedef unsigned short int WhereCost; /* 10 times log2() */ + +WhereCost whereCostMultiply(WhereCost a, WhereCost b){ return a+b; } +WhereCost whereCostAdd(WhereCost a, WhereCost b){ + static const unsigned char x[] = { + 10, 10, /* 0,1 */ + 9, 9, /* 2,3 */ + 8, 8, /* 4,5 */ + 7, 7, 7, /* 6,7,8 */ + 6, 6, 6, /* 9,10,11 */ + 5, 5, 5, /* 12-14 */ + 4, 4, 4, 4, /* 15-18 */ + 3, 3, 3, 3, 3, 3, /* 19-24 */ + 2, 2, 2, 2, 2, 2, 2, /* 25-31 */ + }; + if( ab+49 ) return a; + if( a>b+31 ) return a+1; + return a+x[a-b]; +} +WhereCost whereCostFromInteger(int x){ + static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; + WhereCost y = 40; + if( x<8 ){ + if( x<2 ) return 0; + while( x<8 ){ y -= 10; x <<= 1; } + }else{ + while( x>255 ){ y += 40; x >>= 4; } + while( x>15 ){ y += 10; x >>= 1; } + } + return a[x&7] + y - 10; +} +static unsigned long int whereCostToInt(WhereCost x){ + unsigned long int n; + if( x<=10 ) return 1; + n = x%10; + x /= 10; + if( n>=5 ) n -= 2; + else if( n>=1 ) n -= 1; + if( x>=3 ) return (n+8)<<(x-3); + return (n+8)>>(3-x); +} + +int main(int argc, char **argv){ + int i; + int n = 0; + WhereCost a[100]; + for(i=1; i=2 ){ + a[n-2] = whereCostAdd(a[n-2],a[n-1]); + n--; + } + }else if( z[0]=='x' ){ + if( n>=2 ){ + a[n-2] = whereCostMultiply(a[n-2],a[n-1]); + n--; + } + }else if( z[0]=='^' ){ + a[n++] = atoi(z+1); + }else{ + a[n++] = whereCostFromInteger(atoi(z)); + } + } + for(i=n-1; i>=0; i--){ + printf("%d (%lu)\n", a[i], whereCostToInt(a[i])); + } + return 0; +} From 8636e9c55cb46f8923ebbb8a1014010d9c813472 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 11 Jun 2013 01:50:08 +0000 Subject: [PATCH 104/144] Handle virtual tables correctly when using logarithmic costs. Fixes to test cases. FossilOrigin-Name: e612664aa2e24ed5e222be2c7fe16e210ac9bded --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/where.c | 39 ++++++++++++++++++++++++++++++++++----- test/analyze5.test | 32 ++++++++++++++++---------------- test/between.test | 4 ++-- test/eqp.test | 4 ++-- 6 files changed, 64 insertions(+), 35 deletions(-) diff --git a/manifest b/manifest index c92fe224c3..cda6c0adff 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stest\scases\sfor\sthe\snew\sEXPLAIN\sQUERY\sPLAN\sformat.\s\sAdd\sthe\nwherecosttest\stool.\s\sOther\sfixes\sto\slogarithm\scost. -D 2013-06-10T23:30:09.637 +C Handle\svirtual\stables\scorrectly\swhen\susing\slogarithmic\scosts.\s\sFixes\nto\stest\scases. +D 2013-06-11T01:50:08.263 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 672b76db7422b7bbc94fe1be42183c6356e56e96 +F src/where.c 72f9aa6c35dadf0d432c2d80fd117d8887f70473 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -303,7 +303,7 @@ F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/analyze.test f8ab7d15858b4093b06caf5e57e2a5ff7104bdae F test/analyze3.test 69863b446539f8849a996c2aa0b50461c9cecea4 F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 -F test/analyze5.test 713354664c5ff1853ab2cbcb740f0cf5cb7c802e +F test/analyze5.test 3e57f192307be931f9ab2f6ff456f9063358ac77 F test/analyze6.test cdbf9887d40ab41301f570fe85c6e1525dd3b1c9 F test/analyze7.test 7de3ab66e1981303e783102a012d62cb876bf1d5 F test/analyze8.test ea4972c76820ac8d6a0754e6f5b851292f0f5a61 @@ -335,7 +335,7 @@ F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f F test/bc_common.tcl 5c8689cc6d2fb44b7c0968ae4f85eb26d50022fa -F test/between.test e6896728a636e3e610bcb2f87c9305120c809bc5 +F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 7c79f1ef0c6c2c2bc1e7bd895596fab32bfb4796 F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 @@ -440,7 +440,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020 -F test/eqp.test ac506be979f611719a2a2de8476fe608fc9d66a4 +F test/eqp.test 68dd66c8fa05551d056ebd7fc8ae3b2e1cb5836e F test/errmsg.test 050717f1c6a5685de9c79f5f9f6b83d7c592f73a F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 69cf877283d362915edddf1822fbf7a9f86278b3 -R 6bac639abb86e2ec49ce16ea155e2dc3 +P aa580e368e3c398b8377b80342dfdd906324c248 +R dc216beb84f13406fad3ccd046a844fe U drh -Z f81162c822de40652566c68321ce2c25 +Z a1ab90c9180f43596814678177a2e938 diff --git a/manifest.uuid b/manifest.uuid index 072a7b4e84..b4b006445a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aa580e368e3c398b8377b80342dfdd906324c248 \ No newline at end of file +e612664aa2e24ed5e222be2c7fe16e210ac9bded \ No newline at end of file diff --git a/src/where.c b/src/where.c index 2b0049b9c3..4a27b9e382 100644 --- a/src/where.c +++ b/src/where.c @@ -1882,6 +1882,23 @@ static WhereCost whereCostFromInt(tRowcnt x){ return a[x&7] + y - 10; } +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Convert a double (as received from xBestIndex of a virtual table) +** into a WhereCost +*/ +static WhereCost whereCostFromDouble(double x){ + u64 a; + WhereCost e; + assert( sizeof(x)==8 && sizeof(a)==8 ); + if( x<=1 ) return 0; + if( x<=2000000000 ) return whereCostFromInt((tRowcnt)x); + memcpy(&a, &x, 8); + e = (a>>52) - 1022; + return e*10; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + /* ** Prepare a crude estimate of the logarithm of the input value. ** The results need not be exact. This is only used for estimating @@ -4088,6 +4105,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** more terms of the index */ pNext = p->pNextLoop; break; + }else if( p->nOut>pTemplate->nOut + && p->rSetup==pTemplate->rSetup + && p->rRun==pTemplate->rRun + ){ + /* Overwrite an existing WhereLoop with the same cost but more + ** outputs */ + pNext = p->pNextLoop; + break; }else{ /* pTemplate is not helpful. ** Return without changing or adding anything */ @@ -4263,7 +4288,7 @@ static int whereLoopAddBtreeIndex( WhereCost rDiv; whereRangeScanEst(pParse, pProbe, pNew->u.btree.nEq, pBtm, pTop, &rDiv); - pNew->nOut = saved_nOut - rDiv; + pNew->nOut = saved_nOut>rDiv+10 ? saved_nOut - rDiv : 10; } #ifdef SQLITE_ENABLE_STAT3 if( pNew->u.btree.nEq==1 && pProbe->nSample ){ @@ -4482,6 +4507,7 @@ static int whereLoopAddBtree( return rc; } +#ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. @@ -4569,8 +4595,7 @@ static int whereLoopAddVirtual( pIdxInfo->idxNum = 0; pIdxInfo->needToFreeIdxStr = 0; pIdxInfo->orderByConsumed = 0; - /* ((WhereCost)2) In case of SQLITE_OMIT_FLOATING_POINT... */ - pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((WhereCost)2); + pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; rc = vtabBestIndex(pParse, pTab, pIdxInfo); if( rc ) goto whereLoopAddVtab_exit; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; @@ -4624,7 +4649,7 @@ static int whereLoopAddVirtual( pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0) && pIdxInfo->orderByConsumed); pNew->rSetup = 0; - pNew->rRun = whereCostFromInt((tRowcnt)pIdxInfo->estimatedCost); + pNew->rRun = whereCostFromDouble(pIdxInfo->estimatedCost); pNew->nOut = 46; assert( 46 == whereCostFromInt(25) ); whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ @@ -4639,6 +4664,7 @@ whereLoopAddVtab_exit: sqlite3DbFree(db, pIdxInfo); return rc; } +#endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Add WhereLoop entries to handle OR terms. This works for either @@ -4695,9 +4721,12 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ sBest.maskSelf = 0; sBest.rSetup = 0; sBest.rRun = 0; +#ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mExtra); - }else{ + }else +#endif + { rc = whereLoopAddBtree(&sSubBuild, mExtra); } if( sBest.maskSelf==0 ) break; diff --git a/test/analyze5.test b/test/analyze5.test index 1041d709d2..c400780fff 100644 --- a/test/analyze5.test +++ b/test/analyze5.test @@ -156,13 +156,14 @@ foreach {testid where index rows} { } { # Verify that the expected index is used with the expected row count - do_test analyze5-1.${testid}a { - set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] - set idx {} - regexp {INDEX (t1.) } $x all idx - regexp {~([0-9]+) rows} $x all nrow - list $idx $nrow - } [list $index $rows] + # No longer valid due to an EXPLAIN QUERY PLAN output format change + # do_test analyze5-1.${testid}a { + # set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] + # set idx {} + # regexp {INDEX (t1.) } $x all idx + # regexp {~([0-9]+) rows} $x all nrow + # list $idx $nrow + # } [list $index $rows] # Verify that the same result is achieved regardless of whether or not # the index is used @@ -202,15 +203,14 @@ foreach {testid where index rows} { } { # Verify that the expected index is used with the expected row count -if {$testid==50299} {breakpoint; set sqlite_where_trace 1} - do_test analyze5-1.${testid}a { - set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] - set idx {} - regexp {INDEX (t1.) } $x all idx - regexp {~([0-9]+) rows} $x all nrow - list $idx $nrow - } [list $index $rows] -if {$testid==50299} exit + # No longer valid due to an EXPLAIN QUERY PLAN format change + # do_test analyze5-1.${testid}a { + # set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3] + # set idx {} + # regexp {INDEX (t1.) } $x all idx + # regexp {~([0-9]+) rows} $x all nrow + # list $idx $nrow + # } [list $index $rows] # Verify that the same result is achieved regardless of whether or not # the index is used diff --git a/test/between.test b/test/between.test index f089cd95d3..df4c67995c 100644 --- a/test/between.test +++ b/test/between.test @@ -58,10 +58,10 @@ proc queryplan {sql} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { - if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { lappend data $tab * } } diff --git a/test/eqp.test b/test/eqp.test index f137920309..ad7d4edad2 100644 --- a/test/eqp.test +++ b/test/eqp.test @@ -554,7 +554,7 @@ det 7.1 "SELECT count(*) FROM t1" { } det 7.2 "SELECT count(*) FROM t2" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1(~1000000 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1} } do_execsql_test 7.3 { @@ -576,7 +576,7 @@ det 7.4 "SELECT count(*) FROM t1" { } det 7.5 "SELECT count(*) FROM t2" { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1(~3 rows)} + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1} } From 8a4380d76156ba0ffbcdb64b5e37f82dee6385c6 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 11 Jun 2013 02:32:50 +0000 Subject: [PATCH 105/144] Fixes to EXPLAIN QUERY PLAN output. Change weights back to something closer to what they are in legacy. More test case fixes. FossilOrigin-Name: 36373b85f9a97840aa06e24ae31c12fcfbae084e --- manifest | 24 ++++++++++++------------ manifest.uuid | 2 +- src/select.c | 7 +++---- src/where.c | 2 +- test/like.test | 6 +++--- test/where.test | 16 ++++++++-------- test/where2.test | 4 ++-- test/where3.test | 4 ++-- test/whereE.test | 8 ++++---- 9 files changed, 36 insertions(+), 37 deletions(-) diff --git a/manifest b/manifest index cda6c0adff..6c5cbae82b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Handle\svirtual\stables\scorrectly\swhen\susing\slogarithmic\scosts.\s\sFixes\nto\stest\scases. -D 2013-06-11T01:50:08.263 +C Fixes\sto\sEXPLAIN\sQUERY\sPLAN\soutput.\s\sChange\sweights\sback\sto\ssomething\scloser\nto\swhat\sthey\sare\sin\slegacy.\s\sMore\stest\scase\sfixes. +D 2013-06-11T02:32:50.482 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -215,7 +215,7 @@ F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c ddcf0c795f690968de66ab21051e764ca1c13f09 +F src/select.c 588ae13fc3d10dc812a0832fd143374583beb847 F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 72f9aa6c35dadf0d432c2d80fd117d8887f70473 +F src/where.c 1241512fecb60142384231ba902e3b68a550c0b8 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -620,7 +620,7 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test 52e650adfa208325f928b847571d77b647af07c3 +F test/like.test 935fb4f608e3ea126891496a6e99b9468372bf5c F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99 F test/loadext.test 92e6dfefd1229c3ef4aaabd87419efd8fa57a7a5 @@ -1029,9 +1029,9 @@ F test/walro.test 6cc247a0cc9b36aeea2057dd28a922a1cdfbd630 F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e -F test/where.test 054a6b6f7933c5a5f50d0bcd650b5eccb450cc81 -F test/where2.test 116fb0d6e98a423d12eb9a65906218ce09936674 -F test/where3.test 1f2a9c997243dc39c67d38fe6d73254ab2f880b8 +F test/where.test cd13d4804b8f2986b176fb45c0a43fbbba64215a +F test/where2.test 58cc3f85c082015144bc34c7ffdbd64134f650ee +F test/where3.test f2a7027e1971d583069947edba0a31563e86284f F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b @@ -1043,7 +1043,7 @@ F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62 -F test/whereE.test 7bd34945797efef15819368479bacc34215e4e1d +F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P aa580e368e3c398b8377b80342dfdd906324c248 -R dc216beb84f13406fad3ccd046a844fe +P e612664aa2e24ed5e222be2c7fe16e210ac9bded +R 22fdd5c799c9a709871f8decba5b6ac4 U drh -Z a1ab90c9180f43596814678177a2e938 +Z 5d13a5c0b3748ceb3b9bdd15d82353e6 diff --git a/manifest.uuid b/manifest.uuid index b4b006445a..5783c7e87f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e612664aa2e24ed5e222be2c7fe16e210ac9bded \ No newline at end of file +36373b85f9a97840aa06e24ae31c12fcfbae084e \ No newline at end of file diff --git a/src/select.c b/src/select.c index ee994a8c20..8972faacc6 100644 --- a/src/select.c +++ b/src/select.c @@ -3884,11 +3884,10 @@ static void explainSimpleCount( Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ - char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s %s%s(~%d rows)", + char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", pTab->zName, - pIdx ? "USING COVERING INDEX " : "", - pIdx ? pIdx->zName : "", - pTab->nRowEst + pIdx ? " USING COVERING INDEX " : "", + pIdx ? pIdx->zName : "" ); sqlite3VdbeAddOp4( pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC diff --git a/src/where.c b/src/where.c index 4a27b9e382..330faf771c 100644 --- a/src/where.c +++ b/src/where.c @@ -4308,7 +4308,7 @@ static int whereLoopAddBtreeIndex( }else{ /* Each row involves a step of the index, then a binary search of ** the main table */ - WhereCost rStepAndSearch = rLogSize>80 ? rLogSize-80 : 1; + WhereCost rStepAndSearch = whereCostAdd(10, rLogSize>17 ? rLogSize-17 : 1); pNew->rRun = whereCostAdd(pNew->rRun, rStepAndSearch); } /* TBD: Adjust nOut for additional constraints */ diff --git a/test/like.test b/test/like.test index f68a93537b..230dc74fed 100644 --- a/test/like.test +++ b/test/like.test @@ -166,13 +166,13 @@ proc queryplan {sql} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { - if {[regexp { TABLE (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\W} \ + if {[regexp { TABLE (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\y} \ $x all as tab idx]} { lappend data {} $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + } elseif {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { lappend data $tab * } } diff --git a/test/where.test b/test/where.test index 8610fa6f3d..39324bf1a6 100644 --- a/test/where.test +++ b/test/where.test @@ -67,7 +67,7 @@ do_test where-1.1.1 { } {3 121 10 3} do_eqp_test where-1.1.2 { SELECT x, y, w FROM t1 WHERE w=10 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.1.3 { db status step } {0} @@ -79,13 +79,13 @@ do_test where-1.1.5 { } {99} do_eqp_test where-1.1.6 { SELECT x, y, w FROM t1 WHERE +w=10 -} {*SCAN TABLE t1 *} +} {*SCAN TABLE t1*} do_test where-1.1.7 { count {SELECT x, y, w AS abc FROM t1 WHERE abc=10} } {3 121 10 3} do_eqp_test where-1.1.8 { SELECT x, y, w AS abc FROM t1 WHERE abc=10 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.1.9 { db status step } {0} @@ -106,19 +106,19 @@ do_test where-1.4.1 { } {11 3 144 3} do_eqp_test where-1.4.2 { SELECT w, x, y FROM t1 WHERE 11=w AND x>2 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.4.3 { count {SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2} } {11 3 144 3} do_eqp_test where-1.4.4 { SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.5 { count {SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2} } {3 144 3} do_eqp_test where-1.5.2 { SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?) *} +} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} do_test where-1.6 { count {SELECT x, y FROM t1 WHERE y<200 AND x>2 AND w=11} } {3 144 3} @@ -130,10 +130,10 @@ do_test where-1.8 { } {3 144 3} do_eqp_test where-1.8.2 { SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3 -} {*SEARCH TABLE t1 USING INDEX i1xy (x=? AND y=?) *} +} {*SEARCH TABLE t1 USING INDEX i1xy (x=? AND y=?)*} do_eqp_test where-1.8.3 { SELECT x, y FROM t1 WHERE y=144 AND x=3 -} {*SEARCH TABLE t1 USING COVERING INDEX i1xy (x=? AND y=?) *} +} {*SEARCH TABLE t1 USING COVERING INDEX i1xy (x=? AND y=?)*} do_test where-1.9 { count {SELECT x, y FROM t1 WHERE y=144 AND w>10 AND x=3} } {3 144 3} diff --git a/test/where2.test b/test/where2.test index d7fb514a87..c55d4a12a3 100644 --- a/test/where2.test +++ b/test/where2.test @@ -76,10 +76,10 @@ proc queryplan {sql} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { - if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { lappend data $tab * } } diff --git a/test/where3.test b/test/where3.test index cee74ba434..e6acafed07 100644 --- a/test/where3.test +++ b/test/where3.test @@ -111,10 +111,10 @@ proc queryplan {sql} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { - if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\W} \ + if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+)\W} $x all as tab]} { + } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { lappend data $tab * } } diff --git a/test/whereE.test b/test/whereE.test index e686a4628e..a6b8f481b2 100644 --- a/test/whereE.test +++ b/test/whereE.test @@ -47,16 +47,16 @@ do_execsql_test 1.1 { CREATE UNIQUE INDEX t2zx ON t2(z,x); EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.2 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.3 { ANALYZE; EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.4 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} finish_test From 8e23daf372c57084e7921e48c1b7968b631bb94d Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 11 Jun 2013 13:30:04 +0000 Subject: [PATCH 106/144] Fix the Parse.nQueryLoop state variable to work with NGQP. FossilOrigin-Name: f1cac24f06b9c71cfa472fdcf2da4cd8689a7cc3 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/expr.c | 6 +++--- src/prepare.c | 4 ++-- src/sqliteInt.h | 2 +- src/where.c | 9 +++++---- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index f2ea8783ae..9e3a53b7f0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sa\slogarithmic\srather\sthan\slinear\scost\sand\srow-count\smeasures.\nDo\snot\sreport\srow\scount\sestimates\sin\sEQP\soutput. -D 2013-06-11T02:36:41.347 +C Fix\sthe\sParse.nQueryLoop\sstate\svariable\sto\swork\swith\sNGQP. +D 2013-06-11T13:30:04.431 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -171,7 +171,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778 -F src/expr.c ac9d259eea3123faa05fabe6dd8717696aca72b1 +F src/expr.c 9cc9e4c85197b567e5f97f3296700faf7747810f F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179 F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef @@ -210,7 +210,7 @@ F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938 F src/pragma.c 67a611bd4be0754f27ee13eb87932c3b14415862 -F src/prepare.c 743e484233c51109666d402f470523553b41797c +F src/prepare.c 213de4aae5e29cfbb32202d1c09f4fc4b5a51b09 F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 @@ -220,7 +220,7 @@ F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 4284f3a915d6ee86656aa0d47649855e8df8081e +F src/sqliteInt.h f2e51444e15f7dd35c1ee139f95f43b0bccf3fb5 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 1241512fecb60142384231ba902e3b68a550c0b8 +F src/where.c 572357246bee5389751427c670cb0222fe36be78 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 0f8a38ee54208d6a477aa2482cd277b4808450f0 36373b85f9a97840aa06e24ae31c12fcfbae084e -R 22fdd5c799c9a709871f8decba5b6ac4 +P b777b1097dcf9dfeb1b86c71e1b5f6918d68c975 +R 1aa8d10751da8bc78a75655bc8318da4 U drh -Z 00ce9a3b8547724477b5f04e4eb4057d +Z 0a42be2e93f4ddc55a00a5d0e3551610 diff --git a/manifest.uuid b/manifest.uuid index 06a0d20b6c..3db045bf33 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b777b1097dcf9dfeb1b86c71e1b5f6918d68c975 \ No newline at end of file +f1cac24f06b9c71cfa472fdcf2da4cd8689a7cc3 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index c1a27ebf84..4e834ffe8e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1596,15 +1596,15 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ /* Could not found an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. */ - double savedNQueryLoop = pParse->nQueryLoop; + u32 savedNQueryLoop = pParse->nQueryLoop; int rMayHaveNull = 0; eType = IN_INDEX_EPH; if( prNotFound ){ *prNotFound = rMayHaveNull = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); }else{ - testcase( pParse->nQueryLoop>(double)1 ); - pParse->nQueryLoop = (double)1; + testcase( pParse->nQueryLoop>1 ); + pParse->nQueryLoop = 1; if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } diff --git a/src/prepare.c b/src/prepare.c index d78d83cbd8..319bb5012e 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -592,7 +592,7 @@ static int sqlite3Prepare( sqlite3VtabUnlockList(db); pParse->db = db; - pParse->nQueryLoop = (double)1; + pParse->nQueryLoop = 1; if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -614,7 +614,7 @@ static int sqlite3Prepare( }else{ sqlite3RunParser(pParse, zSql, &zErrMsg); } - assert( 1==(int)pParse->nQueryLoop ); + assert( 1==pParse->nQueryLoop ); if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index aa1ea51011..d3d6fcf70a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2226,7 +2226,7 @@ struct Parse { /* Information used while coding trigger programs. */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - u32 nQueryLoop; /* Estimated number of iterations of a query */ + u32 grep nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ diff --git a/src/where.c b/src/where.c index 330faf771c..d493dba46f 100644 --- a/src/where.c +++ b/src/where.c @@ -358,7 +358,7 @@ struct WhereInfo { WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereLoop *pLoops; /* List of all WhereLoop objects */ - WhereCost savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ + int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ WhereCost nRowOut; /* Estimated number of output rows */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; @@ -3099,7 +3099,7 @@ static void explainOneScan( }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); - if( flags&WHERE_COLUMN_EQ ){ + if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowidpBest - && pTabList->nSrc>1 +// && pTabList->nSrc>1 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->viaCoroutine && !pSrc->notIndexed @@ -5074,7 +5074,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ } /* Seed the search with a single WherePath containing zero WhereLoops */ - aFrom[0].nRow = 0; + aFrom[0].nRow = pWInfo->pParse->nQueryLoop; nFrom = 1; /* Precompute the cost of sorting the final result set, if the caller @@ -5615,6 +5615,7 @@ WhereInfo *sqlite3WhereBegin( } #endif WHERETRACE(("*** Optimizer Finished ***\n")); + pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; #if 0 /* FIXME: Add this back in? */ /* If the caller is an UPDATE or DELETE statement that is requesting From 5f0b33c2cb4724cb40e8c693bbf5fec084b596b8 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 11 Jun 2013 14:22:11 +0000 Subject: [PATCH 107/144] Add the SQLITE_FTS3_MAX_EXPR_DEPTH compile time option. FossilOrigin-Name: 24fc9d4438a5615dd20af5419456166df83a72ea --- ext/fts3/fts3Int.h | 12 ++++++++++++ ext/fts3/fts3_expr.c | 10 +++++----- manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index b19064cd3b..5d1706c927 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -39,6 +39,18 @@ extern const sqlite3_api_routines *sqlite3_api; #include "fts3_tokenizer.h" #include "fts3_hash.h" +/* +** This constant determines the maximum depth of an FTS expression tree +** that the library will create and use. FTS uses recursion to perform +** various operations on the query tree, so the disadvantage of a large +** limit is that it may allow very large queries to use large amounts +** of stack space (perhaps causing a stack overflow). +*/ +#ifndef SQLITE_FTS3_MAX_EXPR_DEPTH +# define SQLITE_FTS3_MAX_EXPR_DEPTH 12 +#endif + + /* ** This constant controls how often segments are merged. Once there are ** FTS3_MERGE_COUNT segments of level N, they are merged into a single diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c index c046d7d5ff..29fb2887da 100644 --- a/ext/fts3/fts3_expr.c +++ b/ext/fts3/fts3_expr.c @@ -1000,17 +1000,16 @@ int sqlite3Fts3ExprParse( Fts3Expr **ppExpr, /* OUT: Parsed query structure */ char **pzErr /* OUT: Error message (sqlite3_malloc) */ ){ - static const int MAX_EXPR_DEPTH = 12; int rc = fts3ExprParseUnbalanced( pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr ); /* Rebalance the expression. And check that its depth does not exceed - ** MAX_EXPR_DEPTH. */ + ** SQLITE_FTS3_MAX_EXPR_DEPTH. */ if( rc==SQLITE_OK && *ppExpr ){ - rc = fts3ExprBalance(ppExpr, MAX_EXPR_DEPTH); + rc = fts3ExprBalance(ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); if( rc==SQLITE_OK ){ - rc = fts3ExprCheckDepth(*ppExpr, MAX_EXPR_DEPTH); + rc = fts3ExprCheckDepth(*ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); } } @@ -1019,7 +1018,8 @@ int sqlite3Fts3ExprParse( *ppExpr = 0; if( rc==SQLITE_TOOBIG ){ *pzErr = sqlite3_mprintf( - "FTS expression tree is too large (maximum depth %d)", MAX_EXPR_DEPTH + "FTS expression tree is too large (maximum depth %d)", + SQLITE_FTS3_MAX_EXPR_DEPTH ); rc = SQLITE_ERROR; }else if( rc==SQLITE_ERROR ){ diff --git a/manifest b/manifest index 69da1f7a96..dbb20a50de 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\smemory\sleak\sin\sCREATE\sTABLE\sthat\soccurs\sif\sthere\sare\stwo\sor\smore\nCOLLATE\sclauses\son\sthe\ssame\scolumn. -D 2013-06-09T20:22:41.259 +C Add\sthe\sSQLITE_FTS3_MAX_EXPR_DEPTH\scompile\stime\soption. +D 2013-06-11T14:22:11.456 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -80,9 +80,9 @@ F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d F ext/fts3/fts3.c 931b3c83abdd1ab3bb389b2130431c2a9ff73b91 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h 0b167bed9e63151635620a4f639bc62ac6012cba +F ext/fts3/fts3Int.h cb4df04cf886d9920a71df9e8faaa5aae2fa48c6 F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd -F ext/fts3/fts3_expr.c 193d6fc156d744ab548a2ed06c31869e54dac739 +F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d5bc1fe1c461bdb3d889ab2e50feb944881822a4 0a60212c9c8404ee079985a58094ed2b2b554d48 -R 866dc59c759cbc65061f28ee32001d2c -U drh -Z 8263ab0aca3a813bb75c33a7d2fdca4d +P 7e3820e5b989426c64af46f6bf862b91366ae954 +R 5f94a46cd24d5603b852ca86ea7eaf5a +U dan +Z 30f6897d1a48f4a9b1a79c1749e033ce diff --git a/manifest.uuid b/manifest.uuid index c82f3e71cd..87e2685a16 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7e3820e5b989426c64af46f6bf862b91366ae954 \ No newline at end of file +24fc9d4438a5615dd20af5419456166df83a72ea \ No newline at end of file From 4f402f26b15902d22f13df5e77cfdc4d8a5622cb Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 11 Jun 2013 18:59:38 +0000 Subject: [PATCH 108/144] Improved processing of DISTINCT. FossilOrigin-Name: ba897100fed291d2025f68d09334f9985312298b --- ext/misc/fuzzer.c | 6 +-- manifest | 16 +++--- manifest.uuid | 2 +- src/sqliteInt.h | 6 ++- src/where.c | 126 ++++++++++++++++++++++++++++++---------------- 5 files changed, 100 insertions(+), 56 deletions(-) diff --git a/ext/misc/fuzzer.c b/ext/misc/fuzzer.c index 023bdb1d09..fe41cda8c2 100644 --- a/ext/misc/fuzzer.c +++ b/ext/misc/fuzzer.c @@ -1079,7 +1079,7 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int seenMatch = 0; const struct sqlite3_index_constraint *pConstraint; - double rCost = 100000; + double rCost = 1e12; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ @@ -1095,7 +1095,7 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ iPlan |= 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; - rCost /= 1000000.0; + rCost /= 1e6; } if( (iPlan & 2)==0 && pConstraint->iColumn==1 @@ -1132,7 +1132,7 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ){ pIdxInfo->orderByConsumed = 1; } - if( seenMatch && (iPlan&1)==0 ) rCost *= 1e30; + if( seenMatch && (iPlan&1)==0 ) rCost = 1e99; pIdxInfo->estimatedCost = rCost; return SQLITE_OK; diff --git a/manifest b/manifest index 9e3a53b7f0..bdcdfbf749 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sParse.nQueryLoop\sstate\svariable\sto\swork\swith\sNGQP. -D 2013-06-11T13:30:04.431 +C Improved\sprocessing\sof\sDISTINCT. +D 2013-06-11T18:59:38.240 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -108,7 +108,7 @@ F ext/icu/icu.c 7538f98eab2854cf17fa5f7797bffa6c76e3863b F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c eae8454cd9dcb287b2a3ec2e65a865a4ac5f0d06 F ext/misc/closure.c 997c20ddf35f85ab399f4a02a557a9baa822ec32 -F ext/misc/fuzzer.c 79ac20b68794dfe03626f3a31681e6c240583052 +F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556 F ext/misc/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e F ext/misc/percentile.c 4fb5e46c4312b0be74e8e497ac18f805f0e3e6c5 @@ -220,7 +220,7 @@ F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h f2e51444e15f7dd35c1ee139f95f43b0bccf3fb5 +F src/sqliteInt.h 026a52f3e24c15603fddb78025e786b96c4c0d2c F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 572357246bee5389751427c670cb0222fe36be78 +F src/where.c 2afa8f1a71dd088b137a7772f5c5dfee70c8fbe8 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b777b1097dcf9dfeb1b86c71e1b5f6918d68c975 -R 1aa8d10751da8bc78a75655bc8318da4 +P f1cac24f06b9c71cfa472fdcf2da4cd8689a7cc3 +R f41c25fe4af487f857bb0cfd93c46d44 U drh -Z 0a42be2e93f4ddc55a00a5d0e3551610 +Z 15fc6bc86393280f1819e7074b4ff66c diff --git a/manifest.uuid b/manifest.uuid index 3db045bf33..64bfde3e8b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f1cac24f06b9c71cfa472fdcf2da4cd8689a7cc3 \ No newline at end of file +ba897100fed291d2025f68d09334f9985312298b \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d3d6fcf70a..b22689462c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1967,8 +1967,10 @@ struct SrcList { #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ +#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ -/* Allowed values for WhereInfo.eDistinct and DistinctCtx.eTnctType */ +/* Allowed return values from sqlite3WhereIsDistinct() +*/ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ #define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */ @@ -2226,7 +2228,7 @@ struct Parse { /* Information used while coding trigger programs. */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - u32 grep nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ + u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ diff --git a/src/where.c b/src/where.c index d493dba46f..c21f3fc494 100644 --- a/src/where.c +++ b/src/where.c @@ -345,9 +345,11 @@ struct WhereInfo { SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pDistinct; /* DISTINCT ON values, or NULL */ + WhereLoop *pLoops; /* List of all WhereLoop objects */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ - u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */ + WhereCost nRowOut; /* Estimated number of output rows */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ + u8 bOBSat; /* ORDER BY satisfied by indices */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ @@ -355,11 +357,9 @@ struct WhereInfo { int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ int nLevel; /* Number of nested loop */ + int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereClause sWC; /* Decomposition of the WHERE clause */ - WhereLoop *pLoops; /* List of all WhereLoop objects */ - int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ - WhereCost nRowOut; /* Estimated number of output rows */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; @@ -441,7 +441,7 @@ int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ ** Return FALSE if the output needs to be sorted. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ - return pWInfo->nOBSat>0; + return pWInfo->bOBSat!=0; } /* @@ -1776,15 +1776,16 @@ static int findIndexCol( /* ** Return true if the DISTINCT expression-list passed as the third argument -** is redundant. A DISTINCT list is redundant if the database contains a -** UNIQUE index that guarantees that the result of the query will be distinct -** anyway. +** is redundant. +** +** A DISTINCT list is redundant if the database contains some set of +** columns that are unique and non-null. */ static int isDistinctRedundant( - Parse *pParse, - SrcList *pTabList, - WhereClause *pWC, - ExprList *pDistinct + Parse *pParse, /* Parsing context */ + SrcList *pTabList, /* The FROM clause */ + WhereClause *pWC, /* The WHERE clause */ + ExprList *pDistinct /* The result set that needs to be DISTINCT */ ){ Table *pTab; Index *pIdx; @@ -3418,7 +3419,7 @@ static Bitmask codeOneLoopStart( ** this requires some special handling. */ if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 - && (pWInfo->nOBSat>0) + && (pWInfo->bOBSat!=0) && (pIdx->nColumn>nEq) ){ /* assert( pOrderBy->nExpr==1 ); */ @@ -4493,7 +4494,9 @@ static int whereLoopAddBtree( ){ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; - pNew->rRun = whereCostAdd(rSize,rLogSize) + ((m==0 && b) ? 10 : 0); + pNew->rRun = whereCostAdd(rSize,rLogSize); + if( m!=0 ) pNew->rRun += rLogSize; + if( b ) pNew->rRun--; rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; } @@ -4804,11 +4807,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ */ static int wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ + ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ - int nLoop, /* Number of entries in pPath->aLoop[] */ - int isLastLoop, /* True if pLast is the inner-most loop */ + u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */ + u16 nLoop, /* Number of entries in pPath->aLoop[] */ + u8 isLastLoop, /* True if pLast is the inner-most loop */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ - Bitmask *pRevMask /* Mask of WhereLoops to run in reverse order */ + Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ ){ u8 revSet; /* True if rev is known */ u8 rev; /* Composite sort order */ @@ -4823,7 +4828,6 @@ static int wherePathSatisfiesOrderBy( int iCur; /* Cursor number for current WhereLoop */ int iColumn; /* A column number within table iCur */ WhereLoop *pLoop; /* Current WhereLoop being processed. */ - ExprList *pOrderBy = pWInfo->pOrderBy; /* the ORDER BY clause */ WhereTerm *pTerm; /* A single term of the WHERE clause */ Expr *pOBExpr; /* An expression from the ORDER BY clause */ CollSeq *pColl; /* COLLATE function from an ORDER BY clause term */ @@ -4960,7 +4964,7 @@ static int wherePathSatisfiesOrderBy( for(i=0; bOnce && ia[i].pExpr); - if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ) bOnce = 0; + if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; @@ -5111,8 +5115,9 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ rCost = whereCostAdd(rCost, pFrom->rCost); maskNew = pFrom->maskLoop | pWLoop->maskSelf; if( !isOrderedValid ){ - switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, iLoop==nLoop-1, - pWLoop, &revMask) ){ + switch( wherePathSatisfiesOrderBy(pWInfo, + pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, + iLoop, iLoop==nLoop-1, pWLoop, &revMask) ){ case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ isOrdered = 1; isOrderedValid = 1; @@ -5249,9 +5254,22 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ pLevel->iFrom = pWLoop->iTab; /* FIXME: Omit the iFrom field */ pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; } + if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0 + && pWInfo->pDistinct + && nRowEst + ){ + Bitmask notUsed; + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pDistinct, pFrom, + WHERE_DISTINCTBY, nLoop-1, 1, pFrom->aLoop[nLoop-1], ¬Used); + if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; + } if( pFrom->isOrdered ){ - pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; - pWInfo->revMask = pFrom->revLoop; + if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ + pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; + }else{ + pWInfo->bOBSat = 1; + pWInfo->revMask = pFrom->revLoop; + } } pWInfo->nRowOut = pFrom->nRow; @@ -5327,7 +5345,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; - pWInfo->nOBSat = pWInfo->pOrderBy ? pWInfo->pOrderBy->nExpr : 0; + if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1; + if( pWInfo->pDistinct ) pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; #ifdef SQLITE_DEBUG pLoop->cId = '0'; #endif @@ -5414,15 +5433,6 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ** pOrderBy is a pointer to the ORDER BY clause of a SELECT statement, ** if there is one. If there is no ORDER BY clause or if this routine ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. -** -** If an index can be used so that the natural output order of the table -** scan is correct for the ORDER BY clause, then that index is used and -** the returned WhereInfo.nOBSat field is set to pOrderBy->nExpr. This -** is an optimization that prevents an unnecessary sort of the result set -** if an index appropriate for the ORDER BY clause already exists. -** -** If the where clause loops cannot be arranged to provide the correct -** output order, then WhereInfo.nOBSat is 0. */ WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ @@ -5558,13 +5568,32 @@ WhereInfo *sqlite3WhereBegin( goto whereBeginError; } + /* If the ORDER BY (or GROUP BY) clause contains references to general + ** expressions, then we won't be able to satisfy it using indices, so + ** go ahead and disable it now. + */ + if( pOrderBy ){ + for(ii=0; iinExpr; ii++){ + Expr *pExpr = sqlite3ExprSkipCollate(pOrderBy->a[ii].pExpr); + if( pExpr->op!=TK_COLUMN ){ + pWInfo->pOrderBy = pOrderBy = 0; + break; + } + } + } + /* Check if the DISTINCT qualifier, if there is one, is redundant. ** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to ** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT. */ - if( pDistinct && isDistinctRedundant(pParse,pTabList,&pWInfo->sWC,pDistinct) ){ - pDistinct = 0; - pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + if( pDistinct ){ + if( isDistinctRedundant(pParse,pTabList,&pWInfo->sWC,pDistinct) ){ + pDistinct = 0; + pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + }else if( pOrderBy==0 ){ + pWInfo->wctrlFlags |= WHERE_DISTINCTBY; + pWInfo->pOrderBy = pDistinct; + } } /* Construct the WhereLoop objects */ @@ -5587,7 +5616,7 @@ WhereInfo *sqlite3WhereBegin( } #endif - wherePathSolver(pWInfo, -1); + wherePathSolver(pWInfo, 0); if( db->mallocFailed ) goto whereBeginError; if( pWInfo->pOrderBy ){ wherePathSolver(pWInfo, pWInfo->nRowOut); @@ -5603,12 +5632,25 @@ WhereInfo *sqlite3WhereBegin( #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ int ii; - sqlite3DebugPrintf("---- Solution"); - if( pWInfo->nOBSat ){ - sqlite3DebugPrintf(" ORDER BY omitted rev=0x%llx\n", pWInfo->revMask); - }else{ - sqlite3DebugPrintf("\n"); + sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); + if( pWInfo->bOBSat ){ + sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask); } + switch( pWInfo->eDistinct ){ + case WHERE_DISTINCT_UNIQUE: { + sqlite3DebugPrintf(" DISTINCT=unique"); + break; + } + case WHERE_DISTINCT_ORDERED: { + sqlite3DebugPrintf(" DISTINCT=ordered"); + break; + } + case WHERE_DISTINCT_UNORDERED: { + sqlite3DebugPrintf(" DISTINCT=unordered"); + break; + } + } + sqlite3DebugPrintf("\n"); for(ii=0; iia[ii].pWLoop, pTabList); } From e217efc82218d232320402bdc13c05058058d9b2 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Jun 2013 03:48:41 +0000 Subject: [PATCH 109/144] Continue refining the NGQP FossilOrigin-Name: 40567fddd468d00295275af8df09a7a1785e684a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index bdcdfbf749..0f0b79ba59 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sprocessing\sof\sDISTINCT. -D 2013-06-11T18:59:38.240 +C Continue\srefining\sthe\sNGQP +D 2013-06-12T03:48:41.127 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 2afa8f1a71dd088b137a7772f5c5dfee70c8fbe8 +F src/where.c 3f38f769ef1365d7c8ff5b0ae9341b32f49bf46e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P f1cac24f06b9c71cfa472fdcf2da4cd8689a7cc3 -R f41c25fe4af487f857bb0cfd93c46d44 +P ba897100fed291d2025f68d09334f9985312298b +R 5ed376a4396f55c99b307b2ce75a8d86 U drh -Z 15fc6bc86393280f1819e7074b4ff66c +Z 47a7a33cc642ca844caf03a37d1ebaba diff --git a/manifest.uuid b/manifest.uuid index 64bfde3e8b..d84595d4b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba897100fed291d2025f68d09334f9985312298b \ No newline at end of file +40567fddd468d00295275af8df09a7a1785e684a \ No newline at end of file diff --git a/src/where.c b/src/where.c index c21f3fc494..059c2c1015 100644 --- a/src/where.c +++ b/src/where.c @@ -74,7 +74,7 @@ struct WhereLevel { int addrNxt; /* Jump here to start the next IN combination */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ - u8 iFrom; /* FIXME: Which entry in the FROM clause */ + u8 iFrom; /* Which entry in the FROM clause */ u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to ends the loop */ union { /* Information that depends on plan.wsFlags */ @@ -4248,7 +4248,7 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */ - nIn = 46; /* whereCostFromInt(25) */ + nIn = 46; assert( 46==whereCostFromInt(25) ); }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nIn = whereCostFromInt(pExpr->x.pList->nExpr); @@ -4272,7 +4272,7 @@ static int whereLoopAddBtreeIndex( }else if( pTerm->eOperator & (WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_NULL; pNew->u.btree.nEq++; - nIn = 10; /* Assume IS NULL matches two rows */ + nIn = 10; assert( 10==whereCostFromInt(2) ); pNew->nOut = nRowEst + nInMul + nIn; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; @@ -4303,15 +4303,13 @@ static int whereLoopAddBtreeIndex( pNew->nOut = whereCostFromInt(nOut); } #endif - if( pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK) ){ - /* Step cost for each output row */ - pNew->rRun = whereCostAdd(pNew->rRun, pNew->nOut); - }else{ + if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ /* Each row involves a step of the index, then a binary search of ** the main table */ - WhereCost rStepAndSearch = whereCostAdd(10, rLogSize>17 ? rLogSize-17 : 1); - pNew->rRun = whereCostAdd(pNew->rRun, rStepAndSearch); + pNew->rRun = whereCostAdd(pNew->rRun, rLogSize>27 ? rLogSize-17 : 10); } + /* Step cost for each output row */ + pNew->rRun = whereCostAdd(pNew->rRun, pNew->nOut); /* TBD: Adjust nOut for additional constraints */ rc = whereLoopInsert(pBuilder, pNew); if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 @@ -5251,7 +5249,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ for(iLoop=0; iLoopa + iLoop; pLevel->pWLoop = pWLoop = pFrom->aLoop[iLoop]; - pLevel->iFrom = pWLoop->iTab; /* FIXME: Omit the iFrom field */ + pLevel->iFrom = pWLoop->iTab; pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; } if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0 @@ -5572,12 +5570,14 @@ WhereInfo *sqlite3WhereBegin( ** expressions, then we won't be able to satisfy it using indices, so ** go ahead and disable it now. */ - if( pOrderBy ){ + if( pOrderBy && pDistinct ){ for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollate(pOrderBy->a[ii].pExpr); if( pExpr->op!=TK_COLUMN ){ pWInfo->pOrderBy = pOrderBy = 0; break; + }else if( pExpr->iColumn<0 ){ + break; } } } From fd5874d23dce6e96aba056485b328e3801b69270 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Jun 2013 14:52:39 +0000 Subject: [PATCH 110/144] Add the "queryplanner" test permutation. Continuing refinements to NGQP. FossilOrigin-Name: 25e2cde105a19293bdb9c001b48624e5d7f8c4e5 --- manifest | 20 +++++------ manifest.uuid | 2 +- src/where.c | 34 +++++++++---------- test/permutations.test | 77 ++++++++++++++++++++++++++++++++++++++++++ test/where8.test | 2 +- test/where9.test | 36 ++++++++++++++------ test/whereF.test | 8 ++--- 7 files changed, 136 insertions(+), 43 deletions(-) diff --git a/manifest b/manifest index 0f0b79ba59..2445afe8f0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Continue\srefining\sthe\sNGQP -D 2013-06-12T03:48:41.127 +C Add\sthe\s"queryplanner"\stest\spermutation.\s\sContinuing\srefinements\sto\sNGQP. +D 2013-06-12T14:52:39.194 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 3f38f769ef1365d7c8ff5b0ae9341b32f49bf46e +F src/where.c 67d70ce776aae6e81eddc182357bd5542dc9e023 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -707,7 +707,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test 4614301e38398df7fdd5f28f4ed8f272b328251b -F test/permutations.test d997a947ab8aabb15f763d50a030b3c11e8ef1b6 +F test/permutations.test 2ab3937fdd34e18712be8f4159ac354c4d27ce1d F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 @@ -1036,15 +1036,15 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where7.test e0741d85b6069effe53c6ed7682e18aa078f4b11 -F test/where8.test d6a283eb7348a8967d44e2a753f117ab0d21d4f3 +F test/where8.test f6b9559723564a042927ee0f22003ac9bed71b21 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 -F test/where9.test 4094299aea1c5a1ebe172ad832c2467cba23133a +F test/where9.test f5752185fc19a1ee826a2386a249f05dbc25979b F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62 F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f -F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9 +F test/whereF.test 136a7301512d72a08a272806c8767066311b7bc1 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ba897100fed291d2025f68d09334f9985312298b -R 5ed376a4396f55c99b307b2ce75a8d86 +P 40567fddd468d00295275af8df09a7a1785e684a +R 8ad423cc8976bc762dc67ac33e49e948 U drh -Z 47a7a33cc642ca844caf03a37d1ebaba +Z 7a74b3f46b1e20d0df5f0a7a123b8d69 diff --git a/manifest.uuid b/manifest.uuid index d84595d4b9..943b9de7f4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -40567fddd468d00295275af8df09a7a1785e684a \ No newline at end of file +25e2cde105a19293bdb9c001b48624e5d7f8c4e5 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 059c2c1015..06470f6fa4 100644 --- a/src/where.c +++ b/src/where.c @@ -604,7 +604,7 @@ static void whereSplit(WhereClause *pWC, Expr *pExpr, int op){ /* ** Initialize an expression mask set (a WhereMaskSet object) */ -#define initMaskSet(P) memset(P, 0, sizeof(*P)) +#define initMaskSet(P) (P)->n=0 /* ** Return the bitmask for the given cursor number. Return 0 if @@ -4361,7 +4361,7 @@ static int indexMightHelpWithOrderBy( ** Return a bitmask where 1s indicate that the corresponding column of ** the table is used by an index. Only the first 63 columns are considered. */ -static Bitmask columnsUsedByIndex(Index *pIdx){ +static Bitmask columnsInIndex(Index *pIdx){ Bitmask m = 0; int j; for(j=pIdx->nColumn-1; j>=0; j--){ @@ -4431,7 +4431,6 @@ static int whereLoopAddBtree( /* Automatic indexes */ if( !pBuilder->pBest -// && pTabList->nSrc>1 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->viaCoroutine && !pSrc->notIndexed @@ -4476,11 +4475,11 @@ static int whereLoopAddBtree( /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; - pNew->rRun = whereCostAdd(rSize,rLogSize) + 16 + b*4; + pNew->rRun = whereCostAdd(rSize,rLogSize) + 16 - b; rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; }else{ - Bitmask m = pSrc->colUsed & ~columnsUsedByIndex(pProbe); + Bitmask m = pSrc->colUsed & ~columnsInIndex(pProbe); pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; /* Full scan via index */ @@ -4493,8 +4492,7 @@ static int whereLoopAddBtree( pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; pNew->rRun = whereCostAdd(rSize,rLogSize); - if( m!=0 ) pNew->rRun += rLogSize; - if( b ) pNew->rRun--; + pNew->rRun += ((m!=0) ? rLogSize : 10) - b; rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; } @@ -4737,15 +4735,17 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ prereq |= sBest.prereq; } assert( pNew->nLSlot>=1 ); - pNew->nLTerm = 1; - pNew->aLTerm[0] = pTerm; - pNew->wsFlags = WHERE_MULTI_OR; - pNew->rSetup = 0; - pNew->rRun = rTotal; - pNew->nOut = nRow; - pNew->prereq = prereq; - memset(&pNew->u, 0, sizeof(pNew->u)); - rc = whereLoopInsert(pBuilder, pNew); + if( sBest.maskSelf ){ + pNew->nLTerm = 1; + pNew->aLTerm[0] = pTerm; + pNew->wsFlags = WHERE_MULTI_OR; + pNew->rSetup = 0; + pNew->rRun = rTotal; + pNew->nOut = nRow; + pNew->prereq = prereq; + memset(&pNew->u, 0, sizeof(pNew->u)); + rc = whereLoopInsert(pBuilder, pNew); + } whereLoopClear(pWInfo->pParse->db, &sBest); } } @@ -5327,7 +5327,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ } if( j!=pIdx->nColumn ) continue; pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; - if( (pItem->colUsed & ~columnsUsedByIndex(pIdx))==0 ){ + if( (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){ pLoop->wsFlags |= WHERE_IDX_ONLY; } pLoop->nLTerm = j; diff --git a/test/permutations.test b/test/permutations.test index bc3ceb8085..7b633019ae 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -213,6 +213,83 @@ test_suite "nofaultsim" -prefix "" -description { unset -nocomplain ::G(valgrind) } +test_suite "queryplanner" -prefix "" -description { + Tests of the query planner and query optimizer +} -files { + alter2.test alter3.test alter4.test alter.test analyze3.test + analyze4.test analyze5.test analyze6.test analyze7.test analyze8.test + analyze.test attach2.test attach3.test attach4.test attachmalloc.test + attach.test autoinc.test autoindex1.test between.test cast.test + check.test closure01.test coalesce.test collate1.test collate2.test + collate3.test collate4.test collate5.test collate6.test collate7.test + collate8.test collate9.test collateA.test colmeta.test colname.test + conflict.test count.test coveridxscan.test createtab.test cse.test + date.test dbstatus2.test dbstatus.test default.test delete2.test + delete3.test delete.test descidx1.test descidx2.test descidx3.test + distinctagg.test distinct.test e_createtable.test e_delete.test + e_droptrigger.test e_dropview.test e_expr.test e_fkey.test e_insert.test + eqp.test e_reindex.test e_resolve.test e_select2.test e_select.test + e_update.test exists.test expr.test fkey1.test fkey2.test fkey3.test + fkey4.test fkey5.test fkey_malloc.test format4.test func2.test + func3.test func.test fuzz2.test fuzz3.test fuzzer1.test fuzz-oss1.test + fuzz.test in2.test in3.test in4.test in5.test index2.test index3.test + index4.test index5.test indexedby.test indexfault.test index.test + insert2.test insert3.test insert4.test insert5.test insert.test + instr.test in.test intpkey.test join2.test join3.test join4.test + join5.test join6.test join.test like2.test like.test limit.test + minmax2.test minmax3.test minmax4.test minmax.test misc1.test misc2.test + misc3.test misc4.test misc5.test misc6.test misc7.test orderby1.test + orderby2.test orderby3.test orderby4.test randexpr1.test regexp1.test + reindex.test rowhash.test rowid.test schema2.test schema3.test + schema4.test schema5.test schema.test securedel2.test securedel.test + select1.test select2.test select3.test select4.test select5.test + select6.test select7.test select8.test select9.test selectA.test + selectB.test selectC.test selectD.test selectE.test sidedelete.test + sort.test spellfix.test subquery2.test subquery.test subselect.test + substr.test tkt-02a8e81d44.test tkt1435.test tkt1443.test tkt1444.test + tkt1449.test tkt1473.test tkt1501.test tkt1512.test tkt1514.test + tkt1536.test tkt1537.test tkt1567.test tkt1644.test tkt1667.test + tkt1873.test tkt2141.test tkt2192.test tkt2213.test tkt2251.test + tkt2285.test tkt2332.test tkt2339.test tkt2391.test tkt2409.test + tkt2450.test tkt2565.test tkt2640.test tkt2643.test tkt2686.test + tkt-26ff0c2d1e.test tkt2767.test tkt2817.test tkt2820.test tkt2822.test + tkt2832.test tkt2854.test tkt2920.test tkt2927.test tkt2942.test + tkt-2a5629202f.test tkt-2d1a5c67d.test tkt-2ea2425d34.test tkt3080.test + tkt3093.test tkt3121.test tkt-31338dca7e.test tkt-313723c356.test + tkt3201.test tkt3292.test tkt3298.test tkt3334.test tkt3346.test + tkt3357.test tkt3419.test tkt3424.test tkt3442.test tkt3457.test + tkt3461.test tkt3493.test tkt3508.test tkt3522.test tkt3527.test + tkt3541.test tkt3554.test tkt3581.test tkt35xx.test tkt3630.test + tkt3718.test tkt3731.test tkt3757.test tkt3761.test tkt3762.test + tkt3773.test tkt3791.test tkt3793.test tkt3810.test tkt3824.test + tkt3832.test tkt3838.test tkt3841.test tkt-385a5b56b9.test tkt3871.test + tkt3879.test tkt-38cb5df375.test tkt3911.test tkt3918.test tkt3922.test + tkt3929.test tkt3935.test tkt3992.test tkt3997.test tkt-3998683a16.test + tkt-3a77c9714e.test tkt-3fe897352e.test tkt4018.test tkt-4a03edc4c8.test + tkt-4dd95f6943.test tkt-54844eea3f.test tkt-5d863f876e.test + tkt-5e10420e8d.test tkt-5ee23731f.test tkt-6bfb98dfc0.test + tkt-752e1646fc.test tkt-78e04e52ea.test tkt-7a31705a7e6.test + tkt-7bbfb7d442.test tkt-80ba201079.test tkt-80e031a00f.test + tkt-8454a207b9.test tkt-91e2e8ba6f.test tkt-94c04eaadb.test + tkt-9d68c883.test tkt-a7b7803e.test tkt-b1d3a2e531.test + tkt-b351d95f9.test tkt-b72787b1.test tkt-bd484a090c.test + tkt-bdc6bbbb38.test tkt-c48d99d690.test tkt-cbd054fa6b.test + tkt-d11f09d36e.test tkt-d635236375.test tkt-d82e3f3721.test + tkt-f3e5abed55.test tkt-f777251dc7a.test tkt-f7b4edec.test + tkt-f973c7ac31.test tkt-fa7bf5ec.test tkt-fc62af4523.test + tkt-fc7bd6358f.test trigger1.test trigger2.test trigger3.test + trigger4.test trigger5.test trigger6.test trigger7.test trigger8.test + trigger9.test triggerA.test triggerB.test triggerC.test triggerD.test + types2.test types3.test types.test unique.test unordered.test + update.test view.test vtab1.test vtab2.test vtab3.test vtab4.test + vtab5.test vtab6.test vtab7.test vtab8.test vtab9.test vtab_alter.test + vtabA.test vtabB.test vtabC.test vtabD.test vtab_err.test vtabE.test + vtabF.test where2.test where3.test where4.test where5.test where6.test + where7.test where8m.test where8.test where9.test whereA.test whereB.test + whereC.test whereD.test whereE.test whereF.test wherelimit.test + where.test +} + lappend ::testsuitelist xxx #------------------------------------------------------------------------- # Define the coverage related test suites: diff --git a/test/where8.test b/test/where8.test index 9b6014e708..6890e3ac59 100644 --- a/test/where8.test +++ b/test/where8.test @@ -268,7 +268,7 @@ do_test where8-3.12 { execsql_status { SELECT a, d FROM t1, t2 WHERE (a=d OR b=e) AND +a<5 ORDER BY a } -} {1 1 2 2 3 3 4 2 4 4 0 0} +} {1 1 2 2 3 3 4 2 4 4 9 0} do_test where8-3.13 { execsql_status { SELECT a, d FROM t1, t2 WHERE (a=d OR b=e) AND +a<5 diff --git a/test/where9.test b/test/where9.test index d6a8c597b4..4ffcad1470 100644 --- a/test/where9.test +++ b/test/where9.test @@ -420,7 +420,7 @@ do_test where9-4.5 { AND (c=31031 OR d IS NULL) ORDER BY +a } -} {1 {cannot use index: t1b}} +} {1 {no query solution}} do_test where9-4.6 { count_steps { SELECT a FROM t1 NOT INDEXED @@ -436,7 +436,7 @@ do_test where9-4.7 { AND (c=31031 OR d IS NULL) ORDER BY +a } -} {1 {cannot use index: t1c}} +} {1 {no query solution}} do_test where9-4.8 { catchsql { SELECT a FROM t1 INDEXED BY t1d @@ -444,7 +444,7 @@ do_test where9-4.8 { AND (c=31031 OR d IS NULL) ORDER BY +a } -} {1 {cannot use index: t1d}} +} {1 {no query solution}} ifcapable explain { # The (c=31031 OR d IS NULL) clause is preferred over b>1000 because @@ -598,7 +598,7 @@ do_test where9-6.3.5 { OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 98 sort 0} ;# DELETEs rows 90 91 92 97 +} {scan 0 sort 0} ;# DELETEs rows 90 91 92 97 do_test where9-6.3.6 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -615,7 +615,7 @@ do_test where9-6.3.7 { OR (b NOT NULL AND +c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 98 sort 0} ;# Add 100 to rowids 90 91 92 97 +} {scan 0 sort 0} ;# Add 100 to rowids 90 91 92 97 do_test where9-6.3.8 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -705,7 +705,7 @@ do_test where9-6.6.1 { OR (b NOT NULL AND +c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 98 sort 0} ;# DELETEs rows 90 91 92 97 +} {scan 0 sort 0} ;# DELETEs rows 90 91 92 97 do_test where9-6.6.2 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -722,7 +722,7 @@ do_test where9-6.6.3 { OR (b NOT NULL AND +c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 98 sort 0} ;# Add 100 to rowids 90 91 92 97 +} {scan 0 sort 0} ;# Add 100 to rowids 90 91 92 97 do_test where9-6.6.4 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -768,19 +768,35 @@ do_test where9-6.7.4 { do_test where9-6.8.1 { catchsql { DELETE FROM t1 INDEXED BY t1b - WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {1 {cannot use index: t1b}} +} {1 {no query solution}} do_test where9-6.8.2 { + catchsql { + UPDATE t1 INDEXED BY t1b SET a=a+100 + WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } +} {1 {no query solution}} +do_test where9-6.8.3 { catchsql { UPDATE t1 INDEXED BY t1b SET a=a+100 WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {1 {cannot use index: t1b}} +} {0 {}} +do_test where9-6.8.4 { + catchsql { + DELETE FROM t1 INDEXED BY t1b + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } +} {0 {}} ############################################################################ # Test cases where terms inside an OR series are combined with AND terms diff --git a/test/whereF.test b/test/whereF.test index 57bdbee058..c98312a262 100644 --- a/test/whereF.test +++ b/test/whereF.test @@ -46,7 +46,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -set testprefix x +set testprefix whereF do_execsql_test 1.0 { PRAGMA automatic_index = 0; @@ -63,7 +63,7 @@ foreach {tn sql} { } { do_test 1.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} + } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} } do_execsql_test 2.0 { @@ -84,7 +84,7 @@ foreach {tn sql} { } { do_test 2.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} + } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} } do_execsql_test 3.0 { @@ -109,7 +109,7 @@ foreach {tn sql} { } { do_test 3.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} + } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} } finish_test From 4fe425ad798b7d11ba0adc4078df34cca5d4c848 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Jun 2013 17:08:06 +0000 Subject: [PATCH 111/144] "make test" now passing. FossilOrigin-Name: addd7f466d6ff55f82d907286650c26b06e9397b --- manifest | 40 ++++++++++++++++++++-------------------- manifest.uuid | 2 +- src/where.c | 13 +++++++++++-- test/autoindex1.test | 2 +- test/distinct.test | 2 +- test/eqp.test | 2 +- test/indexedby.test | 22 +++++++++++----------- test/orderby1.test | 10 ++++------ test/permutations.test | 15 +++++++-------- test/tkt-2a5629202f.test | 2 +- test/unordered.test | 4 ++-- test/vtab1.test | 25 +++++++++++++------------ test/vtab6.test | 4 ++-- test/where.test | 2 +- test/where2.test | 36 ++++++++++++++++++------------------ test/where3.test | 2 ++ test/where7.test | 4 ++-- 17 files changed, 98 insertions(+), 89 deletions(-) diff --git a/manifest b/manifest index 2445afe8f0..8b92ace178 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s"queryplanner"\stest\spermutation.\s\sContinuing\srefinements\sto\sNGQP. -D 2013-06-12T14:52:39.194 +C "make\stest"\snow\spassing. +D 2013-06-12T17:08:06.018 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 67d70ce776aae6e81eddc182357bd5542dc9e023 +F src/where.c 58522e12fcb559ac138d1cf51348b6861345968e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -322,7 +322,7 @@ F test/auth.test 4a4c3b034fff7750513520defa910f376c96ab49 F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf -F test/autoindex1.test fadbdf682948e0be840a3958d1df5501cfca9d6e +F test/autoindex1.test fac4207316e4e954abd086eafdd571ef093c5f5d F test/autovacuum.test 9f22a7733f39c56ef6a5665d10145ac25d8cb574 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 @@ -419,7 +419,7 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240 F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e -F test/distinct.test 84da1414b2e6887fffd5ed571311b344c5b082ce +F test/distinct.test 44028aaf161a5e80a2f229622b3a174d3b352810 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 F test/e_createtable.test ddf3b2e4506e0813f46b69ccf55757c5570cc181 F test/e_delete.test 89aa84d3d1bd284a0689ede04bce10226a5aeaa5 @@ -440,7 +440,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020 -F test/eqp.test 68dd66c8fa05551d056ebd7fc8ae3b2e1cb5836e +F test/eqp.test 8ef4d89dc44d8988b3ea6e60902905d739508db0 F test/errmsg.test 050717f1c6a5685de9c79f5f9f6b83d7c592f73a F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75 @@ -586,7 +586,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7 F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026 F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33 -F test/indexedby.test e06e1bf5a933b53f7dbeedf45749d0d37c7067ff +F test/indexedby.test 0e959308707c808515c3a51363f7a9835027108c F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 489aa12a027c83d291f5034a83c8c32e6be1dca2 @@ -691,7 +691,7 @@ F test/notnull.test 2afad748d18fd66d01f66463de73b3e2501fb226 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 -F test/orderby1.test 3c5ff32c23364fb3d567ad53b945837736e701ce +F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6 F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99 F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4 @@ -707,7 +707,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test 4614301e38398df7fdd5f28f4ed8f272b328251b -F test/permutations.test 2ab3937fdd34e18712be8f4159ac354c4d27ce1d +F test/permutations.test 02a3c0174c943734d710ac01ca465198bff05819 F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 @@ -821,7 +821,7 @@ F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 -F test/tkt-2a5629202f.test befaa77b90426a5ca8025724279e0bc26336610e +F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 F test/tkt-2d1a5c67d.test d371279946622698ab393ff88cad9f5f6d82960b F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 6fb8807851964da0d24e942f2e19c7c705b9fb58 @@ -975,7 +975,7 @@ F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a F test/unique.test cadb172bbd5a2e83cd644d186ccd602085e54edc F test/unixexcl.test a9870e46cc6f8390a494513d4f2bf55b5a8b3e46 -F test/unordered.test 08b4ea1c273891ebc10d5e5c3a352ac5c62a6fbf +F test/unordered.test ef85ac8f2f3c93ed2b9e811b684de73175fc464c F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172 F test/uri.test 63e03df051620a18f794b4f4adcdefb3c23b6751 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae @@ -986,12 +986,12 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/view.test 4057630287bfa5955628fe90a13d4c225d1c7352 -F test/vtab1.test 4403f987860ebddef1ce2de6db7216421035339d +F test/vtab1.test 1550abf90bc2b996f8c34e0be3fdb251af54fa41 F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1 F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391 -F test/vtab6.test c7f290d172609d636fbfc58166eadcb55d5c117c +F test/vtab6.test 5f5380c425e52993560ab4763db4f826d2ba7b09 F test/vtab7.test ae560ebea870ed04e9aa4177cc302f910faaabb5 F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b @@ -1029,13 +1029,13 @@ F test/walro.test 6cc247a0cc9b36aeea2057dd28a922a1cdfbd630 F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e -F test/where.test cd13d4804b8f2986b176fb45c0a43fbbba64215a -F test/where2.test 58cc3f85c082015144bc34c7ffdbd64134f650ee -F test/where3.test f2a7027e1971d583069947edba0a31563e86284f +F test/where.test da54153a4c1571ea1b95659e5bec8119edf786aa +F test/where2.test dcf0ffafe0de55051c1373835a5a57aee6b50094 +F test/where3.test 157071521ceabc06bfd4d37106e4270a8956364d F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b -F test/where7.test e0741d85b6069effe53c6ed7682e18aa078f4b11 +F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8 F test/where8.test f6b9559723564a042927ee0f22003ac9bed71b21 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 F test/where9.test f5752185fc19a1ee826a2386a249f05dbc25979b @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 40567fddd468d00295275af8df09a7a1785e684a -R 8ad423cc8976bc762dc67ac33e49e948 +P 25e2cde105a19293bdb9c001b48624e5d7f8c4e5 +R 74299348f4ebeefec70a5406f9e251d7 U drh -Z 7a74b3f46b1e20d0df5f0a7a123b8d69 +Z ad22135d0c0bd81f6331e3b3327b23e1 diff --git a/manifest.uuid b/manifest.uuid index 943b9de7f4..16f0323d65 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -25e2cde105a19293bdb9c001b48624e5d7f8c4e5 \ No newline at end of file +addd7f466d6ff55f82d907286650c26b06e9397b \ No newline at end of file diff --git a/src/where.c b/src/where.c index 06470f6fa4..9886d4e214 100644 --- a/src/where.c +++ b/src/where.c @@ -1908,7 +1908,8 @@ static WhereCost whereCostFromDouble(double x){ ** logN is a little off. */ static WhereCost estLog(WhereCost N){ - return whereCostFromInt(N) - 33; + WhereCost x = whereCostFromInt(N); + return x>33 ? x - 33 : 0; } /* @@ -4431,7 +4432,8 @@ static int whereLoopAddBtree( /* Automatic indexes */ if( !pBuilder->pBest - && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 + && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 + && pSrc->pIndex==0 && !pSrc->viaCoroutine && !pSrc->notIndexed && !pSrc->isCorrelated @@ -5526,6 +5528,13 @@ WhereInfo *sqlite3WhereBegin( pWhere = 0; } + /* Special case: No FROM clause + */ + if( nTabList==0 ){ + if( pOrderBy ) pWInfo->bOBSat = 1; + if( pDistinct ) pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + } + /* Assign a bit from the bitmask to every term in the FROM clause. ** ** When assigning bitmask values to FROM clause cursors, it must be diff --git a/test/autoindex1.test b/test/autoindex1.test index f8ab0c9d57..9d67def05f 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -245,7 +245,7 @@ do_execsql_test autoindex1-600 { 1 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} 2 0 0 {SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date0 ORDER BY c,a LIMIT 3 } -} {1 100 4 sort} +} {1 100 4 nosort} do_test where-6.9.8 { cksort { SELECT * FROM t3 WHERE a=1 AND c>0 ORDER BY a DESC, c ASC LIMIT 3 diff --git a/test/where2.test b/test/where2.test index c55d4a12a3..e57192d85c 100644 --- a/test/where2.test +++ b/test/where2.test @@ -283,12 +283,12 @@ do_test where2-6.3 { queryplan { SELECT * FROM t1 WHERE w=99 OR w=100 OR 6=+w ORDER BY +w } -} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 {}} +} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 *} do_test where2-6.4 { queryplan { SELECT * FROM t1 WHERE w=99 OR +w=100 OR 6=w ORDER BY +w } -} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 {}} +} {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 *} set ::idx {} ifcapable subquery {set ::idx i1zyx} @@ -324,7 +324,7 @@ do_test where2-6.7 { -- SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=b; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.9 { queryplan { -- The + operator removes affinity from the rhs. No conversions @@ -332,13 +332,13 @@ do_test where2-6.9 { -- SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b; } -} {nosort t2249b {} {} sqlite_autoindex_t2249a_1} +} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.9.2 { # The same thing but with the expression flipped around. queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE +b=a } -} {nosort t2249b {} {} sqlite_autoindex_t2249a_1} +} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.10 { queryplan { -- Use + on both sides of the comparison to disable indices @@ -346,32 +346,32 @@ do_test where2-6.10 { -- SELECT * FROM t2249b CROSS JOIN t2249a WHERE +a=+b; } -} {nosort t2249b {} t2249a {}} +} {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11 { # This will not attempt the OR optimization because of the a=b # comparison. queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello'; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11.2 { # Permutations of the expression terms. queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello'; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11.3 { # Permutations of the expression terms. queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.11.4 { # Permutations of the expression terms. queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a; } -} {123 0123 nosort t2249b {} t2249a {}} +} {123 0123 nosort t2249b * t2249a sqlite_autoindex_t2249a_1} ifcapable explain&&subquery { # These tests are not run if subquery support is not included in the # build. This is because these tests test the "a = 1 OR a = 2" to @@ -385,7 +385,7 @@ ifcapable explain&&subquery { queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello'; } - } {nosort t2249b {} {} sqlite_autoindex_t2249a_1} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.12.2 { # In this case, the +b disables the affinity conflict and allows # the OR optimization to be used again. The result is now an empty @@ -393,7 +393,7 @@ ifcapable explain&&subquery { queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a; } - } {nosort t2249b {} {} sqlite_autoindex_t2249a_1} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.12.3 { # In this case, the +b disables the affinity conflict and allows # the OR optimization to be used again. The result is now an empty @@ -401,14 +401,14 @@ ifcapable explain&&subquery { queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello'; } - } {nosort t2249b {} {} sqlite_autoindex_t2249a_1} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} do_test where2-6.13 { # The addition of +a on the second term disabled the OR optimization. # But we should still get the same empty-set result as in where2-6.9. queryplan { SELECT * FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello'; } - } {nosort t2249b {} t2249a {}} + } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1} } # Variations on the order of terms in a WHERE clause in order @@ -417,7 +417,7 @@ do_test where2-6.20 { queryplan { SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a } -} {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} +} {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} ifcapable explain&&subquery { # These tests are not run if subquery support is not included in the # build. This is because these tests test the "a = 1 OR a = 2" to @@ -428,17 +428,17 @@ ifcapable explain&&subquery { queryplan { SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE x.a=y.a OR y.a='hello' } - } {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} + } {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} do_test where2-6.22 { queryplan { SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE y.a=x.a OR y.a='hello' } - } {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} + } {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} do_test where2-6.23 { queryplan { SELECT * FROM t2249a x CROSS JOIN t2249a y WHERE y.a='hello' OR x.a=y.a } - } {0123 0123 nosort x {} {} sqlite_autoindex_t2249a_1} + } {0123 0123 nosort x sqlite_autoindex_t2249a_1 y sqlite_autoindex_t2249a_1} } # Unique queries (queries that are guaranteed to return only a single diff --git a/test/where3.test b/test/where3.test index e6acafed07..a5137173f2 100644 --- a/test/where3.test +++ b/test/where3.test @@ -247,6 +247,7 @@ do_execsql_test where3-3.1 { 0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} } +if 0 { # Query planner no longer does this # Verify that when there are multiple tables in a join which must be # full table scans that the query planner attempts put the table with # the fewest number of output rows as the outer loop. @@ -278,6 +279,7 @@ do_execsql_test where3-4.2 { 0 1 1 {SCAN TABLE t401} 0 2 2 {SCAN TABLE t402} } +} ;# endif # Verify that a performance regression encountered by firefox # has been fixed. diff --git a/test/where7.test b/test/where7.test index 3cb8781200..5032c698b2 100644 --- a/test/where7.test +++ b/test/where7.test @@ -23303,7 +23303,7 @@ do_test where7-2.1001.2 { # # The test case that follows is code from an actual # application with identifiers change and unused columns -# remove. +# removed. # do_execsql_test where7-3.1 { CREATE TABLE t301 ( @@ -23332,7 +23332,7 @@ do_execsql_test where7-3.1 { EXPLAIN QUERY PLAN SELECT t302.c1 - FROM t302 JOIN t301 ON t302.c8 = t301.c8 + FROM t302 JOIN t301 ON t302.c8 = +t301.c8 WHERE t302.c2 = 19571 AND t302.c3 > 1287603136 AND (t301.c4 = 1407449685622784 From 95ed68df55bce1b194dc6dd5b94dc8ed59506854 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Jun 2013 17:55:50 +0000 Subject: [PATCH 112/144] Bug fixes in the handling of virtual tables. FossilOrigin-Name: 25c0f7292a20c0db6ef176966d9987f29c7d73e5 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 4944aabb1c..86301aff88 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sall\schanges\sfrom\strunk. -D 2013-06-12T17:17:45.907 +C Bug\sfixes\sin\sthe\shandling\sof\svirtual\stables. +D 2013-06-12T17:55:50.456 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 97f5d9c3a9dfa802d91f7723cd1d782a3ce78e7a +F src/where.c 568aef7548e2cad24f03b6099f07aa66b2fa269c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P addd7f466d6ff55f82d907286650c26b06e9397b 24fc9d4438a5615dd20af5419456166df83a72ea -R 400236daf5743c1455f090bd73116cba +P f2e15b1974e55373b5819e3b2326653f890f409f +R 6fa5c9c088caf080e0b4a5ec6cf7a456 U drh -Z eafccaa2bb28a08ba2c2409a2846f8df +Z 738850606e13a26064a82bd0faf55587 diff --git a/manifest.uuid b/manifest.uuid index 9a98bfb402..86fd19a1a4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f2e15b1974e55373b5819e3b2326653f890f409f \ No newline at end of file +25c0f7292a20c0db6ef176966d9987f29c7d73e5 \ No newline at end of file diff --git a/src/where.c b/src/where.c index abf4ebf56e..5b699a8663 100644 --- a/src/where.c +++ b/src/where.c @@ -3211,6 +3211,7 @@ static Bitmask codeOneLoopStart( for(j=0; jaLTerm[j]; + if( pTerm==0 ) continue; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); addrNotFound = pLevel->addrNxt; @@ -4704,7 +4705,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ sSubBuild.pOrderBy = 0; sSubBuild.pBest = &sBest; - for(pOrTerm=pOrWC->a; pOrTerma; rc==SQLITE_OK && pOrTermeOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; }else if( pOrTerm->leftCursor==iCur ){ From 3b48e8c91a631d35c2479087d1db944d19d72f77 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Jun 2013 20:18:16 +0000 Subject: [PATCH 113/144] Activate the one-pass optimization. Update comments, especially the descriptions of the various objects. FossilOrigin-Name: e120c558a5bafc0f0d2cc12ee5c9d36e20cc642d --- manifest | 12 ++-- manifest.uuid | 2 +- src/where.c | 178 +++++++++++++++++++++++++++----------------------- 3 files changed, 105 insertions(+), 87 deletions(-) diff --git a/manifest b/manifest index 86301aff88..b3d0bc075d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bug\sfixes\sin\sthe\shandling\sof\svirtual\stables. -D 2013-06-12T17:55:50.456 +C Activate\sthe\sone-pass\soptimization.\s\sUpdate\scomments,\sespecially\sthe\ndescriptions\sof\sthe\svarious\sobjects. +D 2013-06-12T20:18:16.225 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 568aef7548e2cad24f03b6099f07aa66b2fa269c +F src/where.c 4209851115ec883e004f0e0ec496215c9df10e33 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P f2e15b1974e55373b5819e3b2326653f890f409f -R 6fa5c9c088caf080e0b4a5ec6cf7a456 +P 25c0f7292a20c0db6ef176966d9987f29c7d73e5 +R abdb63c5ef041b9c2f729e7a4c7abdae U drh -Z 738850606e13a26064a82bd0faf55587 +Z 9e2bd249132b4bdcba34d19dbfd465f2 diff --git a/manifest.uuid b/manifest.uuid index 86fd19a1a4..f1e38ab6d5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -25c0f7292a20c0db6ef176966d9987f29c7d73e5 \ No newline at end of file +e120c558a5bafc0f0d2cc12ee5c9d36e20cc642d \ No newline at end of file diff --git a/src/where.c b/src/where.c index 5b699a8663..62cef439ba 100644 --- a/src/where.c +++ b/src/where.c @@ -27,10 +27,10 @@ #endif #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) -# define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X +# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X # define WHERETRACE_ENABLED 1 #else -# define WHERETRACE(X) +# define WHERETRACE(K,X) #endif /* Forward reference @@ -48,23 +48,32 @@ typedef struct WhereScan WhereScan; /* ** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The -** maximum cost is 64*(2**63) which becomes 6900. So all costs can be -** be stored in a 16-bit unsigned integer without risk of overflow. +** maximum cost for ordinary tables is 64*(2**63) which becomes 6900. +** (Virtual tables can return a larger cost, but let's assume they do not.) +** So all costs can be stored in a 16-bit unsigned integer without risk +** of overflow. +** +** Costs are estimates, so don't go to the computational trouble to compute +** 10*log2(X) exactly. Instead, a close estimate is used. Any value of +** X<=1 is stored as 0. X=2 is 10. X=3 is 16. X=1000 is 99. etc. +** */ typedef unsigned short int WhereCost; /* -** For each nested loop in a WHERE clause implementation, the WhereInfo -** structure contains a single instance of this structure. This structure -** is intended to be private to the where.c module and should not be -** access or modified by other modules. +** This object contains information needed to implement a single nestd +** loop in WHERE clause. ** -** The pIdxInfo field is used to help pick the best index on a -** virtual table. The pIdxInfo pointer contains indexing -** information for the i-th table in the FROM clause before reordering. -** All the pIdxInfo pointers are freed by whereInfoFree() in where.c. -** All other information in the i-th WhereLevel object for the i-th table -** after FROM clause ordering. +** Contrast this object with WhereLoop. This object describes the +** implementation of the loop. WhereLoop describes the algorithm. +** This object contains a pointer to the WhereLoop algorithm as one of +** its elements. +** +** The WhereInfo object contains a single instance of this object for +** each term in the FROM clause (which is to say, for each of the +** nested loops as implemented). The order of WhereLevel objects determines +** the loop nested order, with WhereInfo.a[0] being the outer loop and +** WhereInfo.a[WhereInfo.nLevel-1] being the inner loop. */ struct WhereLevel { int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ @@ -92,10 +101,18 @@ struct WhereLevel { }; /* -** Each instance of this object represents a way of evaluating one -** term of a join. The WhereClause object holds a table of these -** objects using (maskSelf,prereq,) as the primary key. Note that the -** same join term might have multiple associated WhereLoop objects. +** Each instance of this object represents an algorithm for evaluating one +** term of a join. Every term of the FROM clause will have at least +** one corresponding WhereLoop object (unless INDEXED BY constraints +** prevent a query solution - which is an error) and many terms of the +** FROM clause will have multiple WhereLoop objects, each describing a +** potential way of implementing that FROM-clause term, together with +** dependencies and cost estimates for using the chosen algorithm. +** +** Query planning consists of building up a collection of these WhereLoop +** objects, then computing a particular sequence of WhereLoop objects, with +** one WhereLoop object per FROM clause term, that satisfy all dependencies +** and that minimize the overall cost. */ struct WhereLoop { Bitmask prereq; /* Bitmask of other loops that must run first */ @@ -136,7 +153,21 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int); /* ** Each instance of this object holds a sequence of WhereLoop objects -** that implement some or all of the entire query plan. +** that implement some or all of a query plan. +** +** Think of each WhereLoop objects as a node in a graph, which arcs +** showing dependences and costs for travelling between nodes. (That is +** not a completely accurate description because WhereLoop costs are a +** vector, not a scalar, and because dependences are many-to-one, not +** one-to-one as are graph nodes. But it is a useful visualization aid.) +** Then a WherePath object is a path through the graph that visits some +** or all of the WhereLoop objects once. +** +** The "solver" works by creating the N best WherePath objects of length +** 1. Then using those as a basis to compute the N best WherePath objects +** of length 2. And so forth until the length of WherePaths equals the +** number of nodes in the FROM clause. The best (lowest cost) WherePath +** at the end is the choosen query plan. */ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ @@ -323,7 +354,8 @@ struct WhereMaskSet { }; /* -** This object is a factory for WhereLoop objects for a particular query. +** This object is a convenience wrapper holding all information needed +** to construct WhereLoop objects for a particular query. */ struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ @@ -339,6 +371,9 @@ struct WhereLoopBuilder { ** half does the tail of the WHERE loop. An instance of ** this structure is returned by the first half and passed ** into the second half to give some continuity. +** +** An instance of this object holds the complete state of the query +** planner. */ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ @@ -364,9 +399,10 @@ struct WhereInfo { }; /* -** Bitmasks for the operators that indices are able to exploit. An +** Bitmasks for the operators on WhereTerm objects. These are all +** operators that are of interest to the query planner. An ** OR-ed combination of these values can be used when searching for -** terms in the where clause. +** particular WhereTerms within a WhereClause. */ #define WO_IN 0x001 #define WO_EQ 0x002 @@ -385,9 +421,9 @@ struct WhereInfo { #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */ /* -** Value for wsFlags returned by bestIndex() and stored in -** WhereLevel.wsFlags. These flags determine which search -** strategies are appropriate. +** These are definitions of bits in the WhereLoop.wsFlags field. +** The particular combination of bits in each WhereLoop help to +** determine the algorithm that WhereLoop represents. */ #define WHERE_COLUMN_EQ 0x00000001 /* x=EXPR or x IN (...) or x IS NULL */ #define WHERE_COLUMN_RANGE 0x00000002 /* xEXPR */ @@ -409,6 +445,7 @@ struct WhereInfo { /* Convert a WhereCost value (10 times log2(X)) into its integer value X. +** A rough approximation is used. The value returned is not exact. */ static u64 whereCostToInt(WhereCost x){ u64 n; @@ -602,7 +639,7 @@ static void whereSplit(WhereClause *pWC, Expr *pExpr, int op){ } /* -** Initialize an expression mask set (a WhereMaskSet object) +** Initialize a WhereMaskSet object */ #define initMaskSet(P) (P)->n=0 @@ -635,18 +672,9 @@ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ } /* -** This routine walks (recursively) an expression tree and generates +** These routine walk (recursively) an expression tree and generates ** a bitmask indicating which tables are used in that expression ** tree. -** -** In order for this routine to work, the calling function must have -** previously invoked sqlite3ResolveExprNames() on the expression. See -** the header comment on that routine for additional information. -** The sqlite3ResolveExprNames() routines looks for column names and -** sets their opcodes to TK_COLUMN and their Expr.iTable fields to -** the VDBE cursor number of the table. This routine just has to -** translate the cursor numbers into bitmask values and OR all -** the bitmasks together. */ static Bitmask exprListTableUsage(WhereMaskSet*, ExprList*); static Bitmask exprSelectTableUsage(WhereMaskSet*, Select*); @@ -700,7 +728,7 @@ static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){ /* ** Return TRUE if the given operator is one of the operators that is ** allowed for an indexable WHERE clause term. The allowed operators are -** "=", "<", ">", "<=", ">=", and "IN". +** "=", "<", ">", "<=", ">=", "IN", and "IS NULL" ** ** IMPLEMENTATION-OF: R-59926-26393 To be usable by an index a term must be ** of one of the following forms: column = expression column > expression @@ -727,10 +755,9 @@ static int allowedOp(int op){ ** are converted into "Y op X". ** ** If left/right precedence rules come into play when determining the -** collating -** side of the comparison, it remains associated with the same side after -** the commutation. So "Y collate NOCASE op X" becomes -** "X op Y". This is because any collation sequence on +** collating sequence, then COLLATE operators are adjusted to ensure +** that the collating sequence does not change. For example: +** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on ** the left hand side of a comparison overrides any collation sequence ** attached to the right. For the same reason the EP_Collate flag ** is not commuted. @@ -871,6 +898,11 @@ WhereTerm *whereScanNext(WhereScan *pScan){ ** for terms of the form "X " where X is column iColumn of table ** iCur. The must be one of the operators described by opMask. ** +** If the search is for X and the WHERE clause contains terms of the +** form X=Y then this routine might also return terms of the form +** "Y ". The number of levels of transitivity is limited, +** but is enough to handle most commonly occurring SQL statements. +** ** If X is not the INTEGER PRIMARY KEY then X must be compatible with ** index pIdx. */ @@ -959,8 +991,6 @@ static void exprAnalyze(SrcList*, WhereClause*, int); /* ** Call exprAnalyze on all terms in a WHERE clause. -** -** */ static void exprAnalyzeAll( SrcList *pTabList, /* the FROM clause */ @@ -1739,11 +1769,8 @@ static void exprAnalyze( } /* -** This function searches the expression list passed as the second argument -** for an expression of type TK_COLUMN that refers to the same column and -** uses the same collation sequence as the iCol'th column of index pIdx. -** Argument iBase is the cursor number used for the table that pIdx refers -** to. +** This function searches pList for a entry that matches the iCol-th column +** of index pIdx. ** ** If such an expression is found, its index in pList->a[] is returned. If ** no expression is found, -1 is returned. @@ -1778,7 +1805,7 @@ static int findIndexCol( ** Return true if the DISTINCT expression-list passed as the third argument ** is redundant. ** -** A DISTINCT list is redundant if the database contains some set of +** A DISTINCT list is redundant if the database contains some subset of ** columns that are unique and non-null. */ static int isDistinctRedundant( @@ -1842,7 +1869,10 @@ static int isDistinctRedundant( } /* -** The sum of two WhereCosts +** The (an approximate) sum of two WhereCosts. This computation is +** not a simple "+" operator because WhereCost is stored as a logarithmic +** value. +** */ static WhereCost whereCostAdd(WhereCost a, WhereCost b){ static const unsigned char x[] = { @@ -1868,7 +1898,8 @@ static WhereCost whereCostAdd(WhereCost a, WhereCost b){ } /* -** Convert an integer into a WhereCost +** Convert an integer into a WhereCost. In other words, compute a +** good approximatation for 10*log2(x). */ static WhereCost whereCostFromInt(tRowcnt x){ static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; @@ -1886,7 +1917,8 @@ static WhereCost whereCostFromInt(tRowcnt x){ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Convert a double (as received from xBestIndex of a virtual table) -** into a WhereCost +** into a WhereCost. In other words, compute an approximation for +** 10*log2(x). */ static WhereCost whereCostFromDouble(double x){ u64 a; @@ -1901,11 +1933,7 @@ static WhereCost whereCostFromDouble(double x){ #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* -** Prepare a crude estimate of the logarithm of the input value. -** The results need not be exact. This is only used for estimating -** the total cost of performing operations with O(logN) or O(NlogN) -** complexity. Because N is just a guess, it is no great tragedy if -** logN is a little off. +** Estimate the logarithm of the input value to base 2. */ static WhereCost estLog(WhereCost N){ WhereCost x = whereCostFromInt(N); @@ -2158,8 +2186,6 @@ static sqlite3_index_info *allocateIndexInfo( int nOrderBy; sqlite3_index_info *pIdxInfo; - /*WHERETRACE(("Recomputing index info for %s...\n", pSrc->pTab->zName));*/ - /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){ @@ -2250,8 +2276,8 @@ static sqlite3_index_info *allocateIndexInfo( /* ** The table object reference passed as the second argument to this function ** must represent a virtual table. This function invokes the xBestIndex() -** method of the virtual table with the sqlite3_index_info pointer passed -** as the argument. +** method of the virtual table with the sqlite3_index_info object that +** comes in as the 3rd argument to this function. ** ** If an error occurs, pParse is populated with an error message and a ** non-zero value is returned. Otherwise, 0 is returned and the output @@ -2266,7 +2292,6 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ int i; int rc; - /*WHERETRACE(("xBestIndex for %s\n", pTab->zName));*/ TRACE_IDX_INPUTS(p); rc = pVtab->pModule->xBestIndex(pVtab, p); TRACE_IDX_OUTPUTS(p); @@ -2578,8 +2603,8 @@ static int whereRangeScanEst( iBase -= whereCostFromInt(iUpper - iLower); } *pRangeDiv = iBase; - /*WHERETRACE(("range scan regions: %u..%u div=%g\n", - (u32)iLower, (u32)iUpper, *pRangeDiv));*/ + WHERETRACE(0x100, ("range scan regions: %u..%u div=%d\n", + (u32)iLower, (u32)iUpper, *pRangeDiv)); return SQLITE_OK; } } @@ -2640,7 +2665,7 @@ static int whereEqualScanEst( if( pRhs==0 ) return SQLITE_NOTFOUND; rc = whereKeyStats(pParse, p, pRhs, 0, a); if( rc==SQLITE_OK ){ - /*WHERETRACE(("equality scan regions: %d\n", (int)a[1]));*/ + WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1])); *pnRow = a[1]; } whereEqualScanEst_cancel: @@ -2686,7 +2711,7 @@ static int whereInScanEst( if( rc==SQLITE_OK ){ if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0]; *pnRow = nRowEst; - /*WHERETRACE(("IN row estimate: est=%g\n", nRowEst));*/ + WHERETRACE(0x100,("IN row estimate: est=%g\n", nRowEst)); } return rc; } @@ -5060,9 +5085,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ nLoop = pWInfo->nLevel; mxChoice = (nLoop==1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); -#ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace>=2 ) sqlite3DebugPrintf("---- begin solver\n"); -#endif + WHERETRACE(0x002, ("---- begin solver\n")); /* Allocate and initialize space for aTo and aFrom */ ii = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; @@ -5088,11 +5111,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ }else{ /* Compute an estimate on the cost to sort the entire result set */ rSortCost = nRowEst + estLog(nRowEst); -#ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace>=2 ){ - sqlite3DebugPrintf("---- sort cost=%-3d\n", rSortCost); - } -#endif + WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost)); } /* Compute successively longer WherePaths using the previous generation @@ -5605,7 +5624,7 @@ WhereInfo *sqlite3WhereBegin( } /* Construct the WhereLoop objects */ - WHERETRACE(("*** Optimizer Start ***\n")); + WHERETRACE(0xffff,("*** Optimizer Start ***\n")); if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; @@ -5664,21 +5683,20 @@ WhereInfo *sqlite3WhereBegin( } } #endif - WHERETRACE(("*** Optimizer Finished ***\n")); + WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; -#if 0 /* FIXME: Add this back in? */ /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. ** The one-pass algorithm only works if the WHERE clause constraints ** the statement to update a single row. */ assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); - if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 && (andFlags & WHERE_ONEROW)!=0 ){ + if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 + && (pWInfo->a[0].pWLoop->wsFlags & WHERE_ONEROW)!=0 ){ pWInfo->okOnePass = 1; - pWInfo->a[0].plan.wsFlags &= ~WHERE_IDX_ONLY; + pWInfo->a[0].pWLoop->wsFlags &= ~WHERE_IDX_ONLY; } -#endif /* Open all tables in the pTabList and any indices selected for ** searching those tables. From 12ffbc7e690fb2b6f001493c16efcdaa24f9be8b Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 13 Jun 2013 14:51:53 +0000 Subject: [PATCH 114/144] Fix an off-by-one error in the WhereCost to integer conversion. FossilOrigin-Name: b5ca80d924f8c6d31f036247ba6e20d234f4482e --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 2 +- tool/wherecosttest.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index b3d0bc075d..91e4990458 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Activate\sthe\sone-pass\soptimization.\s\sUpdate\scomments,\sespecially\sthe\ndescriptions\sof\sthe\svarious\sobjects. -D 2013-06-12T20:18:16.225 +C Fix\san\soff-by-one\serror\sin\sthe\sWhereCost\sto\sinteger\sconversion. +D 2013-06-13T14:51:53.839 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 4209851115ec883e004f0e0ec496215c9df10e33 +F src/where.c c6944d98be4dfd0f080c2e205909ca6c25c21224 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1093,9 +1093,9 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -F tool/wherecosttest.c 4d0393bdbe7230adb712e925863744dd2b7ffc5b +F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 25c0f7292a20c0db6ef176966d9987f29c7d73e5 -R abdb63c5ef041b9c2f729e7a4c7abdae +P e120c558a5bafc0f0d2cc12ee5c9d36e20cc642d +R 70bdc5e3664356410e482d1133202557 U drh -Z 9e2bd249132b4bdcba34d19dbfd465f2 +Z 22748fc276d8e873b764764d1effa482 diff --git a/manifest.uuid b/manifest.uuid index f1e38ab6d5..4172d0480a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e120c558a5bafc0f0d2cc12ee5c9d36e20cc642d \ No newline at end of file +b5ca80d924f8c6d31f036247ba6e20d234f4482e \ No newline at end of file diff --git a/src/where.c b/src/where.c index 62cef439ba..8593dc4d94 100644 --- a/src/where.c +++ b/src/where.c @@ -449,7 +449,7 @@ struct WhereInfo { */ static u64 whereCostToInt(WhereCost x){ u64 n; - if( x<=10 ) return 1; + if( x<10 ) return 1; n = x%10; x /= 10; if( n>=5 ) n -= 2; diff --git a/tool/wherecosttest.c b/tool/wherecosttest.c index 3055358fc2..39d4a7a368 100644 --- a/tool/wherecosttest.c +++ b/tool/wherecosttest.c @@ -73,7 +73,7 @@ WhereCost whereCostFromInteger(int x){ } static unsigned long int whereCostToInt(WhereCost x){ unsigned long int n; - if( x<=10 ) return 1; + if( x<10 ) return 1; n = x%10; x /= 10; if( n>=5 ) n -= 2; From e1e2e9acd6a66c7a3b6cf133dcf76711271d7049 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 13 Jun 2013 15:16:53 +0000 Subject: [PATCH 115/144] Make the MIN() and MAX() macros available in sqliteInt.h. Add TUNING comments to the NGQP and adjust costs slightly. FossilOrigin-Name: 3a72af2a95b04b8e195ef17cb3e9d9021a4f0915 --- manifest | 22 +++++----- manifest.uuid | 2 +- src/backup.c | 6 --- src/memjournal.c | 6 --- src/os_win.c | 7 --- src/sqliteInt.h | 6 +++ src/where.c | 102 ++++++++++++++++++++++++++++++------------- test/autoindex1.test | 6 +++ 8 files changed, 96 insertions(+), 61 deletions(-) diff --git a/manifest b/manifest index 91e4990458..d0d1a72243 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\soff-by-one\serror\sin\sthe\sWhereCost\sto\sinteger\sconversion. -D 2013-06-13T14:51:53.839 +C Make\sthe\sMIN()\sand\sMAX()\smacros\savailable\sin\ssqliteInt.h.\s\sAdd\sTUNING\ncomments\sto\sthe\sNGQP\sand\sadjust\scosts\sslightly. +D 2013-06-13T15:16:53.047 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -159,7 +159,7 @@ F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168 F src/analyze.c 27e541b9b5b48b41eb899b22a49ff42384899151 F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 -F src/backup.c b266767351ae2d847716c56fcb2a1fea7c761c03 +F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c 7fba377c29573adfc6091832e27ee1fcbefb51d0 @@ -191,7 +191,7 @@ F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f -F src/memjournal.c 41a598445c8f249bd9b26ecae700c60dcf34cbf3 +F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785 F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553 @@ -202,7 +202,7 @@ F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_unix.c 42c9b8b7c61c9fa3561258f523be5749e52ed0e0 -F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b +F src/os_win.c 074cb2b9bca6a1c2bd72acf04666cdc554bfaa9b F src/pager.c 79df56da9dd49aceaa4cac207484a9a82cba40ae F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 F src/parse.y 9acfcc83ddbf0cf82f0ed9582ccf0ad6c366ff37 @@ -220,7 +220,7 @@ F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 026a52f3e24c15603fddb78025e786b96c4c0d2c +F src/sqliteInt.h 82a0f3e7c3410cc748c80268e0831dba5ea98cb4 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c c6944d98be4dfd0f080c2e205909ca6c25c21224 +F src/where.c 2e8e0a18dcef3a56a5874a33ba5ec4339f6911ce F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -322,7 +322,7 @@ F test/auth.test 4a4c3b034fff7750513520defa910f376c96ab49 F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf -F test/autoindex1.test fac4207316e4e954abd086eafdd571ef093c5f5d +F test/autoindex1.test 6a22a566b2dcbc968a62f8282af81574055d1bbf F test/autovacuum.test 9f22a7733f39c56ef6a5665d10145ac25d8cb574 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P e120c558a5bafc0f0d2cc12ee5c9d36e20cc642d -R 70bdc5e3664356410e482d1133202557 +P b5ca80d924f8c6d31f036247ba6e20d234f4482e +R 224bd6bce7ee1e3846617c8c2c148fe1 U drh -Z 22748fc276d8e873b764764d1effa482 +Z df43f94251ce9f1e894782fd34764619 diff --git a/manifest.uuid b/manifest.uuid index 4172d0480a..b4af3a8785 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b5ca80d924f8c6d31f036247ba6e20d234f4482e \ No newline at end of file +3a72af2a95b04b8e195ef17cb3e9d9021a4f0915 \ No newline at end of file diff --git a/src/backup.c b/src/backup.c index 252f61cfca..6ef9374ec6 100644 --- a/src/backup.c +++ b/src/backup.c @@ -15,12 +15,6 @@ #include "sqliteInt.h" #include "btreeInt.h" -/* Macro to find the minimum of two numeric values. -*/ -#ifndef MIN -# define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - /* ** Structure allocated for each backup operation. */ diff --git a/src/memjournal.c b/src/memjournal.c index 05725948f6..65ed378b38 100644 --- a/src/memjournal.c +++ b/src/memjournal.c @@ -31,12 +31,6 @@ typedef struct FileChunk FileChunk; */ #define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*))) -/* Macro to find the minimum of two numeric values. -*/ -#ifndef MIN -# define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - /* ** The rollback journal is composed of a linked list of these structures. */ diff --git a/src/os_win.c b/src/os_win.c index 07b74cbe22..bdf025aa4c 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -84,13 +84,6 @@ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); #endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */ -/* -** Macro to find the minimum of two numeric values. -*/ -#ifndef MIN -# define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - /* ** Some Microsoft compilers lack this definition. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b22689462c..b2cab7a7ad 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -395,6 +395,12 @@ #define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) #endif +/* +** Macros to compute minimum and maximum of two numbers. +*/ +#define MIN(A,B) ((A)<(B)?(A):(B)) +#define MAX(A,B) ((A)>(B)?(A):(B)) + /* ** Check to see if this machine uses EBCDIC. (Yes, believe it or ** not, there are still machines out there that use EBCDIC.) diff --git a/src/where.c b/src/where.c index 8593dc4d94..000df0e107 100644 --- a/src/where.c +++ b/src/where.c @@ -57,6 +57,10 @@ typedef struct WhereScan WhereScan; ** 10*log2(X) exactly. Instead, a close estimate is used. Any value of ** X<=1 is stored as 0. X=2 is 10. X=3 is 16. X=1000 is 99. etc. ** +** The tool/wherecosttest.c source file implements a command-line program +** that will convert between WhereCost to integers and do addition and +** multiplication on WhereCost values. That command-line program is a +** useful utility to have around when working with this module. */ typedef unsigned short int WhereCost; @@ -1901,7 +1905,7 @@ static WhereCost whereCostAdd(WhereCost a, WhereCost b){ ** Convert an integer into a WhereCost. In other words, compute a ** good approximatation for 10*log2(x). */ -static WhereCost whereCostFromInt(tRowcnt x){ +static WhereCost whereCost(tRowcnt x){ static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; WhereCost y = 40; if( x<8 ){ @@ -1925,7 +1929,7 @@ static WhereCost whereCostFromDouble(double x){ WhereCost e; assert( sizeof(x)==8 && sizeof(a)==8 ); if( x<=1 ) return 0; - if( x<=2000000000 ) return whereCostFromInt((tRowcnt)x); + if( x<=2000000000 ) return whereCost((tRowcnt)x); memcpy(&a, &x, 8); e = (a>>52) - 1022; return e*10; @@ -1936,7 +1940,7 @@ static WhereCost whereCostFromDouble(double x){ ** Estimate the logarithm of the input value to base 2. */ static WhereCost estLog(WhereCost N){ - WhereCost x = whereCostFromInt(N); + WhereCost x = whereCost(N); return x>33 ? x - 33 : 0; } @@ -2598,9 +2602,9 @@ static int whereRangeScanEst( sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK ){ - WhereCost iBase = whereCostFromInt(p->aiRowEst[0]); + WhereCost iBase = whereCost(p->aiRowEst[0]); if( iUpper>iLower ){ - iBase -= whereCostFromInt(iUpper - iLower); + iBase -= whereCost(iUpper - iLower); } *pRangeDiv = iBase; WHERETRACE(0x100, ("range scan regions: %u..%u div=%d\n", @@ -2615,11 +2619,13 @@ static int whereRangeScanEst( #endif assert( pLower || pUpper ); *pRangeDiv = 0; + /* TUNING: Each inequality constraint reduces the search space 4-fold. + ** A BETWEEN operator, therefore, reduces the search space 16-fold */ if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){ - *pRangeDiv += 20; assert( 20==whereCostFromInt(4) ); + *pRangeDiv += 20; assert( 20==whereCost(4) ); } if( pUpper ){ - *pRangeDiv += 20; assert( 20==whereCostFromInt(4) ); + *pRangeDiv += 20; assert( 20==whereCost(4) ); } return rc; } @@ -4244,7 +4250,7 @@ static int whereLoopAddBtreeIndex( if( pNew->u.btree.nEq < pProbe->nColumn ){ iCol = pProbe->aiColumn[pNew->u.btree.nEq]; - nRowEst = whereCostFromInt(pProbe->aiRowEst[pNew->u.btree.nEq+1]); + nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]); }else{ iCol = -1; nRowEst = 0; @@ -4257,7 +4263,7 @@ static int whereLoopAddBtreeIndex( saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pNew->rSetup = 0; - rLogSize = estLog(whereCostFromInt(pProbe->aiRowEst[0])); + rLogSize = estLog(whereCost(pProbe->aiRowEst[0])); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ int nIn = 0; if( pTerm->prereqRight & pNew->maskSelf ) continue; @@ -4267,16 +4273,16 @@ static int whereLoopAddBtreeIndex( if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTerm; pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; - pNew->rRun = rLogSize; + pNew->rRun = rLogSize; /* Baseline cost is log2(N). Adjustments below */ if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */ - nIn = 46; assert( 46==whereCostFromInt(25) ); + /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ + nIn = 46; assert( 46==whereCost(25) ); }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ - nIn = whereCostFromInt(pExpr->x.pList->nExpr); + nIn = whereCost(pExpr->x.pList->nExpr); } pNew->rRun += nIn; pNew->u.btree.nEq++; @@ -4297,7 +4303,8 @@ static int whereLoopAddBtreeIndex( }else if( pTerm->eOperator & (WO_ISNULL) ){ pNew->wsFlags |= WHERE_COLUMN_NULL; pNew->u.btree.nEq++; - nIn = 10; assert( 10==whereCostFromInt(2) ); + /* TUNING: IS NULL selects 2 rows */ + nIn = 10; assert( 10==whereCost(2) ); pNew->nOut = nRowEst + nInMul + nIn; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; @@ -4325,7 +4332,7 @@ static int whereLoopAddBtreeIndex( && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut); } - pNew->nOut = whereCostFromInt(nOut); + pNew->nOut = whereCost(nOut); } #endif if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ @@ -4451,7 +4458,7 @@ static int whereLoopAddBtree( } pProbe = &sPk; } - rSize = whereCostFromInt(pSrc->pTab->nRowEst); + rSize = whereCost(pSrc->pTab->nRowEst); rLogSize = estLog(rSize); /* Automatic indexes */ @@ -4473,9 +4480,12 @@ static int whereLoopAddBtree( pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; - assert( 43==whereCostFromInt(20) ); - pNew->rSetup = 43 + rLogSize + rSize; - pNew->nOut = 33; assert( 33==whereCostFromInt(10) ); + /* TUNING: One-time cost for computing the automatic index is + ** approximately 6*N*log2(N) where N is the number of rows in + ** the table being indexed. */ + pNew->rSetup = rLogSize + rSize + 26; assert( 26==whereCost(6) ); + /* TUNING: Each index lookup yields 10 rows in the table */ + pNew->nOut = 33; assert( 33==whereCost(10) ); pNew->rRun = whereCostAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_TEMP_INDEX; pNew->prereq = mExtra | pTerm->prereqRight; @@ -4501,7 +4511,12 @@ static int whereLoopAddBtree( /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; - pNew->rRun = whereCostAdd(rSize,rLogSize) + 16 - b; + /* TUNING: Cost of full table scan is 3*(N + log2(N)). + ** + The extra 3 factor is to encourage the use of indexed lookups + ** over full scans. A smaller constant 2 is used for covering + ** index scans so that a covering index scan will be favored over + ** a table scan. */ + pNew->rRun = whereCostAdd(rSize,rLogSize) + 16; rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; }else{ @@ -4517,8 +4532,22 @@ static int whereLoopAddBtree( ){ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; - pNew->rRun = whereCostAdd(rSize,rLogSize); - pNew->rRun += ((m!=0) ? rLogSize : 10) - b; + if( m==0 ){ + /* TUNING: Cost of a covering index scan is 2*(N + log2(N)). + ** + The extra 2 factor is to encourage the use of indexed lookups + ** over index scans. A table scan uses a factor of 3 so that + ** index scans are favored over table scans. + ** + If this covering index might also help satisfy the ORDER BY + ** clause, then the cost is fudged down slightly so that this + ** index is favored above other indices that have no hope of + ** helping with the ORDER BY. */ + pNew->rRun = 10 + whereCostAdd(rSize,rLogSize) - b; + }else{ + assert( b!=0 ); + /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N) + ** which we will simplify to just N*log2(N) */ + pNew->rRun = rSize + rLogSize; + } rc = whereLoopInsert(pBuilder, pNew); if( rc ) break; } @@ -4675,7 +4704,8 @@ static int whereLoopAddVirtual( && pIdxInfo->orderByConsumed); pNew->rSetup = 0; pNew->rRun = whereCostFromDouble(pIdxInfo->estimatedCost); - pNew->nOut = 46; assert( 46 == whereCostFromInt(25) ); + /* TUNING: Every virtual table query returns 25 rows */ + pNew->nOut = 46; assert( 46==whereCost(25) ); whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); @@ -5066,6 +5096,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ + Parse *pParse; /* Parsing context */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ @@ -5081,8 +5112,12 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ WhereLoop **pX; /* Used to divy up the pSpace memory */ char *pSpace; /* Temporary memory used by this routine */ - db = pWInfo->pParse->db; + pParse = pWInfo->pParse; + db = pParse->db; nLoop = pWInfo->nLevel; + /* TUNING: For simple queries, only the best path is tracked. + ** For 2-way joins, the 5 best paths are followed. + ** For joins of 3 or more tables, track the 10 best paths */ mxChoice = (nLoop==1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); WHERETRACE(0x002, ("---- begin solver\n")); @@ -5099,8 +5134,12 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ pFrom->aLoop = pX; } - /* Seed the search with a single WherePath containing zero WhereLoops */ - aFrom[0].nRow = pWInfo->pParse->nQueryLoop; + /* Seed the search with a single WherePath containing zero WhereLoops. + ** + ** TUNING: Do not let the number of iterations go above 25. If the cost + ** of computing an automatic index is not paid back within the first 25 + ** rows, then do not use the automatic index. */ + aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==whereCost(25) ); nFrom = 1; /* Precompute the cost of sorting the final result set, if the caller @@ -5109,7 +5148,8 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ if( pWInfo->pOrderBy==0 || nRowEst==0 ){ aFrom[0].isOrderedValid = 1; }else{ - /* Compute an estimate on the cost to sort the entire result set */ + /* TUNING: Estimated cost of sorting is N*log2(N) where N is the + ** number of output rows. */ rSortCost = nRowEst + estLog(nRowEst); WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost)); } @@ -5254,7 +5294,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ } if( nFrom==0 ){ - sqlite3ErrorMsg(pWInfo->pParse, "no query solution"); + sqlite3ErrorMsg(pParse, "no query solution"); sqlite3DbFree(db, pSpace); return SQLITE_ERROR; } @@ -5335,7 +5375,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop->aLTerm[0] = pTerm; pLoop->nLTerm = 1; pLoop->u.btree.nEq = 1; - pLoop->rRun = 33; /* 33 == whereCostFromInt(10) */ + /* TUNING: Cost of a rowid lookup is 10 */ + pLoop->rRun = 33; /* 33==whereCost(10) */ }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->onError==OE_None ) continue; @@ -5353,7 +5394,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop->nLTerm = j; pLoop->u.btree.nEq = j; pLoop->u.btree.pIndex = pIdx; - pLoop->rRun = 39; /* 39 == whereCostFromInt(15) */ + /* TUNING: Cost of a unique index lookup is 15 */ + pLoop->rRun = 39; /* 39==whereCost(15) */ break; } } diff --git a/test/autoindex1.test b/test/autoindex1.test index 9d67def05f..f7b0977fbc 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -78,6 +78,9 @@ do_test autoindex1-202 { do_test autoindex1-210 { db eval { PRAGMA automatic_index=ON; + ANALYZE; + UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t1'; + ANALYZE sqlite_master; SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1; } } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988} @@ -143,6 +146,9 @@ do_test autoindex1-401 { do_execsql_test autoindex1-500 { CREATE TABLE t501(a INTEGER PRIMARY KEY, b); CREATE TABLE t502(x INTEGER PRIMARY KEY, y); + INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t501',null,'1000000'); + INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t502',null,'1000'); + ANALYZE sqlite_master; EXPLAIN QUERY PLAN SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=?); From bbe8b24b8d96b8e0c79c68869358e7501ad007a8 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 13 Jun 2013 15:50:59 +0000 Subject: [PATCH 116/144] Restore the ability to do a BETWEEN query on the rowid. Also fix a nearby comment. FossilOrigin-Name: 459a7b9068310b36fed950940d251c4b798ffc58 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index d0d1a72243..1780bda7cd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sthe\sMIN()\sand\sMAX()\smacros\savailable\sin\ssqliteInt.h.\s\sAdd\sTUNING\ncomments\sto\sthe\sNGQP\sand\sadjust\scosts\sslightly. -D 2013-06-13T15:16:53.047 +C Restore\sthe\sability\sto\sdo\sa\sBETWEEN\squery\son\sthe\srowid.\s\sAlso\sfix\sa\nnearby\scomment. +D 2013-06-13T15:50:59.429 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 2e8e0a18dcef3a56a5874a33ba5ec4339f6911ce +F src/where.c 82b519b79e4efc45461f6ce3990292c01b5adfdd F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b5ca80d924f8c6d31f036247ba6e20d234f4482e -R 224bd6bce7ee1e3846617c8c2c148fe1 +P 3a72af2a95b04b8e195ef17cb3e9d9021a4f0915 +R 1257e951bd26adefbb24e4a4d17e2b37 U drh -Z df43f94251ce9f1e894782fd34764619 +Z e1ac17bd2fbb6e506f40edf419e837ee diff --git a/manifest.uuid b/manifest.uuid index b4af3a8785..fe46658266 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3a72af2a95b04b8e195ef17cb3e9d9021a4f0915 \ No newline at end of file +459a7b9068310b36fed950940d251c4b798ffc58 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 000df0e107..14bbf88a5b 100644 --- a/src/where.c +++ b/src/where.c @@ -4345,8 +4345,7 @@ static int whereLoopAddBtreeIndex( /* TBD: Adjust nOut for additional constraints */ rc = whereLoopInsert(pBuilder, pNew); if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 - && pNew->u.btree.nEq<=pProbe->nColumn - && pProbe->zName!=0 + && pNew->u.btree.nEq<(pProbe->nColumn + (pProbe->zName!=0)) ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } From 53cfbe92d1ca41e6873e7c897023187d656f41c1 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 13 Jun 2013 17:28:22 +0000 Subject: [PATCH 117/144] Make sure that disabling the covering index scan optimization does not prevent a covering index from being used to satisfy an ORDER BY clause. FossilOrigin-Name: e8b7ea8202c443bfc8a978588c7d2cfaa14a8fea --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 19 +++++++++++-------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 1780bda7cd..97ae5f18b7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Restore\sthe\sability\sto\sdo\sa\sBETWEEN\squery\son\sthe\srowid.\s\sAlso\sfix\sa\nnearby\scomment. -D 2013-06-13T15:50:59.429 +C Make\ssure\sthat\sdisabling\sthe\scovering\sindex\sscan\soptimization\sdoes\snot\nprevent\sa\scovering\sindex\sfrom\sbeing\sused\sto\ssatisfy\san\sORDER\sBY\sclause. +D 2013-06-13T17:28:22.026 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 82b519b79e4efc45461f6ce3990292c01b5adfdd +F src/where.c 700085a8d8e0edf13db11e110577320ec7348edc F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 3a72af2a95b04b8e195ef17cb3e9d9021a4f0915 -R 1257e951bd26adefbb24e4a4d17e2b37 +P 459a7b9068310b36fed950940d251c4b798ffc58 +R 242dd2338fa025aa7191faa8afaf3ae6 U drh -Z e1ac17bd2fbb6e506f40edf419e837ee +Z 7fc4ebaffcaa0d84212cec77e769d428 diff --git a/manifest.uuid b/manifest.uuid index fe46658266..10384ea54c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -459a7b9068310b36fed950940d251c4b798ffc58 \ No newline at end of file +e8b7ea8202c443bfc8a978588c7d2cfaa14a8fea \ No newline at end of file diff --git a/src/where.c b/src/where.c index 14bbf88a5b..46f741d159 100644 --- a/src/where.c +++ b/src/where.c @@ -445,7 +445,6 @@ struct WhereInfo { #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ #define WHERE_TEMP_INDEX 0x00004000 /* Uses an ephemeral index */ -#define WHERE_COVER_SCAN 0x00008000 /* Full scan of a covering index */ /* Convert a WhereCost value (10 times log2(X)) into its integer value X. @@ -3614,8 +3613,7 @@ static Bitmask codeOneLoopStart( pLevel->op = OP_Next; } pLevel->p1 = iIdxCur; - if( (pLoop->wsFlags & (WHERE_COLUMN_EQ | WHERE_COLUMN_RANGE | - WHERE_COLUMN_NULL | WHERE_COLUMN_IN))==0 ){ + if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; }else{ assert( pLevel->p5==0 ); @@ -4375,6 +4373,7 @@ static int indexMightHelpWithOrderBy( int iCol; int ii; + if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; iCol = pIndex->aiColumn[0]; for(ii=0; iinExpr; ii++){ @@ -4503,6 +4502,8 @@ static int whereLoopAddBtree( pNew->prereq = mExtra; 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 ); if( pProbe->tnum<=0 ){ /* Integer primary key index */ pNew->wsFlags = WHERE_IPK; @@ -4523,11 +4524,13 @@ static int whereLoopAddBtree( pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; /* Full scan via index */ - if( (m==0 || b) - && pProbe->bUnordered==0 - && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 - && sqlite3GlobalConfig.bUseCis - && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) + if( b + || ( m==0 + && pProbe->bUnordered==0 + && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 + && sqlite3GlobalConfig.bUseCis + && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) + ) ){ pNew->iSortIdx = b ? iSortIdx : 0; pNew->nOut = rSize; From 6d38147c191e9c7a34b505f2c3a8926bbddec9a6 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 13 Jun 2013 17:58:08 +0000 Subject: [PATCH 118/144] An index might be useful for ORDER BY if any indexed column is in the ORDER BY clause, not just the first indexed column. FossilOrigin-Name: ade473b5ae3fe2162b0ec29731d8e864a9301e07 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 9 ++++----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 97ae5f18b7..a5722835d2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\sthat\sdisabling\sthe\scovering\sindex\sscan\soptimization\sdoes\snot\nprevent\sa\scovering\sindex\sfrom\sbeing\sused\sto\ssatisfy\san\sORDER\sBY\sclause. -D 2013-06-13T17:28:22.026 +C An\sindex\smight\sbe\suseful\sfor\sORDER\sBY\sif\sany\sindexed\scolumn\sis\sin\sthe\nORDER\sBY\sclause,\snot\sjust\sthe\sfirst\sindexed\scolumn. +D 2013-06-13T17:58:08.642 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 700085a8d8e0edf13db11e110577320ec7348edc +F src/where.c ba5f6766cfc7fcee945d45120cbb6e39a881b8e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1095,7 +1095,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 459a7b9068310b36fed950940d251c4b798ffc58 -R 242dd2338fa025aa7191faa8afaf3ae6 +P e8b7ea8202c443bfc8a978588c7d2cfaa14a8fea +R 20475a52b4ff0eaa6499f9e0ae4a1e9c U drh -Z 7fc4ebaffcaa0d84212cec77e769d428 +Z f8930bf04903145489a941260cbef3e2 diff --git a/manifest.uuid b/manifest.uuid index 10384ea54c..1431942f12 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e8b7ea8202c443bfc8a978588c7d2cfaa14a8fea \ No newline at end of file +ade473b5ae3fe2162b0ec29731d8e864a9301e07 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 46f741d159..d702668aab 100644 --- a/src/where.c +++ b/src/where.c @@ -4370,18 +4370,17 @@ static int indexMightHelpWithOrderBy( int iCursor ){ ExprList *pOB; - int iCol; - int ii; + int ii, jj; if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; - iCol = pIndex->aiColumn[0]; for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); if( pExpr->op!=TK_COLUMN ) return 0; if( pExpr->iTable==iCursor ){ - if( pExpr->iColumn==iCol ) return 1; - return 0; + for(jj=0; jjnColumn; jj++){ + if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; + } } } return 0; From b8916be945bebb123a03e0193a567f4934c787ba Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 14 Jun 2013 02:51:48 +0000 Subject: [PATCH 119/144] Add a new ORDER BY optimization that bypasses ORDER BY terms that are constrained by == and IS NULL terms of the WHERE clause. FossilOrigin-Name: b920bb70bb009b7c54e7667544c9810c5ee25e19 --- manifest | 13 ++++--- manifest.uuid | 2 +- src/where.c | 33 +++++++++++++++- test/orderby5.test | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 test/orderby5.test diff --git a/manifest b/manifest index a5722835d2..ed857f034a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C An\sindex\smight\sbe\suseful\sfor\sORDER\sBY\sif\sany\sindexed\scolumn\sis\sin\sthe\nORDER\sBY\sclause,\snot\sjust\sthe\sfirst\sindexed\scolumn. -D 2013-06-13T17:58:08.642 +C Add\sa\snew\sORDER\sBY\soptimization\sthat\sbypasses\sORDER\sBY\sterms\sthat\sare\nconstrained\sby\s==\sand\sIS\sNULL\sterms\sof\sthe\sWHERE\sclause. +D 2013-06-14T02:51:48.285 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c ba5f6766cfc7fcee945d45120cbb6e39a881b8e0 +F src/where.c 7d406cca2f60afbbfb57470f0d4981798bccf6e8 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -695,6 +695,7 @@ F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6 F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99 F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4 +F test/orderby5.test 02eca502a0f97c77ce383b0dfa17e99c6a107b8d F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 F test/pager1.test 16b649c8f0b38d446acbcff8a7bf055a9be43276 F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71 @@ -1095,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P e8b7ea8202c443bfc8a978588c7d2cfaa14a8fea -R 20475a52b4ff0eaa6499f9e0ae4a1e9c +P ade473b5ae3fe2162b0ec29731d8e864a9301e07 +R eae0305c76446978c9d6694aa033807b U drh -Z f8930bf04903145489a941260cbef3e2 +Z 288ef6a3a068d55d460d1b487a44477a diff --git a/manifest.uuid b/manifest.uuid index 1431942f12..ade080fb52 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ade473b5ae3fe2162b0ec29731d8e864a9301e07 \ No newline at end of file +b920bb70bb009b7c54e7667544c9810c5ee25e19 \ No newline at end of file diff --git a/src/where.c b/src/where.c index d702668aab..2163ee7a56 100644 --- a/src/where.c +++ b/src/where.c @@ -4891,7 +4891,7 @@ static int wherePathSatisfiesOrderBy( Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ Bitmask obDone; /* Mask of all ORDER BY terms */ Bitmask orderDistinctMask; /* Mask of all well-ordered loops */ - + Bitmask ready; /* Mask of inner loops */ /* ** We say the WhereLoop is "one-row" if it generates no more than one @@ -4931,10 +4931,39 @@ static int wherePathSatisfiesOrderBy( isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; + ready = 0; for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; pLoop = iLoopaLoop[iLoop] : pLast; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; + + /* Mark off any ORDER BY term X that is a column in the table of + ** the current loop for which there is term in the WHERE + ** clause of the form X IS NULL or X=? that reference only outer + ** loops. + */ + for(i=0; ia[i].pExpr); + if( pOBExpr->op!=TK_COLUMN ) continue; + if( pOBExpr->iTable!=iCur ) continue; + pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, + ~ready, WO_EQ|WO_ISNULL, 0); + if( pTerm==0 ) continue; + if( pOBExpr->iColumn>=0 ){ + const char *z1, *z2; + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); + if( !pColl ) pColl = db->pDfltColl; + z1 = pColl->zName; + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr); + if( !pColl ) pColl = db->pDfltColl; + z2 = pColl->zName; + if( sqlite3StrICmp(z1, z2)!=0 ) continue; + } + obSat |= MASKBIT(i); + } + if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ if( pLoop->wsFlags & WHERE_IPK ){ pIndex = 0; @@ -5066,7 +5095,7 @@ static int wherePathSatisfiesOrderBy( } } } - } + } /* End the loop over all WhereLoops from outer-most down to inner-most */ if( obSat==obDone ) return 1; if( !isOrderDistinct ) return 0; if( isLastLoop ) return 1; diff --git a/test/orderby5.test b/test/orderby5.test new file mode 100644 index 0000000000..5bae5db717 --- /dev/null +++ b/test/orderby5.test @@ -0,0 +1,97 @@ +# 2013-06-14 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing that the optimizations that disable +# ORDER BY clauses work correctly +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix orderby5 + +# Generate test data for a join. Verify that the join gets the +# correct answer. +# +do_execsql_test 1.1 { + CREATE TABLE t1(a,b,c); + CREATE INDEX t1bc ON t1(b,c); + + EXPLAIN QUERY PLAN + SELECT DISTINCT a, b, c FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.2.1 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a, c, b FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.2.2 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a, c, b FROM t1 WHERE a='xyz' COLLATE nocase; +} {/B-TREE/} +do_execsql_test 1.2.3 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a COLLATE nocase, c, b FROM t1 WHERE a='xyz'; +} {/B-TREE/} +do_execsql_test 1.2.4 { + EXPLAIN QUERY PLAN + SELECT DISTINCT a COLLATE nocase, c, b FROM t1 WHERE a='xyz' COLLATE nocase; +} {~/B-TREE/} +do_execsql_test 1.3 { + EXPLAIN QUERY PLAN + SELECT DISTINCT b, a, c FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.4 { + EXPLAIN QUERY PLAN + SELECT DISTINCT b, c, a FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.5 { + EXPLAIN QUERY PLAN + SELECT DISTINCT c, a, b FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.6 { + EXPLAIN QUERY PLAN + SELECT DISTINCT c, b, a FROM t1 WHERE a=0; +} {~/B-TREE/} +do_execsql_test 1.7 { + EXPLAIN QUERY PLAN + SELECT DISTINCT c, b, a FROM t1 WHERE +a=0; +} {/B-TREE/} +do_execsql_test 2.1 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY a, b, c; +} {~/B-TREE/} +do_execsql_test 2.2 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c; +} {/B-TREE/} +do_execsql_test 2.3 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY b, a, c; +} {~/B-TREE/} +do_execsql_test 2.4 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY b, c, a; +} {~/B-TREE/} +do_execsql_test 2.5 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY a, c, b; +} {/B-TREE/} +do_execsql_test 2.6 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY c, a, b; +} {/B-TREE/} +do_execsql_test 2.7 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a=0 ORDER BY c, b, a; +} {/B-TREE/} + + +finish_test From f003076032281c2f2dfc884f2e59934f811af6fe Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 14 Jun 2013 13:27:01 +0000 Subject: [PATCH 120/144] Comment tweaks in where.c. No changes to code. FossilOrigin-Name: cecc5fdd5d8fbad7d9e8c275b9ba9ade3dbee8ef --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 12 +++++------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index ed857f034a..299b950889 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\snew\sORDER\sBY\soptimization\sthat\sbypasses\sORDER\sBY\sterms\sthat\sare\nconstrained\sby\s==\sand\sIS\sNULL\sterms\sof\sthe\sWHERE\sclause. -D 2013-06-14T02:51:48.285 +C Comment\stweaks\sin\swhere.c.\s\sNo\schanges\sto\scode. +D 2013-06-14T13:27:01.630 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 7d406cca2f60afbbfb57470f0d4981798bccf6e8 +F src/where.c cd2ee239c40ef7ffc952e176bfb98ff13a638b20 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ade473b5ae3fe2162b0ec29731d8e864a9301e07 -R eae0305c76446978c9d6694aa033807b +P b920bb70bb009b7c54e7667544c9810c5ee25e19 +R 382f7260a0330db641dd26f80cde0534 U drh -Z 288ef6a3a068d55d460d1b487a44477a +Z 568b215d3c8e178d6fdb12bf215bc7ae diff --git a/manifest.uuid b/manifest.uuid index ade080fb52..6a7fb20d1e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b920bb70bb009b7c54e7667544c9810c5ee25e19 \ No newline at end of file +cecc5fdd5d8fbad7d9e8c275b9ba9ade3dbee8ef \ No newline at end of file diff --git a/src/where.c b/src/where.c index 2163ee7a56..33370c383f 100644 --- a/src/where.c +++ b/src/where.c @@ -65,7 +65,7 @@ typedef struct WhereScan WhereScan; typedef unsigned short int WhereCost; /* -** This object contains information needed to implement a single nestd +** This object contains information needed to implement a single nested ** loop in WHERE clause. ** ** Contrast this object with WhereLoop. This object describes the @@ -5944,12 +5944,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ } } - /* If this scan uses an index, make code substitutions to read data - ** from the index in preference to the table. Sometimes, this means - ** the table need never be read from. This is a performance boost, - ** as the vdbe level waits until the table is read before actually - ** seeking the table cursor to the record corresponding to the current - ** position in the index. + /* If this scan uses an index, make VDBE code substitutions to read data + ** from the index instead of from the table where possible. In some cases + ** this optimization prevents the table from ever being read, which can + ** yield a significant performance boost. ** ** Calls to the code generator in between sqlite3WhereBegin and ** sqlite3WhereEnd will have created code that references the table From 613ba1ea9c851b35cbf131e5da52244b0d1081f1 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 15 Jun 2013 15:11:45 +0000 Subject: [PATCH 121/144] Fix compiler warnings. FossilOrigin-Name: 3e8ac46918c68723bd199dbec8b0901457d524a9 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 6 +++--- src/where.c | 13 ++++--------- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 299b950889..c6e1871a02 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Comment\stweaks\sin\swhere.c.\s\sNo\schanges\sto\scode. -D 2013-06-14T13:27:01.630 +C Fix\scompiler\swarnings. +D 2013-06-15T15:11:45.875 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -215,7 +215,7 @@ F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c 588ae13fc3d10dc812a0832fd143374583beb847 +F src/select.c 94a755b3d3788cf171c98064f2fa0ce6350fd6ca F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c cd2ee239c40ef7ffc952e176bfb98ff13a638b20 +F src/where.c df0d274ff134fab313f576f232e586756339e7a1 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b920bb70bb009b7c54e7667544c9810c5ee25e19 -R 382f7260a0330db641dd26f80cde0534 +P cecc5fdd5d8fbad7d9e8c275b9ba9ade3dbee8ef +R ef11f7373ad17a9fe10dde15795cd3f5 U drh -Z 568b215d3c8e178d6fdb12bf215bc7ae +Z 56f2db275e8c6ae6e91e7c2a5db315eb diff --git a/manifest.uuid b/manifest.uuid index 6a7fb20d1e..f8be393895 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cecc5fdd5d8fbad7d9e8c275b9ba9ade3dbee8ef \ No newline at end of file +3e8ac46918c68723bd199dbec8b0901457d524a9 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 8972faacc6..0c706bdbc2 100644 --- a/src/select.c +++ b/src/select.c @@ -1538,8 +1538,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ VdbeComment((v, "LIMIT counter")); if( n==0 ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); - }else{ - if( p->nSelectRow > n ) p->nSelectRow = n; + }else if( n>=0 && p->nSelectRow>(u64)n ){ + p->nSelectRow = n; } }else{ sqlite3ExprCode(pParse, p->pLimit, iLimit); @@ -1733,7 +1733,7 @@ static int multiSelect( p->nSelectRow += pPrior->nSelectRow; if( pPrior->pLimit && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit) - && p->nSelectRow > nLimit + && nLimit>0 && p->nSelectRow > (u64)nLimit ){ p->nSelectRow = nLimit; } diff --git a/src/where.c b/src/where.c index 33370c383f..7777d7e878 100644 --- a/src/where.c +++ b/src/where.c @@ -2927,8 +2927,6 @@ static int codeEqualityTerm( static int codeAllEqualityTerms( Parse *pParse, /* Parsing context */ WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ - WhereClause *pWC, /* The WHERE clause */ - Bitmask notReady, /* Which parts of FROM have not yet been coded */ int bRev, /* Reverse the order of IN operators */ int nExtraReg, /* Number of extra registers to allocate */ char **pzAff /* OUT: Set to point to affinity string */ @@ -3475,9 +3473,7 @@ static Bitmask codeOneLoopStart( ** and store the values of those terms in an array of registers ** starting at regBase. */ - regBase = codeAllEqualityTerms( - pParse, pLevel, pWC, notReady, bRev, nExtraReg, &zStartAff - ); + regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); zEndAff = sqlite3DbStrDup(pParse->db, zStartAff); addrNxt = pLevel->addrNxt; @@ -4568,8 +4564,7 @@ static int whereLoopAddBtree( ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. */ static int whereLoopAddVirtual( - WhereLoopBuilder *pBuilder, /* WHERE clause information */ - Bitmask mExtra /* Extra prerequesites for using this table */ + WhereLoopBuilder *pBuilder /* WHERE clause information */ ){ WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ @@ -4779,7 +4774,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ sBest.rRun = 0; #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ - rc = whereLoopAddVirtual(&sSubBuild, mExtra); + rc = whereLoopAddVirtual(&sSubBuild); }else #endif { @@ -4836,7 +4831,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ } priorJoinType = pItem->jointype; if( IsVirtual(pItem->pTab) ){ - rc = whereLoopAddVirtual(pBuilder, mExtra); + rc = whereLoopAddVirtual(pBuilder); }else{ rc = whereLoopAddBtree(pBuilder, mExtra); } From 75bf6b984ac35bdb16dbb42a06e4596cde365127 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 17 Jun 2013 14:18:21 +0000 Subject: [PATCH 122/144] Use automatic indices on subqueries of the FROM clause when appropriate. FossilOrigin-Name: e8f124284ee0d0e373dc4431668630f1e17015c1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 1 - test/autoindex1.test | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index c6e1871a02..c2a22a6d6e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scompiler\swarnings. -D 2013-06-15T15:11:45.875 +C Use\sautomatic\sindices\son\ssubqueries\sof\sthe\sFROM\sclause\swhen\sappropriate. +D 2013-06-17T14:18:21.734 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c df0d274ff134fab313f576f232e586756339e7a1 +F src/where.c 74ecd744a5a9d18cc8e66f4c234bdac11c472eee F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -322,7 +322,7 @@ F test/auth.test 4a4c3b034fff7750513520defa910f376c96ab49 F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf -F test/autoindex1.test 6a22a566b2dcbc968a62f8282af81574055d1bbf +F test/autoindex1.test 314f12f87667861ac965c41587f9df82c42fff65 F test/autovacuum.test 9f22a7733f39c56ef6a5665d10145ac25d8cb574 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P cecc5fdd5d8fbad7d9e8c275b9ba9ade3dbee8ef -R ef11f7373ad17a9fe10dde15795cd3f5 +P 3e8ac46918c68723bd199dbec8b0901457d524a9 +R cb395ca086e8d43cd185b18cda8198f7 U drh -Z 56f2db275e8c6ae6e91e7c2a5db315eb +Z 602d1da2f8b38f776a1f4f76f4cb8197 diff --git a/manifest.uuid b/manifest.uuid index f8be393895..b46fbe6550 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e8ac46918c68723bd199dbec8b0901457d524a9 \ No newline at end of file +e8f124284ee0d0e373dc4431668630f1e17015c1 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 7777d7e878..0977dbea8d 100644 --- a/src/where.c +++ b/src/where.c @@ -5770,7 +5770,6 @@ WhereInfo *sqlite3WhereBegin( */ sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ notReady = ~(Bitmask)0; - pWInfo->nRowOut = (WhereCost)1; for(ii=0, pLevel=pWInfo->a; ii? AND owner_change_date Date: Mon, 17 Jun 2013 18:20:48 +0000 Subject: [PATCH 123/144] Simplifications to the NGQP. Add the queryplantest makefile target. Add testcase() macros in the NGQP. FossilOrigin-Name: eaf1f1b405ec2c498092527fae00e5dbe9e176c1 --- main.mk | 3 +++ manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/select.c | 3 ++- src/where.c | 39 +++++++++++---------------------------- 5 files changed, 25 insertions(+), 38 deletions(-) diff --git a/main.mk b/main.mk index 845df4beaa..d8c4c29168 100644 --- a/main.mk +++ b/main.mk @@ -593,6 +593,9 @@ soaktest: testfixture$(EXE) sqlite3$(EXE) fulltestonly: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/full.test +queryplantest: testfixture$(EXE) sqlite3$(EXE) + ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner + test: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/veryquick.test diff --git a/manifest b/manifest index c2a22a6d6e..9a336de116 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sautomatic\sindices\son\ssubqueries\sof\sthe\sFROM\sclause\swhen\sappropriate. -D 2013-06-17T14:18:21.734 +C Simplifications\sto\sthe\sNGQP.\s\sAdd\sthe\squeryplantest\smakefile\starget.\s\sAdd\ntestcase()\smacros\sin\sthe\sNGQP. +D 2013-06-17T18:20:48.993 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -138,7 +138,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d -F main.mk e536751ac719806209c51f5dc63022a5dd40c631 +F main.mk c4335dbdb004d37e00e23d6ff226e55df0db5b21 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -215,7 +215,7 @@ F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c 94a755b3d3788cf171c98064f2fa0ce6350fd6ca +F src/select.c d5a1b9bc3fb451e68ce907df253c6ac17e7310f7 F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 74ecd744a5a9d18cc8e66f4c234bdac11c472eee +F src/where.c 74627cb9415ad421004de574cfafe6ed0359554b F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 3e8ac46918c68723bd199dbec8b0901457d524a9 -R cb395ca086e8d43cd185b18cda8198f7 +P e8f124284ee0d0e373dc4431668630f1e17015c1 +R 5f6127cf4cee34c1f05fd60f463f5e2a U drh -Z 602d1da2f8b38f776a1f4f76f4cb8197 +Z 08d0c98ccbb424b49a424bc18bdd25d5 diff --git a/manifest.uuid b/manifest.uuid index b46fbe6550..2d08ee9b92 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e8f124284ee0d0e373dc4431668630f1e17015c1 \ No newline at end of file +eaf1f1b405ec2c498092527fae00e5dbe9e176c1 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 0c706bdbc2..40b7ec86f0 100644 --- a/src/select.c +++ b/src/select.c @@ -4401,7 +4401,8 @@ int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, + WHERE_GROUPBY, 0); if( pWInfo==0 ) goto select_end; if( sqlite3WhereIsOrdered(pWInfo) ){ /* The optimizer is able to deliver rows in group by order so diff --git a/src/where.c b/src/where.c index 0977dbea8d..cf55858f7e 100644 --- a/src/where.c +++ b/src/where.c @@ -4321,6 +4321,8 @@ static int whereLoopAddBtreeIndex( if( pNew->u.btree.nEq==1 && pProbe->nSample ){ tRowcnt nOut = 0; if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ + testcase( pTerm->eOperator & WO_EQ ); + testcase( pTerm->eOperator & WO_ISNULL ); rc = whereEqualScanEst(pParse, pProbe, pTerm->pExpr->pRight, &nOut); }else if( (pTerm->eOperator & WO_IN) && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ @@ -4861,7 +4863,6 @@ static int wherePathSatisfiesOrderBy( WherePath *pPath, /* The WherePath to check */ u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */ u16 nLoop, /* Number of entries in pPath->aLoop[] */ - u8 isLastLoop, /* True if pLast is the inner-most loop */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ ){ @@ -4946,6 +4947,8 @@ static int wherePathSatisfiesOrderBy( pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, WO_EQ|WO_ISNULL, 0); if( pTerm==0 ) continue; + testcase( pTerm->eOperator & WO_EQ ); + testcase( pTerm->eOperator & WO_ISNULL ); if( pOBExpr->iColumn>=0 ){ const char *z1, *z2; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); @@ -4970,30 +4973,6 @@ static int wherePathSatisfiesOrderBy( isOrderDistinct = pIndex->onError!=OE_None; } - /* For every term of the index that is constrained by == or IS NULL, - ** mark off corresponding ORDER BY terms wherever they occur - ** in the ORDER BY clause. - */ - for(i=0; iu.btree.nEq; i++){ - pTerm = pLoop->aLTerm[i]; - if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))==0 ) continue; - iColumn = pTerm->u.leftColumn; - for(j=0; ja[j].pExpr); - if( pOBExpr->op!=TK_COLUMN ) continue; - if( pOBExpr->iTable!=iCur ) continue; - if( pOBExpr->iColumn!=iColumn ) continue; - if( iColumn>=0 ){ - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[j].pExpr); - if( !pColl ) pColl = db->pDfltColl; - if( sqlite3StrICmp(pColl->zName, pIndex->azColl[i])!=0 ) continue; - } - obSat |= MASKBIT(j); - } - if( obSat==obDone ) return 1; - } - /* Loop through all columns of the index and deal with the ones ** that are not constrained by == or IN. */ @@ -5043,6 +5022,8 @@ static int wherePathSatisfiesOrderBy( for(i=0; bOnce && ia[i].pExpr); + testcase( wctrlFlags & WHERE_GROUPBY ); + testcase( wctrlFlags & WHERE_DISTINCTBY ); if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; @@ -5093,7 +5074,6 @@ static int wherePathSatisfiesOrderBy( } /* End the loop over all WhereLoops from outer-most down to inner-most */ if( obSat==obDone ) return 1; if( !isOrderDistinct ) return 0; - if( isLastLoop ) return 1; return -1; } @@ -5200,7 +5180,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ if( !isOrderedValid ){ switch( wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, - iLoop, iLoop==nLoop-1, pWLoop, &revMask) ){ + iLoop, pWLoop, &revMask) ){ case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ isOrdered = 1; isOrderedValid = 1; @@ -5326,9 +5306,12 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ /* Find the lowest cost path. pFrom will be left pointing to that path */ pFrom = aFrom; + assert( nFrom==1 ); +#if 0 /* The following is needed if nFrom is ever more than 1 */ for(ii=1; iirCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; } +#endif assert( pWInfo->nLevel==nLoop ); /* Load the lowest cost path into pWInfo */ for(iLoop=0; iLooppDistinct, pFrom, - WHERE_DISTINCTBY, nLoop-1, 1, pFrom->aLoop[nLoop-1], ¬Used); + WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } if( pFrom->isOrdered ){ From 7963b0e85321b7af85a632cab1c2e0b410adaf6a Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 17 Jun 2013 21:37:40 +0000 Subject: [PATCH 124/144] Add more testcase() macros. Fix a memory leak following OOM in the virtual table analysis logic. FossilOrigin-Name: b61402af690ac08b68974f3c807096b0cffd9bc0 --- manifest | 12 +++---- manifest.uuid | 2 +- src/where.c | 86 +++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 73 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 9a336de116..8f9dc7b011 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplifications\sto\sthe\sNGQP.\s\sAdd\sthe\squeryplantest\smakefile\starget.\s\sAdd\ntestcase()\smacros\sin\sthe\sNGQP. -D 2013-06-17T18:20:48.993 +C Add\smore\stestcase()\smacros.\s\sFix\sa\smemory\sleak\sfollowing\sOOM\sin\sthe\nvirtual\stable\sanalysis\slogic. +D 2013-06-17T21:37:40.990 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 74627cb9415ad421004de574cfafe6ed0359554b +F src/where.c b911a484d36d5dca41448e493974368d8147a2e1 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P e8f124284ee0d0e373dc4431668630f1e17015c1 -R 5f6127cf4cee34c1f05fd60f463f5e2a +P eaf1f1b405ec2c498092527fae00e5dbe9e176c1 +R 7a1603a9005d87a42c0df561c944734f U drh -Z 08d0c98ccbb424b49a424bc18bdd25d5 +Z 30a954d83fb3f9269803abab8ea42340 diff --git a/manifest.uuid b/manifest.uuid index 2d08ee9b92..a6139b6aec 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eaf1f1b405ec2c498092527fae00e5dbe9e176c1 \ No newline at end of file +b61402af690ac08b68974f3c807096b0cffd9bc0 \ No newline at end of file diff --git a/src/where.c b/src/where.c index cf55858f7e..e3ab83c592 100644 --- a/src/where.c +++ b/src/where.c @@ -2114,6 +2114,8 @@ static void constructAutomaticIndex( if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol = pTerm->u.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); + testcase( iCol==BMS-1 ); + testcase( iCol==BMS ); if( (idxCols & cMask)==0 ){ Expr *pX = pTerm->pExpr; idxCols |= cMask; @@ -3046,7 +3048,6 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ int *aiColumn = pIndex->aiColumn; StrAccum txt; - if( pIndex==0 ) return 0; if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ return 0; } @@ -3113,7 +3114,7 @@ static void explainOneScan( zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); } if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 - && pLoop->u.btree.pIndex!=0 + && ALWAYS(pLoop->u.btree.pIndex!=0) ){ char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg, @@ -3133,7 +3134,7 @@ static void explainOneScan( zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid?)", zMsg); - }else if( flags&WHERE_TOP_LIMIT ){ + }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowideOperator & WO_LE ); - testcase( pRangeStart && pRangeStart->eOperator & WO_GE ); - testcase( pRangeEnd && pRangeEnd->eOperator & WO_LE ); - testcase( pRangeEnd && pRangeEnd->eOperator & WO_GE ); + testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); + testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); start_constraints = pRangeStart || nEq>0; @@ -3889,6 +3890,8 @@ static Bitmask codeOneLoopStart( pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; + testcase( pAlt->eOperator & WO_EQ ); + testcase( pAlt->eOperator & WO_IN ); VdbeNoopComment((v, "begin transitive constraint")); sEq = *pAlt->pExpr; sEq.pLeft = pE->pLeft; @@ -4095,6 +4098,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereCost rCost = whereCostAdd(p->rRun,p->rSetup); WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup); if( rCost < rTemplate ){ + testcase( rCost==rTemplate-1 ); goto whereLoopInsert_noop; } if( rCost == rTemplate && p->prereq <= pTemplate->prereq ){ @@ -4120,6 +4124,8 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ && p->rSetup<=pTemplate->rSetup && p->rRun<=pTemplate->rRun ){ + testcase( p->rSetup==pTemplate->rSetup ); + testcase( p->rRun==pTemplate->rRun ); /* p is equal or better than pTemplate */ if( p->nLTermnLTerm && (p->wsFlags & WHERE_INDEXED)!=0 @@ -4145,14 +4151,26 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ goto whereLoopInsert_noop; } } + testcase( (p->prereq & pTemplate->prereq)==p->prereq + && p->rSetup==pTemplate->rSetup+1 ); + testcase( (p->prereq & pTemplate->prereq)==p->prereq + && p->rSetup<=pTemplate->rSetup + && p->rRun==pTemplate->rRun+1 ); if( (p->prereq & pTemplate->prereq)==pTemplate->prereq && p->rSetup>=pTemplate->rSetup && p->rRun>=pTemplate->rRun ){ /* Overwrite an existing WhereLoop with a better one */ + testcase( p->rSetup==pTemplate->rSetup ); + testcase( p->rRun==pTemplate->rRun ); pNext = p->pNextLoop; break; } + testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq + && p->rSetup==pTemplate->rSetup-1 ); + testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq + && p->rSetup>=pTemplate->rSetup-1 + && p->rRun==pTemplate->rRun-1 ); } /* If we reach this point it means that either p[] should be overwritten @@ -4231,7 +4249,6 @@ static int whereLoopAddBtreeIndex( if( db->mallocFailed ) return SQLITE_NOMEM; assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); - assert( pNew->u.btree.nEq<=pProbe->nColumn ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; @@ -4242,6 +4259,7 @@ static int whereLoopAddBtreeIndex( } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); + assert( pNew->u.btree.nEq<=pProbe->nColumn ); if( pNew->u.btree.nEq < pProbe->nColumn ){ iCol = pProbe->aiColumn[pNew->u.btree.nEq]; nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]); @@ -4301,10 +4319,15 @@ static int whereLoopAddBtreeIndex( nIn = 10; assert( 10==whereCost(2) ); pNew->nOut = nRowEst + nInMul + nIn; }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ + testcase( pTerm->eOperator & WO_GT ); + testcase( pTerm->eOperator & WO_GE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; pTop = 0; - }else if( pTerm->eOperator & (WO_LT|WO_LE) ){ + }else{ + assert( pTerm->eOperator & (WO_LT|WO_LE) ); + testcase( pTerm->eOperator & WO_LT ); + testcase( pTerm->eOperator & WO_LE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? @@ -4393,6 +4416,8 @@ static Bitmask columnsInIndex(Index *pIdx){ int j; for(j=pIdx->nColumn-1; j>=0; j--){ int x = pIdx->aiColumn[j]; + testcase( x==BMS-1 ); + testcase( x==BMS-2 ); if( xu.vtab.needFree = 0; pUsage = pIdxInfo->aConstraintUsage; nConstraint = pIdxInfo->nConstraint; - if( whereLoopResize(db, pNew, nConstraint) ) return SQLITE_NOMEM; + if( whereLoopResize(db, pNew, nConstraint) ){ + sqlite3DbFree(db, pIdxInfo); + return SQLITE_NOMEM; + } for(iPhase=0; iPhase<=3; iPhase++){ if( !seenIn && (iPhase&1)!=0 ){ @@ -4621,9 +4649,10 @@ static int whereLoopAddVirtual( pIdxCons->usable = 0; if( (pTerm->eOperator & WO_IN)!=0 ){ seenIn = 1; - }else if( pTerm->prereqRight!=0 ){ + } + if( pTerm->prereqRight!=0 ){ seenVar = 1; - }else{ + }else if( (pTerm->eOperator & WO_IN)==0 ){ pIdxCons->usable = 1; } break; @@ -4668,11 +4697,16 @@ static int whereLoopAddVirtual( sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName); goto whereLoopAddVtab_exit; } + testcase( iTerm==nConstraint-1 ); + testcase( j==0 ); + testcase( j==pWC->nTerm-1 ); pTerm = &pWC->a[j]; pNew->prereq |= pTerm->prereqRight; assert( iTermnLSlot ); pNew->aLTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; + testcase( iTerm==15 ); + testcase( iTerm==16 ); if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ if( pUsage[i].omit==0 ){ @@ -4923,6 +4957,7 @@ static int wherePathSatisfiesOrderBy( if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; nOrderBy = pOrderBy->nExpr; + testcase( nOrderBy==BMS-1 ); if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; @@ -4947,9 +4982,7 @@ static int wherePathSatisfiesOrderBy( pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, WO_EQ|WO_ISNULL, 0); if( pTerm==0 ) continue; - testcase( pTerm->eOperator & WO_EQ ); - testcase( pTerm->eOperator & WO_ISNULL ); - if( pOBExpr->iColumn>=0 ){ + if( (pTerm->eOperator&WO_EQ)!=0 && pOBExpr->iColumn>=0 ){ const char *z1, *z2; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; @@ -4985,7 +5018,10 @@ static int wherePathSatisfiesOrderBy( if( ju.btree.nEq && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 ){ - if( i & WO_ISNULL ) isOrderDistinct = 0; + if( i & WO_ISNULL ){ + testcase( isOrderDistinct ); + isOrderDistinct = 0; + } continue; } @@ -4999,6 +5035,7 @@ static int wherePathSatisfiesOrderBy( if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; }else{ /* The ROWID column at the end */ + assert( j==nColumn ); iColumn = -1; revIdx = 0; } @@ -5037,7 +5074,10 @@ static int wherePathSatisfiesOrderBy( break; } if( isMatch ){ - if( iColumn<0 ) distinctColumns = 1; + if( iColumn<0 ){ + testcase( distinctColumns==0 ); + distinctColumns = 1; + } obSat |= MASKBIT(i); if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ /* Make sure the sort order is compatible in an ORDER BY clause. @@ -5052,7 +5092,10 @@ static int wherePathSatisfiesOrderBy( } }else{ /* No match found */ - if( j==0 || jmaskLoop==maskNew && pTo->isOrderedValid==isOrderedValid ){ + testcase( jj==nTo-1 ); break; } } @@ -5242,8 +5286,10 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); } #endif + testcase( pTo->rCost==rCost ); continue; } + testcase( pTo->rCost==rCost+1 ); /* A new and better score for a previously created equivalent path */ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace&0x4 ){ @@ -5779,8 +5825,8 @@ WhereInfo *sqlite3WhereBegin( && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); - testcase( pTab->nCol==BMS-1 ); - testcase( pTab->nCol==BMS ); + testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 ); + testcase( !pWInfo->okOnePass && pTab->nCol==BMS ); if( !pWInfo->okOnePass && pTab->nColcolUsed; int n = 0; From 81186b4392bd2710d4e8761f0fa097da68c69430 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 18 Jun 2013 01:52:41 +0000 Subject: [PATCH 125/144] Remove some redundant and unreachable code. FossilOrigin-Name: 4c6d58d75d51e1ce829aec214617c3a89e784a2d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 19 +++++++++---------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 8f9dc7b011..56a8a23589 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\smore\stestcase()\smacros.\s\sFix\sa\smemory\sleak\sfollowing\sOOM\sin\sthe\nvirtual\stable\sanalysis\slogic. -D 2013-06-17T21:37:40.990 +C Remove\ssome\sredundant\sand\sunreachable\scode. +D 2013-06-18T01:52:41.578 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c b911a484d36d5dca41448e493974368d8147a2e1 +F src/where.c 86cc9705ef7de9ef712619485d3bff3910d58b12 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P eaf1f1b405ec2c498092527fae00e5dbe9e176c1 -R 7a1603a9005d87a42c0df561c944734f +P b61402af690ac08b68974f3c807096b0cffd9bc0 +R ddde8ef3fd559d48220a86d476077d7b U drh -Z 30a954d83fb3f9269803abab8ea42340 +Z a276f283a2c7c1a652996ed6754c6f02 diff --git a/manifest.uuid b/manifest.uuid index a6139b6aec..f73027ac71 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b61402af690ac08b68974f3c807096b0cffd9bc0 \ No newline at end of file +4c6d58d75d51e1ce829aec214617c3a89e784a2d \ No newline at end of file diff --git a/src/where.c b/src/where.c index e3ab83c592..800194c6ef 100644 --- a/src/where.c +++ b/src/where.c @@ -2041,7 +2041,6 @@ static void constructAutomaticIndex( WhereLoop *pLoop; /* The Loop object */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ - const int mxConstraint = 10; /* Maximum number of constraints */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ @@ -2056,7 +2055,7 @@ static void constructAutomaticIndex( pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; - for(pTerm=pWC->a; pTermnLTerma; pTermu.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); @@ -3305,6 +3304,7 @@ static Bitmask codeOneLoopStart( pStart = pEnd = 0; if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; + assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; pStart = pEnd; @@ -3359,11 +3359,7 @@ static Bitmask codeOneLoopStart( pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; - if( pStart==0 && pEnd==0 ){ - pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; - }else{ - assert( pLevel->p5==0 ); - } + assert( pLevel->p5==0 ); if( testOp!=OP_Noop ){ iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); @@ -3798,8 +3794,8 @@ static Bitmask codeOneLoopStart( ** be available. */ pSubLoop = pSubWInfo->a[0].pWLoop; + assert( (pSubLoop->wsFlags & WHERE_TEMP_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 - && (pSubLoop->wsFlags & WHERE_TEMP_INDEX)==0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); @@ -5099,7 +5095,10 @@ static int wherePathSatisfiesOrderBy( break; } } /* end Loop over all index columns */ - if( distinctColumns ) isOrderDistinct = 1; + if( distinctColumns ){ + testcase( isOrderDistinct==0 ); + isOrderDistinct = 1; + } } /* end-if not one-row */ /* Mark off any other ORDER BY terms that reference pLoop */ @@ -5749,7 +5748,7 @@ WhereInfo *sqlite3WhereBegin( if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ pWInfo->revMask = (Bitmask)(-1); } - if( pParse->nErr || db->mallocFailed ){ + if( pParse->nErr || NEVER(db->mallocFailed) ){ goto whereBeginError; } #ifdef WHERETRACE_ENABLED From 4a5acf8e5ce52face22d05831453e7d8fb78574e Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 18 Jun 2013 20:06:23 +0000 Subject: [PATCH 126/144] Adjustments to testcase() macros for improved testability. FossilOrigin-Name: 4fbb0c4d26c54aaefbe5397cde2a0b9d2ce3885f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 4 ++-- src/where.c | 18 ++++++++---------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 56a8a23589..3817eca13b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\ssome\sredundant\sand\sunreachable\scode. -D 2013-06-18T01:52:41.578 +C Adjustments\sto\stestcase()\smacros\sfor\simproved\stestability. +D 2013-06-18T20:06:23.048 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -171,7 +171,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778 -F src/expr.c 9cc9e4c85197b567e5f97f3296700faf7747810f +F src/expr.c 3286e703adde34865d3a2cb62f9f4f31e3d2f2ed F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179 F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 86cc9705ef7de9ef712619485d3bff3910d58b12 +F src/where.c 85b7b80a350951444c8e3e45bf2f7e6cc6d34683 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b61402af690ac08b68974f3c807096b0cffd9bc0 -R ddde8ef3fd559d48220a86d476077d7b +P 4c6d58d75d51e1ce829aec214617c3a89e784a2d +R f77d52adfdd29eb20a93333ac0fbc3fa U drh -Z a276f283a2c7c1a652996ed6754c6f02 +Z e0df54c8e9d824f28c0e34a1e5fe6134 diff --git a/manifest.uuid b/manifest.uuid index f73027ac71..cf33cbf052 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4c6d58d75d51e1ce829aec214617c3a89e784a2d \ No newline at end of file +4fbb0c4d26c54aaefbe5397cde2a0b9d2ce3885f \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 4e834ffe8e..d066e9b8bc 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1603,8 +1603,8 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ *prNotFound = rMayHaveNull = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); }else{ - testcase( pParse->nQueryLoop>1 ); - pParse->nQueryLoop = 1; + testcase( pParse->nQueryLoop>0 ); + pParse->nQueryLoop = 0; if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } diff --git a/src/where.c b/src/where.c index 800194c6ef..dc4a515b90 100644 --- a/src/where.c +++ b/src/where.c @@ -4097,7 +4097,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ testcase( rCost==rTemplate-1 ); goto whereLoopInsert_noop; } - if( rCost == rTemplate && p->prereq <= pTemplate->prereq ){ + if( rCost==rTemplate && (p->prereq & pTemplate->prereq)==p->prereq ){ goto whereLoopInsert_noop; } } @@ -4120,9 +4120,9 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ && p->rSetup<=pTemplate->rSetup && p->rRun<=pTemplate->rRun ){ - testcase( p->rSetup==pTemplate->rSetup ); + /* This branch taken when p is equal or better than pTemplate in + ** all of (1) dependences (2) setup-cost, and (3) run-cost. */ testcase( p->rRun==pTemplate->rRun ); - /* p is equal or better than pTemplate */ if( p->nLTermnLTerm && (p->wsFlags & WHERE_INDEXED)!=0 && (pTemplate->wsFlags & WHERE_INDEXED)!=0 @@ -4147,8 +4147,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ goto whereLoopInsert_noop; } } - testcase( (p->prereq & pTemplate->prereq)==p->prereq - && p->rSetup==pTemplate->rSetup+1 ); testcase( (p->prereq & pTemplate->prereq)==p->prereq && p->rSetup<=pTemplate->rSetup && p->rRun==pTemplate->rRun+1 ); @@ -4156,16 +4154,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ && p->rSetup>=pTemplate->rSetup && p->rRun>=pTemplate->rRun ){ - /* Overwrite an existing WhereLoop with a better one */ + /* Overwrite an existing WhereLoop with a better one: one that is + ** better at one of (1) dependences, (2) setup-cost, or (3) run-cost + ** and is no worse in any of those categories. */ testcase( p->rSetup==pTemplate->rSetup ); testcase( p->rRun==pTemplate->rRun ); pNext = p->pNextLoop; break; } testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq - && p->rSetup==pTemplate->rSetup-1 ); - testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq - && p->rSetup>=pTemplate->rSetup-1 + && p->rSetup>=pTemplate->rSetup && p->rRun==pTemplate->rRun-1 ); } @@ -4303,7 +4301,7 @@ static int whereLoopAddBtreeIndex( || (pProbe->onError!=OE_None && nInMul==0 && pNew->u.btree.nEq==pProbe->nColumn-1) ){ - testcase( pNew->wsFlags & WHERE_COLUMN_IN ); + assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 ); pNew->wsFlags |= WHERE_ONEROW; } pNew->u.btree.nEq++; From c7f0d229a7c9f56f0f7f79eee0d69d3f1b54fc78 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 19 Jun 2013 03:27:12 +0000 Subject: [PATCH 127/144] Fix compiler warnings. Fix a harmless off-by-one error in the solver. FossilOrigin-Name: 10021941d0258951b916e788881df140113f0597 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/prepare.c | 4 ++-- src/where.c | 15 +++++++++++---- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 3817eca13b..d232347684 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adjustments\sto\stestcase()\smacros\sfor\simproved\stestability. -D 2013-06-18T20:06:23.048 +C Fix\scompiler\swarnings.\s\sFix\sa\sharmless\soff-by-one\serror\sin\sthe\ssolver. +D 2013-06-19T03:27:12.614 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -210,7 +210,7 @@ F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938 F src/pragma.c 67a611bd4be0754f27ee13eb87932c3b14415862 -F src/prepare.c 213de4aae5e29cfbb32202d1c09f4fc4b5a51b09 +F src/prepare.c 2306be166bbeddf454e18bf8b21dba8388d05328 F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 85b7b80a350951444c8e3e45bf2f7e6cc6d34683 +F src/where.c 5cc059bd283fe9f99800270c797fabdcbef8009a F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 4c6d58d75d51e1ce829aec214617c3a89e784a2d -R f77d52adfdd29eb20a93333ac0fbc3fa +P 4fbb0c4d26c54aaefbe5397cde2a0b9d2ce3885f +R dae7f42197a8d862e7c14dd3769614f8 U drh -Z e0df54c8e9d824f28c0e34a1e5fe6134 +Z e26ab5beb4ba36d99e52a8a301bdec10 diff --git a/manifest.uuid b/manifest.uuid index cf33cbf052..011a8dd71f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4fbb0c4d26c54aaefbe5397cde2a0b9d2ce3885f \ No newline at end of file +10021941d0258951b916e788881df140113f0597 \ No newline at end of file diff --git a/src/prepare.c b/src/prepare.c index 319bb5012e..28145aa4e7 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -592,7 +592,7 @@ static int sqlite3Prepare( sqlite3VtabUnlockList(db); pParse->db = db; - pParse->nQueryLoop = 1; + pParse->nQueryLoop = 0; /* Logarithmic, so 0 really means 1 */ if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -614,7 +614,7 @@ static int sqlite3Prepare( }else{ sqlite3RunParser(pParse, zSql, &zErrMsg); } - assert( 1==pParse->nQueryLoop ); + assert( 0==pParse->nQueryLoop ); if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM; diff --git a/src/where.c b/src/where.c index dc4a515b90..73fdcaa431 100644 --- a/src/where.c +++ b/src/where.c @@ -4237,7 +4237,7 @@ static int whereLoopAddBtreeIndex( int rc = SQLITE_OK; /* Return code */ WhereCost nRowEst; /* Estimated index selectivity */ WhereCost rLogSize; /* Logarithm of table size */ - WhereTerm *pTop, *pBtm; /* Top and bottom range constraints */ + WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM; @@ -4257,6 +4257,7 @@ static int whereLoopAddBtreeIndex( if( pNew->u.btree.nEq < pProbe->nColumn ){ iCol = pProbe->aiColumn[pNew->u.btree.nEq]; nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]); + if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1; }else{ iCol = -1; nRowEst = 0; @@ -4786,7 +4787,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ sSubBuild.pOrderBy = 0; sSubBuild.pBest = &sBest; - for(pOrTerm=pOrWC->a; rc==SQLITE_OK && pOrTerma; pOrTermeOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; }else if( pOrTerm->leftCursor==iCur ){ @@ -4810,6 +4811,8 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ { rc = whereLoopAddBtree(&sSubBuild, mExtra); } + /* sBest.maskSelf is always zero if an error occurs */ + assert( rc==SQLITE_OK || sBest.maskSelf==0 ); if( sBest.maskSelf==0 ) break; assert( sBest.rSetup==0 ); rTotal = whereCostAdd(rTotal, sBest.rRun); @@ -5135,6 +5138,10 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ ** attempts to find the lowest cost path that visits each WhereLoop ** once. This path is then loaded into the pWInfo->a[].pWLoop fields. ** +** Assume that the total number of output rows that will need to be sorted +** will be nRowEst (in the 10*log2 representation). Or, ignore sorting +** costs if nRowEst==0. +** ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation ** error occurs. */ @@ -5146,7 +5153,7 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ WhereCost rCost; /* Cost of a path */ - WhereCost mxCost; /* Maximum cost of a set of paths */ + WhereCost mxCost = 0; /* Maximum cost of a set of paths */ WhereCost rSortCost; /* Cost to do a sort */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ @@ -5739,7 +5746,7 @@ WhereInfo *sqlite3WhereBegin( wherePathSolver(pWInfo, 0); if( db->mallocFailed ) goto whereBeginError; if( pWInfo->pOrderBy ){ - wherePathSolver(pWInfo, pWInfo->nRowOut); + wherePathSolver(pWInfo, pWInfo->nRowOut+1); if( db->mallocFailed ) goto whereBeginError; } } From dbb80234dabefcb518fb09fa073b6b09bd30f3af Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 19 Jun 2013 12:34:13 +0000 Subject: [PATCH 128/144] Simplify and add invariants to the WhereLoop merging logic inside of whereLoopInsert(). FossilOrigin-Name: 8f27f35f288434b9e7bc503c608f1e2b590ade4d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 38 +++++++++++++++++++------------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index d232347684..37bf8cca81 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scompiler\swarnings.\s\sFix\sa\sharmless\soff-by-one\serror\sin\sthe\ssolver. -D 2013-06-19T03:27:12.614 +C Simplify\sand\sadd\sinvariants\sto\sthe\sWhereLoop\smerging\slogic\sinside\sof\nwhereLoopInsert(). +D 2013-06-19T12:34:13.186 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 5cc059bd283fe9f99800270c797fabdcbef8009a +F src/where.c e5ecc3d12c5b9d66d13f786e80641614530d1957 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 4fbb0c4d26c54aaefbe5397cde2a0b9d2ce3885f -R dae7f42197a8d862e7c14dd3769614f8 +P 10021941d0258951b916e788881df140113f0597 +R 38e2e388820d13ceac39bea07ba5a7cc U drh -Z e26ab5beb4ba36d99e52a8a301bdec10 +Z 087e132035ea5a36d1e5d81e4344a21a diff --git a/manifest.uuid b/manifest.uuid index 011a8dd71f..8aac6362f2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -10021941d0258951b916e788881df140113f0597 \ No newline at end of file +8f27f35f288434b9e7bc503c608f1e2b590ade4d \ No newline at end of file diff --git a/src/where.c b/src/where.c index 73fdcaa431..2626306c24 100644 --- a/src/where.c +++ b/src/where.c @@ -4115,14 +4115,30 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** priority over pTemplate. */ for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ - if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ) continue; + 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( (p->prereq & pTemplate->prereq)==p->prereq && p->rSetup<=pTemplate->rSetup && p->rRun<=pTemplate->rRun ){ /* This branch taken when p is equal or better than pTemplate in ** all of (1) dependences (2) setup-cost, and (3) run-cost. */ - testcase( p->rRun==pTemplate->rRun ); + assert( p->rSetup==pTemplate->rSetup ); if( p->nLTermnLTerm && (p->wsFlags & WHERE_INDEXED)!=0 && (pTemplate->wsFlags & WHERE_INDEXED)!=0 @@ -4133,38 +4149,22 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** more terms of the index */ pNext = p->pNextLoop; break; - }else if( p->nOut>pTemplate->nOut - && p->rSetup==pTemplate->rSetup - && p->rRun==pTemplate->rRun - ){ - /* Overwrite an existing WhereLoop with the same cost but more - ** outputs */ - pNext = p->pNextLoop; - break; }else{ /* pTemplate is not helpful. ** Return without changing or adding anything */ goto whereLoopInsert_noop; } } - testcase( (p->prereq & pTemplate->prereq)==p->prereq - && p->rSetup<=pTemplate->rSetup - && p->rRun==pTemplate->rRun+1 ); if( (p->prereq & pTemplate->prereq)==pTemplate->prereq - && p->rSetup>=pTemplate->rSetup && p->rRun>=pTemplate->rRun + && ALWAYS(p->rSetup>=pTemplate->rSetup) /* See SETUP-INVARIANT above */ ){ /* Overwrite an existing WhereLoop with a better one: one that is ** better at one of (1) dependences, (2) setup-cost, or (3) run-cost ** and is no worse in any of those categories. */ - testcase( p->rSetup==pTemplate->rSetup ); - testcase( p->rRun==pTemplate->rRun ); pNext = p->pNextLoop; break; } - testcase( (p->prereq & pTemplate->prereq)==pTemplate->prereq - && p->rSetup>=pTemplate->rSetup - && p->rRun==pTemplate->rRun-1 ); } /* If we reach this point it means that either p[] should be overwritten From e8ae583ebd689f6c95cf29cfe4f474366a7613dd Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 19 Jun 2013 13:32:46 +0000 Subject: [PATCH 129/144] Fix a harmless uninitialized variable warning. FossilOrigin-Name: 9d3ef3bd2c6281784a537a22a87279f420649935 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 37bf8cca81..cb3eff1fbd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplify\sand\sadd\sinvariants\sto\sthe\sWhereLoop\smerging\slogic\sinside\sof\nwhereLoopInsert(). -D 2013-06-19T12:34:13.186 +C Fix\sa\sharmless\suninitialized\svariable\swarning. +D 2013-06-19T13:32:46.775 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c e5ecc3d12c5b9d66d13f786e80641614530d1957 +F src/where.c 0d12d709b410bc19e6a38dd48565d01aa2157a48 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 10021941d0258951b916e788881df140113f0597 -R 38e2e388820d13ceac39bea07ba5a7cc +P 8f27f35f288434b9e7bc503c608f1e2b590ade4d +R 5141bf3c3afc19733578e654fa12a0bb U drh -Z 087e132035ea5a36d1e5d81e4344a21a +Z f8bc370f664ab6cce8282fa162fbfbcd diff --git a/manifest.uuid b/manifest.uuid index 8aac6362f2..c36b341294 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f27f35f288434b9e7bc503c608f1e2b590ade4d \ No newline at end of file +9d3ef3bd2c6281784a537a22a87279f420649935 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 2626306c24..7b7b071b41 100644 --- a/src/where.c +++ b/src/where.c @@ -4909,7 +4909,7 @@ static int wherePathSatisfiesOrderBy( int i, j; /* Loop counters */ int iCur; /* Cursor number for current WhereLoop */ int iColumn; /* A column number within table iCur */ - WhereLoop *pLoop; /* Current WhereLoop being processed. */ + WhereLoop *pLoop = 0; /* Current WhereLoop being processed. */ WhereTerm *pTerm; /* A single term of the WHERE clause */ Expr *pOBExpr; /* An expression from the ORDER BY clause */ CollSeq *pColl; /* COLLATE function from an ORDER BY clause term */ From ad01d892a702ba66b578f512efa660680bc0d6bd Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 19 Jun 2013 13:59:49 +0000 Subject: [PATCH 130/144] Additional compiler warning fixes. FossilOrigin-Name: 8d2ae8e2f343f82f6fba6d0e89cee7f15b444aa3 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 4 ++-- src/where.c | 7 +++---- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index cb3eff1fbd..a1804c7bf0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sharmless\suninitialized\svariable\swarning. -D 2013-06-19T13:32:46.775 +C Additional\scompiler\swarning\sfixes. +D 2013-06-19T13:59:49.313 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -165,7 +165,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c 7fba377c29573adfc6091832e27ee1fcbefb51d0 F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 -F src/build.c eadda12ec0cae14dcdc13e97fd9a3fd2f02e9e8f +F src/build.c 42239cfd95533e4aacf4d58b4724c8f858de5ced F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 0d12d709b410bc19e6a38dd48565d01aa2157a48 +F src/where.c 88884f3a0355ece00fa0d1a3566c4ed6fb5a8bed F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 8f27f35f288434b9e7bc503c608f1e2b590ade4d -R 5141bf3c3afc19733578e654fa12a0bb +P 9d3ef3bd2c6281784a537a22a87279f420649935 +R 576d65f25fc5d448aeaee421b4a0d4ef U drh -Z f8bc370f664ab6cce8282fa162fbfbcd +Z 2fbaa2eda000406e9f5d447a3a6c804c diff --git a/manifest.uuid b/manifest.uuid index c36b341294..350fdf4563 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9d3ef3bd2c6281784a537a22a87279f420649935 \ No newline at end of file +8d2ae8e2f343f82f6fba6d0e89cee7f15b444aa3 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 94fafff9fd..0a3922c952 100644 --- a/src/build.c +++ b/src/build.c @@ -3187,7 +3187,7 @@ SrcList *sqlite3SrcListEnlarge( } pSrc = pNew; nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1; - pSrc->nAlloc = (u16)nGot; + pSrc->nAlloc = (u8)nGot; } /* Move existing slots that come after the newly inserted slots @@ -3195,7 +3195,7 @@ SrcList *sqlite3SrcListEnlarge( for(i=pSrc->nSrc-1; i>=iStart; i--){ pSrc->a[i+nExtra] = pSrc->a[i]; } - pSrc->nSrc += (i16)nExtra; + pSrc->nSrc += (i8)nExtra; /* Zero the newly allocated slots */ memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra); diff --git a/src/where.c b/src/where.c index 7b7b071b41..f1cee90de1 100644 --- a/src/where.c +++ b/src/where.c @@ -883,7 +883,7 @@ WhereTerm *whereScanNext(WhereScan *pScan){ } } } - pWC = pScan->pWC = pScan->pWC->pOuter; + pScan->pWC = pScan->pWC->pOuter; k = 0; } pScan->pWC = pScan->pOrigWC; @@ -3433,7 +3433,6 @@ static Bitmask codeOneLoopStart( pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; - k = (nEq==pIdx->nColumn ? -1 : pIdx->aiColumn[nEq]); /* If this loop satisfies a sort order (pOrderBy) request that ** was passed to this function to implement a "SELECT min(x) ..." @@ -3687,7 +3686,7 @@ static Bitmask codeOneLoopStart( pOrTab = sqlite3StackAllocRaw(pParse->db, sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); if( pOrTab==0 ) return notReady; - pOrTab->nAlloc = (i16)(nNotReady + 1); + pOrTab->nAlloc = (u8)(nNotReady + 1); pOrTab->nSrc = pOrTab->nAlloc; memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); origSrc = pWInfo->pTabList->a; @@ -4346,7 +4345,7 @@ static int whereLoopAddBtreeIndex( && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut); } - pNew->nOut = whereCost(nOut); + if( rc==SQLITE_OK ) pNew->nOut = whereCost(nOut); } #endif if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ From 7fb1b3011870ff7b71084ff0a2a96b5f157b0844 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 19 Jun 2013 14:28:34 +0000 Subject: [PATCH 131/144] Only enable posix_fallocate by default on linux and mac. FossilOrigin-Name: b9b30d4f9845d212e2d3206abbf2795099e5d71d --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os_unix.c | 3 +-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index dbb20a50de..3d40b02bd2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_FTS3_MAX_EXPR_DEPTH\scompile\stime\soption. -D 2013-06-11T14:22:11.456 +C Only\senable\sposix_fallocate\sby\sdefault\son\slinux\sand\smac. +D 2013-06-19T14:28:34.073 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -201,7 +201,7 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c 42c9b8b7c61c9fa3561258f523be5749e52ed0e0 +F src/os_unix.c 4b19844690e2cc044ec55338818efd53d4f2e33e F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b F src/pager.c 79df56da9dd49aceaa4cac207484a9a82cba40ae F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7e3820e5b989426c64af46f6bf862b91366ae954 -R 5f94a46cd24d5603b852ca86ea7eaf5a -U dan -Z 30f6897d1a48f4a9b1a79c1749e033ce +P 24fc9d4438a5615dd20af5419456166df83a72ea +R 298aea423f152d3f9fd68c724c491cd3 +U drh +Z 1d3faaf5004dcac98d19efaebf760ffc diff --git a/manifest.uuid b/manifest.uuid index 87e2685a16..098c1ea845 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -24fc9d4438a5615dd20af5419456166df83a72ea \ No newline at end of file +b9b30d4f9845d212e2d3206abbf2795099e5d71d \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 242c2a3c3b..bc1b44cb2d 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -48,8 +48,7 @@ /* Use posix_fallocate() if it is available */ -#if !defined(HAVE_POSIX_FALLOCATE) \ - && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L) +#if defined(__linux__) || defined(__APPLE__) # define HAVE_POSIX_FALLOCATE 1 #endif From 2daffdf0b522c1d504c7da25c51038dd93db2499 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 19 Jun 2013 14:49:14 +0000 Subject: [PATCH 132/144] Only default HAVE_POSIX_FALLOCATE on for linux, and then only if it is not previously defined. FossilOrigin-Name: 2b2ade92788be623af6f57e37d98994be2cec142 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_unix.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 3d40b02bd2..aab16234de 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Only\senable\sposix_fallocate\sby\sdefault\son\slinux\sand\smac. -D 2013-06-19T14:28:34.073 +C Only\sdefault\sHAVE_POSIX_FALLOCATE\son\sfor\slinux,\sand\sthen\sonly\sif\sit\sis\snot\npreviously\sdefined. +D 2013-06-19T14:49:14.627 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -201,7 +201,7 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c 4b19844690e2cc044ec55338818efd53d4f2e33e +F src/os_unix.c a4c49f855cfd0783d7027a5e20dab6bb10fe4e4b F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b F src/pager.c 79df56da9dd49aceaa4cac207484a9a82cba40ae F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 24fc9d4438a5615dd20af5419456166df83a72ea -R 298aea423f152d3f9fd68c724c491cd3 +P b9b30d4f9845d212e2d3206abbf2795099e5d71d +R 051331ae49dcb9481117487fe2ddd3f7 U drh -Z 1d3faaf5004dcac98d19efaebf760ffc +Z f091211d6e3ac84847a4aa6c11062c5e diff --git a/manifest.uuid b/manifest.uuid index 098c1ea845..edfc6bc72c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b9b30d4f9845d212e2d3206abbf2795099e5d71d \ No newline at end of file +2b2ade92788be623af6f57e37d98994be2cec142 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index bc1b44cb2d..e4382cbff9 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -48,7 +48,7 @@ /* Use posix_fallocate() if it is available */ -#if defined(__linux__) || defined(__APPLE__) +#if !defined(HAVE_POSIX_FALLOCATE) && defined(__linux__) # define HAVE_POSIX_FALLOCATE 1 #endif From 74f91d446213475d5880ecbf6428291796f42d26 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 19 Jun 2013 18:01:44 +0000 Subject: [PATCH 133/144] Add in the cost of doing a table lookup on OR searches. Make test case changes to deal with difference in STAT3 behavior. FossilOrigin-Name: d97898e8e3990ae8c1882c9102b57692d8810730 --- manifest | 14 +++++------ manifest.uuid | 2 +- src/where.c | 10 ++++---- test/where9.test | 63 ++++++++++++++++++++++++++++++++---------------- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/manifest b/manifest index a1804c7bf0..b27c436553 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Additional\scompiler\swarning\sfixes. -D 2013-06-19T13:59:49.313 +C Add\sin\sthe\scost\sof\sdoing\sa\stable\slookup\son\sOR\ssearches.\s\sMake\stest\scase\nchanges\sto\sdeal\swith\sdifference\sin\sSTAT3\sbehavior. +D 2013-06-19T18:01:44.089 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 88884f3a0355ece00fa0d1a3566c4ed6fb5a8bed +F src/where.c ac9f8c4ee8ece1e8a4c93802792dbb0d629a7fa0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1039,7 +1039,7 @@ F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8 F test/where8.test f6b9559723564a042927ee0f22003ac9bed71b21 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 -F test/where9.test f5752185fc19a1ee826a2386a249f05dbc25979b +F test/where9.test 9a7fda4a4512abc26a855e8b2b6572b200f6019b F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 9d3ef3bd2c6281784a537a22a87279f420649935 -R 576d65f25fc5d448aeaee421b4a0d4ef +P 8d2ae8e2f343f82f6fba6d0e89cee7f15b444aa3 +R f44808387531e19eca9d858ab5ea40e0 U drh -Z 2fbaa2eda000406e9f5d447a3a6c804c +Z 1152d5230daa64158b83c69b1e514ae0 diff --git a/manifest.uuid b/manifest.uuid index 350fdf4563..6cc8090fec 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8d2ae8e2f343f82f6fba6d0e89cee7f15b444aa3 \ No newline at end of file +d97898e8e3990ae8c1882c9102b57692d8810730 \ No newline at end of file diff --git a/src/where.c b/src/where.c index f1cee90de1..b7dab2105d 100644 --- a/src/where.c +++ b/src/where.c @@ -630,8 +630,8 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ ** the WhereClause.a[] array. The slot[] array grows as needed to contain ** all terms of the WHERE clause. */ -static void whereSplit(WhereClause *pWC, Expr *pExpr, int op){ - pWC->op = (u8)op; +static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ + pWC->op = op; if( pExpr==0 ) return; if( pExpr->op!=op ){ whereClauseInsert(pWC, pExpr, 0); @@ -4516,6 +4516,7 @@ static int whereLoopAddBtree( pNew->iSortIdx = 0; pNew->rSetup = 0; pNew->prereq = mExtra; + pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ @@ -4526,7 +4527,6 @@ static int whereLoopAddBtree( /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; - pNew->nOut = rSize; /* TUNING: Cost of full table scan is 3*(N + log2(N)). ** + The extra 3 factor is to encourage the use of indexed lookups ** over full scans. A smaller constant 2 is used for covering @@ -4549,7 +4549,6 @@ static int whereLoopAddBtree( ) ){ pNew->iSortIdx = b ? iSortIdx : 0; - pNew->nOut = rSize; if( m==0 ){ /* TUNING: Cost of a covering index scan is 2*(N + log2(N)). ** + The extra 2 factor is to encourage the use of indexed lookups @@ -4824,7 +4823,8 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew->aLTerm[0] = pTerm; pNew->wsFlags = WHERE_MULTI_OR; pNew->rSetup = 0; - pNew->rRun = rTotal; + /* TUNING: Multiple by 3.5 for the secondary table lookup */ + pNew->rRun = rTotal + 18; assert( 18==whereCost(7)-whereCost(2) ); pNew->nOut = nRow; pNew->prereq = prereq; memset(&pNew->u, 0, sizeof(pNew->u)); diff --git a/test/where9.test b/test/where9.test index 4ffcad1470..5b000d967e 100644 --- a/test/where9.test +++ b/test/where9.test @@ -598,7 +598,7 @@ do_test where9-6.3.5 { OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 0 sort 0} ;# DELETEs rows 90 91 92 97 +} {scan 98 sort 0} ;# DELETEs rows 90 91 92 97 do_test where9-6.3.6 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -615,7 +615,7 @@ do_test where9-6.3.7 { OR (b NOT NULL AND +c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 0 sort 0} ;# Add 100 to rowids 90 91 92 97 +} {scan 98 sort 0} ;# Add 100 to rowids 90 91 92 97 do_test where9-6.3.8 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -705,7 +705,7 @@ do_test where9-6.6.1 { OR (b NOT NULL AND +c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 0 sort 0} ;# DELETEs rows 90 91 92 97 +} {scan 98 sort 0} ;# DELETEs rows 90 91 92 97 do_test where9-6.6.2 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -722,7 +722,7 @@ do_test where9-6.6.3 { OR (b NOT NULL AND +c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } -} {scan 0 sort 0} ;# Add 100 to rowids 90 91 92 97 +} {scan 98 sort 0} ;# Add 100 to rowids 90 91 92 97 do_test where9-6.6.4 { db eval { SELECT count(*) FROM t1 UNION ALL @@ -781,23 +781,44 @@ do_test where9-6.8.2 { OR (b NOT NULL AND c NOT NULL AND d IS NULL) } } {1 {no query solution}} -do_test where9-6.8.3 { - catchsql { - UPDATE t1 INDEXED BY t1b SET a=a+100 - WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) - OR (b NOT NULL AND c IS NULL AND d NOT NULL) - OR (b NOT NULL AND c NOT NULL AND d IS NULL) - } -} {0 {}} -do_test where9-6.8.4 { - catchsql { - DELETE FROM t1 INDEXED BY t1b - WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) - OR (b NOT NULL AND c IS NULL AND d NOT NULL) - OR (b NOT NULL AND c NOT NULL AND d IS NULL) - } -} {0 {}} - +ifcapable stat3 { + # When STAT3 is enabled, the "b NOT NULL" terms get translated + # into b>NULL, which can be satified by the index t1b. It is a very + # expensive way to do the query, but it works, and so a solution is possible. + do_test where9-6.8.3-stat3 { + catchsql { + UPDATE t1 INDEXED BY t1b SET a=a+100 + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {0 {}} + do_test where9-6.8.4-stat3 { + catchsql { + DELETE FROM t1 INDEXED BY t1b + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {0 {}} +} else { + do_test where9-6.8.3 { + catchsql { + UPDATE t1 INDEXED BY t1b SET a=a+100 + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {1 {no query solution}} + do_test where9-6.8.4 { + catchsql { + DELETE FROM t1 INDEXED BY t1b + WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) + OR (b NOT NULL AND c IS NULL AND d NOT NULL) + OR (b NOT NULL AND c NOT NULL AND d IS NULL) + } + } {1 {no query solution}} +} ############################################################################ # Test cases where terms inside an OR series are combined with AND terms # external to the OR clause. In other words, cases where From b01e5b59a2e471d468e1854ef4de4b8f54f3bd6c Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 20 Jun 2013 14:07:37 +0000 Subject: [PATCH 134/144] Disable posix_fallocate() for all systems, all the time, unless the HAVE_POSIX_FALLOCATE compile-time macro is supplied. FossilOrigin-Name: b674462243138fcee192ef05d434665e30c681c4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_unix.c | 6 ------ 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index aab16234de..4b1070228c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Only\sdefault\sHAVE_POSIX_FALLOCATE\son\sfor\slinux,\sand\sthen\sonly\sif\sit\sis\snot\npreviously\sdefined. -D 2013-06-19T14:49:14.627 +C Disable\sposix_fallocate()\sfor\sall\ssystems,\sall\sthe\stime,\sunless\sthe\nHAVE_POSIX_FALLOCATE\scompile-time\smacro\sis\ssupplied. +D 2013-06-20T14:07:37.671 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -201,7 +201,7 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c a4c49f855cfd0783d7027a5e20dab6bb10fe4e4b +F src/os_unix.c 9eafa5458cf2ff684ddccff82c9bb113c7cad847 F src/os_win.c 5f018dbd4cec25c5b47e11432b946a7d2ccee60b F src/pager.c 79df56da9dd49aceaa4cac207484a9a82cba40ae F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 @@ -1093,7 +1093,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b9b30d4f9845d212e2d3206abbf2795099e5d71d -R 051331ae49dcb9481117487fe2ddd3f7 +P 2b2ade92788be623af6f57e37d98994be2cec142 +R 4c8df645fee7190a620dee659859568b U drh -Z f091211d6e3ac84847a4aa6c11062c5e +Z 4cfe85260540c90b4ee0898bd7491d71 diff --git a/manifest.uuid b/manifest.uuid index edfc6bc72c..225d72de72 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2b2ade92788be623af6f57e37d98994be2cec142 \ No newline at end of file +b674462243138fcee192ef05d434665e30c681c4 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index e4382cbff9..152bf9a113 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -46,12 +46,6 @@ #include "sqliteInt.h" #if SQLITE_OS_UNIX /* This file is used on unix only */ -/* Use posix_fallocate() if it is available -*/ -#if !defined(HAVE_POSIX_FALLOCATE) && defined(__linux__) -# define HAVE_POSIX_FALLOCATE 1 -#endif - /* ** There are various methods for file locking used for concurrency ** control: From 472eae8a4d4d69895e85234aff425fdc835957ff Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 20 Jun 2013 17:32:28 +0000 Subject: [PATCH 135/144] Add a NEVER() macro and an explanation comment around an unreachable branch in the STAT3 logic. FossilOrigin-Name: 604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 7 ++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 7c057f18d9..e7e71b5de4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Pull\sin\sthe\sposix_fallocate()\schange\sfrom\strunk. -D 2013-06-20T14:17:39.289 +C Add\sa\sNEVER()\smacro\sand\san\sexplanation\scomment\saround\san\sunreachable\sbranch\nin\sthe\sSTAT3\slogic. +D 2013-06-20T17:32:28.451 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c ac9f8c4ee8ece1e8a4c93802792dbb0d629a7fa0 +F src/where.c 8d6c07d9641bf107e03a2b613550d90b8c7f4a82 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P bf5764067ab848e19e5971cbdf892c633495e325 b674462243138fcee192ef05d434665e30c681c4 -R 91cfb3838b57db0708acca963a7bb8c5 +P d94db3fd921890ab1d6414ab629410ae50779686 +R 4877ecf4e1d53d3b49ba9f1fadfb6d66 U drh -Z 767fbda1b22b9d1069574da955ceb02c +Z c939c499a0659dd37def1fcbcc79c922 diff --git a/manifest.uuid b/manifest.uuid index fc397231db..bda9422793 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d94db3fd921890ab1d6414ab629410ae50779686 \ No newline at end of file +604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 \ No newline at end of file diff --git a/src/where.c b/src/where.c index b7dab2105d..cdc0e16839 100644 --- a/src/where.c +++ b/src/where.c @@ -2409,9 +2409,10 @@ static int whereKeyStats( assert( pColl->enc==SQLITE_UTF8 ); }else{ pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl); - if( pColl==0 ){ - return SQLITE_ERROR; - } + /* If the collating sequence was unavailable, we should have failed + ** long ago and never reached this point. But we'll check just to + ** be doubly sure. */ + if( NEVER(pColl==0) ) return SQLITE_ERROR; z = (const u8 *)sqlite3ValueText(pVal, pColl->enc); if( !z ){ return SQLITE_NOMEM; From 6457a353bca93d55db6011df34fb04e8c81e997e Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 21 Jun 2013 00:35:37 +0000 Subject: [PATCH 136/144] Modify the query planner interface so that it always passes in the result set. This is the first step toward adding an optimization that will omit tables from a join that do not contribute to the result. FossilOrigin-Name: 2c2577e69ccb47f1af674a755e71221e2ca0b322 --- manifest | 21 +++++++++++-------- manifest.uuid | 2 +- src/select.c | 7 ++++--- src/sqliteInt.h | 1 + src/where.c | 54 ++++++++++++++++++++++++++---------------------- test/alter2.test | 1 + 6 files changed, 48 insertions(+), 38 deletions(-) diff --git a/manifest b/manifest index e7e71b5de4..ede3df5706 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\sNEVER()\smacro\sand\san\sexplanation\scomment\saround\san\sunreachable\sbranch\nin\sthe\sSTAT3\slogic. -D 2013-06-20T17:32:28.451 +C Modify\sthe\squery\splanner\sinterface\sso\sthat\sit\salways\spasses\sin\sthe\sresult\sset.\nThis\sis\sthe\sfirst\sstep\stoward\sadding\san\soptimization\sthat\swill\somit\stables\nfrom\sa\sjoin\sthat\sdo\snot\scontribute\sto\sthe\sresult. +D 2013-06-21T00:35:37.456 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -215,12 +215,12 @@ F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c d5a1b9bc3fb451e68ce907df253c6ac17e7310f7 +F src/select.c 91b62654caf8dfe292fb8882715e575d34ad3874 F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 82a0f3e7c3410cc748c80268e0831dba5ea98cb4 +F src/sqliteInt.h cabeb0401566d80503a0bc6e2d12e7fe2577bf6d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,14 +289,14 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 8d6c07d9641bf107e03a2b613550d90b8c7f4a82 +F src/where.c c950b131584a40121092d735804472f567beefbc F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748 -F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 +F test/alter2.test 40531b1f89d4fe43f9007b1bfc304e291ed000ae F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5 F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc @@ -1096,7 +1096,10 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d94db3fd921890ab1d6414ab629410ae50779686 -R 4877ecf4e1d53d3b49ba9f1fadfb6d66 +P 604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 +R 54a7c9b08c105a408dfe2c4fd7fd4419 +T *branch * omit-join-table-opt +T *sym-omit-join-table-opt * +T -sym-nextgen-query-plan-exp * U drh -Z c939c499a0659dd37def1fcbcc79c922 +Z d2a3072c8b463b513f8068b32a4cb830 diff --git a/manifest.uuid b/manifest.uuid index bda9422793..169f9d22e6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 \ No newline at end of file +2c2577e69ccb47f1af674a755e71221e2ca0b322 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 40b7ec86f0..fa35f45871 100644 --- a/src/select.c +++ b/src/select.c @@ -4261,15 +4261,16 @@ int sqlite3Select( if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ - ExprList *pDist = (sDistinct.isTnct ? p->pEList : 0); + u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); /* Begin the database scan. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, pDist, 0,0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList, + wctrlFlags, 0); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } - if( sqlite3WhereIsDistinct(pWInfo) ){ + if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b2cab7a7ad..731612d345 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1974,6 +1974,7 @@ struct SrcList { #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ +#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ /* Allowed return values from sqlite3WhereIsDistinct() */ diff --git a/src/where.c b/src/where.c index cdc0e16839..ab4170fe6f 100644 --- a/src/where.c +++ b/src/where.c @@ -383,7 +383,7 @@ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ - ExprList *pDistinct; /* DISTINCT ON values, or NULL */ + ExprList *pResultSet; /* Result set. DISTINCT operates on these */ WhereLoop *pLoops; /* List of all WhereLoop objects */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereCost nRowOut; /* Estimated number of output rows */ @@ -3928,9 +3928,9 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ int nb = 1+(pTabList->nSrc+7)/8; struct SrcList_item *pItem = pTabList->a + p->iTab; Table *pTab = pItem->pTab; - sqlite3DebugPrintf("%c %2d.%0*llx.%0*llx", p->cId, + sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq); - sqlite3DebugPrintf(" %8s", + sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ if( p->u.btree.pIndex ){ @@ -3941,9 +3941,9 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ while( zName[i]!='_' ) i--; zName += i; } - sqlite3DebugPrintf(".%-12s %2d", zName, p->u.btree.nEq); + sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq); }else{ - sqlite3DebugPrintf("%16s",""); + sqlite3DebugPrintf("%20s",""); } }else{ char *z; @@ -3953,10 +3953,10 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ }else{ z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask); } - sqlite3DebugPrintf(" %-15s", z); + sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" fg %05x N %d", p->wsFlags, p->nLTerm); + sqlite3DebugPrintf(" f %04x N %d", p->wsFlags, p->nLTerm); sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); } #endif @@ -5370,12 +5370,12 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ pLevel->iFrom = pWLoop->iTab; pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; } - if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0 - && pWInfo->pDistinct + if( (pWInfo->wctrlFlags & (WHERE_DISTINCTBY|WHERE_WANT_DISTINCT)) + ==WHERE_WANT_DISTINCT && nRowEst ){ Bitmask notUsed; - int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pDistinct, pFrom, + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } @@ -5464,7 +5464,9 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1; - if( pWInfo->pDistinct ) pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ + pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + } #ifdef SQLITE_DEBUG pLoop->cId = '0'; #endif @@ -5554,10 +5556,10 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ */ WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ - SrcList *pTabList, /* A list of all tables to be scanned */ + SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList *pOrderBy, /* An ORDER BY clause, or NULL */ - ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */ + ExprList *pResultSet, /* Result set of the query */ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ ){ @@ -5613,7 +5615,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; - pWInfo->pDistinct = pDistinct; + pWInfo->pResultSet = pResultSet; pWInfo->iBreak = sqlite3VdbeMakeLabel(v); pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; @@ -5628,7 +5630,9 @@ WhereInfo *sqlite3WhereBegin( /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ - if( OptimizationDisabled(db, SQLITE_DistinctOpt) ) pDistinct = 0; + if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ + wctrlFlags &= ~WHERE_WANT_DISTINCT; + } /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. @@ -5650,7 +5654,9 @@ WhereInfo *sqlite3WhereBegin( */ if( nTabList==0 ){ if( pOrderBy ) pWInfo->bOBSat = 1; - if( pDistinct ) pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + if( wctrlFlags & WHERE_WANT_DISTINCT ){ + pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + } } /* Assign a bit from the bitmask to every term in the FROM clause. @@ -5697,7 +5703,7 @@ WhereInfo *sqlite3WhereBegin( ** expressions, then we won't be able to satisfy it using indices, so ** go ahead and disable it now. */ - if( pOrderBy && pDistinct ){ + if( pOrderBy && (wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollate(pOrderBy->a[ii].pExpr); if( pExpr->op!=TK_COLUMN ){ @@ -5709,17 +5715,15 @@ WhereInfo *sqlite3WhereBegin( } } - /* Check if the DISTINCT qualifier, if there is one, is redundant. - ** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to - ** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT. - */ - if( pDistinct ){ - if( isDistinctRedundant(pParse,pTabList,&pWInfo->sWC,pDistinct) ){ - pDistinct = 0; + if( wctrlFlags & WHERE_WANT_DISTINCT ){ + if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ + /* The DISTINCT marking is pointless. Ignore it. */ + wctrlFlags &= ~WHERE_WANT_DISTINCT; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; }else if( pOrderBy==0 ){ + /* Try to ORDER BY the result set to make distinct processing easier */ pWInfo->wctrlFlags |= WHERE_DISTINCTBY; - pWInfo->pOrderBy = pDistinct; + pWInfo->pOrderBy = pResultSet; } } diff --git a/test/alter2.test b/test/alter2.test index 14be637f97..db8a83bf9f 100644 --- a/test/alter2.test +++ b/test/alter2.test @@ -120,6 +120,7 @@ do_test alter2-1.5 { } } {} do_test alter2-1.6 { +breakpoint execsql { SELECT c FROM abc ORDER BY c; } From fd636c7541d0de19ce365fc9e483b88121531c2e Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 21 Jun 2013 02:05:06 +0000 Subject: [PATCH 137/144] Attempt to disable inner loops of a join that do not generate output. This does not work, since the inner loops might run zero times and thus inhibit all output. Needs to be enhanced to work only for LEFT JOINs or when we know that the inner loop will always run at least once. FossilOrigin-Name: ca839723a21bb13d3e0666a672c15c6f3a267c2f --- manifest | 17 +++++++--------- manifest.uuid | 2 +- src/where.c | 51 +++++++++++++++++++++++++++++++++--------------- test/alter2.test | 1 - 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/manifest b/manifest index ede3df5706..2d7ec778f6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Modify\sthe\squery\splanner\sinterface\sso\sthat\sit\salways\spasses\sin\sthe\sresult\sset.\nThis\sis\sthe\sfirst\sstep\stoward\sadding\san\soptimization\sthat\swill\somit\stables\nfrom\sa\sjoin\sthat\sdo\snot\scontribute\sto\sthe\sresult. -D 2013-06-21T00:35:37.456 +C Attempt\sto\sdisable\sinner\sloops\sof\sa\sjoin\sthat\sdo\snot\sgenerate\soutput.\nThis\sdoes\snot\swork,\ssince\sthe\sinner\sloops\smight\srun\szero\stimes\sand\sthus\ninhibit\sall\soutput.\s\sNeeds\sto\sbe\senhanced\sto\swork\sonly\sfor\sLEFT\sJOINs\nor\swhen\swe\sknow\sthat\sthe\sinner\sloop\swill\salways\srun\sat\sleast\sonce. +D 2013-06-21T02:05:06.206 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,14 +289,14 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c c950b131584a40121092d735804472f567beefbc +F src/where.c fc5293b54a70474c2b46e9df26c9e2803b152e68 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748 -F test/alter2.test 40531b1f89d4fe43f9007b1bfc304e291ed000ae +F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5 F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc @@ -1096,10 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 -R 54a7c9b08c105a408dfe2c4fd7fd4419 -T *branch * omit-join-table-opt -T *sym-omit-join-table-opt * -T -sym-nextgen-query-plan-exp * +P 2c2577e69ccb47f1af674a755e71221e2ca0b322 +R b2263c66dd8a59884ee45351c335261a U drh -Z d2a3072c8b463b513f8068b32a4cb830 +Z 6fd83e64fe937f64082b799e88969f81 diff --git a/manifest.uuid b/manifest.uuid index 169f9d22e6..b8cca3c3d8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2c2577e69ccb47f1af674a755e71221e2ca0b322 \ No newline at end of file +ca839723a21bb13d3e0666a672c15c6f3a267c2f \ No newline at end of file diff --git a/src/where.c b/src/where.c index ab4170fe6f..18b4a3782e 100644 --- a/src/where.c +++ b/src/where.c @@ -392,10 +392,10 @@ struct WhereInfo { u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ + u8 nLevel; /* Number of nested loop */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ - int nLevel; /* Number of nested loop */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereClause sWC; /* Decomposition of the WHERE clause */ @@ -5370,8 +5370,9 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ pLevel->iFrom = pWLoop->iTab; pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; } - if( (pWInfo->wctrlFlags & (WHERE_DISTINCTBY|WHERE_WANT_DISTINCT)) - ==WHERE_WANT_DISTINCT + if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 + && (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0 + && pWInfo->eDistinct==WHERE_DISTINCT_NOOP && nRowEst ){ Bitmask notUsed; @@ -5571,15 +5572,23 @@ WhereInfo *sqlite3WhereBegin( WhereLoopBuilder sWLB; /* The WhereLoop builder */ WhereMaskSet *pMaskSet; /* The expression mask set */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */ + WhereLoop *pLoop; /* Pointer to a single WhereLoop object */ int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ int rc; /* Return code */ /* Variable initialization */ + db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); sWLB.pOrderBy = pOrderBy; + /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via + ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ + if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ + wctrlFlags &= ~WHERE_WANT_DISTINCT; + } + /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask */ @@ -5603,7 +5612,6 @@ WhereInfo *sqlite3WhereBegin( ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ - db = pParse->db; nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ @@ -5628,12 +5636,6 @@ WhereInfo *sqlite3WhereBegin( sWLB.pNew->cId = '*'; #endif - /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via - ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ - if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ - wctrlFlags &= ~WHERE_WANT_DISTINCT; - } - /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. */ @@ -5718,7 +5720,6 @@ WhereInfo *sqlite3WhereBegin( if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ - wctrlFlags &= ~WHERE_WANT_DISTINCT; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; }else if( pOrderBy==0 ){ /* Try to ORDER BY the result set to make distinct processing easier */ @@ -5737,11 +5738,11 @@ WhereInfo *sqlite3WhereBegin( #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ WhereLoop *p; - int i = 0; + int i; static char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; - for(p=pWInfo->pLoops; p; p=p->pNextLoop){ - p->cId = zLabel[(i++)%sizeof(zLabel)]; + for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ + p->cId = zLabel[i%sizeof(zLabel)]; whereLoopPrint(p, pTabList); } } @@ -5782,11 +5783,29 @@ WhereInfo *sqlite3WhereBegin( } } sqlite3DebugPrintf("\n"); - for(ii=0; iinLevel; ii++){ whereLoopPrint(pWInfo->a[ii].pWLoop, pTabList); } } #endif + /* Attempt to omit tables from the join that do not effect the result */ + if( pResultSet!=0 && pWInfo->nLevel>=2 ){ + Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet); + if( pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, pOrderBy); + while( pWInfo->nLevel>=2 ){ + pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; + if( ((wctrlFlags & WHERE_WANT_DISTINCT)!=0 + || (pLoop->wsFlags & WHERE_ONEROW)!=0) + && (tabUsed & pLoop->maskSelf)==0 + ){ + WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId)); + pWInfo->nLevel--; + nTabList--; + }else{ + break; + } + } + } WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; @@ -5955,7 +5974,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Close all of the cursors that were opened by sqlite3WhereBegin. */ - assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc ); + assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ Index *pIdx = 0; struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; diff --git a/test/alter2.test b/test/alter2.test index db8a83bf9f..14be637f97 100644 --- a/test/alter2.test +++ b/test/alter2.test @@ -120,7 +120,6 @@ do_test alter2-1.5 { } } {} do_test alter2-1.6 { -breakpoint execsql { SELECT c FROM abc ORDER BY c; } From bc71b1d4536ce7842f80010049c69f5fd2806b3b Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 21 Jun 2013 02:15:48 +0000 Subject: [PATCH 138/144] Only eliminate inner loops of a JOIN if they are the RHS of a LEFT JOIN and if they give no more than a single result. This appears to give correct answers in all cases. FossilOrigin-Name: d7a25cc79794817504ca1a4262008a68b2a4dece --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 2d7ec778f6..a54bc73242 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Attempt\sto\sdisable\sinner\sloops\sof\sa\sjoin\sthat\sdo\snot\sgenerate\soutput.\nThis\sdoes\snot\swork,\ssince\sthe\sinner\sloops\smight\srun\szero\stimes\sand\sthus\ninhibit\sall\soutput.\s\sNeeds\sto\sbe\senhanced\sto\swork\sonly\sfor\sLEFT\sJOINs\nor\swhen\swe\sknow\sthat\sthe\sinner\sloop\swill\salways\srun\sat\sleast\sonce. -D 2013-06-21T02:05:06.206 +C Only\seliminate\sinner\sloops\sof\sa\sJOIN\sif\sthey\sare\sthe\sRHS\sof\sa\sLEFT\sJOIN\nand\sif\sthey\sgive\sno\smore\sthan\sa\ssingle\sresult.\s\sThis\sappears\sto\sgive\scorrect\nanswers\sin\sall\scases. +D 2013-06-21T02:15:48.306 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c fc5293b54a70474c2b46e9df26c9e2803b152e68 +F src/where.c 0ca9544cca6e40550b970574a32055463650df12 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 2c2577e69ccb47f1af674a755e71221e2ca0b322 -R b2263c66dd8a59884ee45351c335261a +P ca839723a21bb13d3e0666a672c15c6f3a267c2f +R 6b62f4d6f88cb9d978862e981acfa473 U drh -Z 6fd83e64fe937f64082b799e88969f81 +Z b99e6e4ea8d5a45c0b5323f96846f0b0 diff --git a/manifest.uuid b/manifest.uuid index b8cca3c3d8..32c308b877 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ca839723a21bb13d3e0666a672c15c6f3a267c2f \ No newline at end of file +d7a25cc79794817504ca1a4262008a68b2a4dece \ No newline at end of file diff --git a/src/where.c b/src/where.c index 18b4a3782e..32fa61c7f0 100644 --- a/src/where.c +++ b/src/where.c @@ -5794,16 +5794,16 @@ WhereInfo *sqlite3WhereBegin( if( pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, pOrderBy); while( pWInfo->nLevel>=2 ){ pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; - if( ((wctrlFlags & WHERE_WANT_DISTINCT)!=0 - || (pLoop->wsFlags & WHERE_ONEROW)!=0) - && (tabUsed & pLoop->maskSelf)==0 + if( (pWInfo->pTabList->a[pLoop->iTab].jointype & JT_LEFT)==0 ) break; + if( (wctrlFlags & WHERE_WANT_DISTINCT)==0 + && (pLoop->wsFlags & WHERE_ONEROW)==0 ){ - WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId)); - pWInfo->nLevel--; - nTabList--; - }else{ break; } + if( (tabUsed & pLoop->maskSelf)!=0 ) break; + WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId)); + pWInfo->nLevel--; + nTabList--; } } WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); From 8def92bac38f32eb0876fb769dfdc52c7779e929 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 21 Jun 2013 17:30:47 +0000 Subject: [PATCH 139/144] Add the "notindexed" option to fts4. FossilOrigin-Name: 8ff2b8f5948ccddce70102e6d68d464c66e4f7ca --- ext/fts3/fts3.c | 53 +++++++++++++++++--- ext/fts3/fts3Int.h | 1 + ext/fts3/fts3_write.c | 84 +++++++++++++++++-------------- manifest | 24 +++++---- manifest.uuid | 2 +- test/fts4noti.test | 111 +++++++++++++++++++++++++++++++++++++++++ test/permutations.test | 2 +- 7 files changed, 222 insertions(+), 55 deletions(-) create mode 100644 test/fts4noti.test diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 374d690688..ccd2345bf1 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1081,6 +1081,8 @@ static int fts3InitVtab( char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ char *zContent = 0; /* content=? parameter (or NULL) */ char *zLanguageid = 0; /* languageid=? parameter (or NULL) */ + char **azNotindexed = 0; /* The set of notindexed= columns */ + int nNotindexed = 0; /* Size of azNotindexed[] array */ assert( strlen(argv[0])==4 ); assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) @@ -1090,9 +1092,19 @@ static int fts3InitVtab( nDb = (int)strlen(argv[1]) + 1; nName = (int)strlen(argv[2]) + 1; - aCol = (const char **)sqlite3_malloc(sizeof(const char *) * (argc-2) ); - if( !aCol ) return SQLITE_NOMEM; - memset((void *)aCol, 0, sizeof(const char *) * (argc-2)); + nByte = sizeof(const char *) * (argc-2); + aCol = (const char **)sqlite3_malloc(nByte); + if( aCol ){ + memset(aCol, 0, nByte); + azNotindexed = (char **)sqlite3_malloc(nByte); + } + if( azNotindexed ){ + memset(azNotindexed, 0, nByte); + } + if( !aCol || !azNotindexed ){ + rc = SQLITE_NOMEM; + goto fts3_init_out; + } /* Loop through all of the arguments passed by the user to the FTS3/4 ** module (i.e. all the column names and special arguments). This loop @@ -1131,7 +1143,8 @@ static int fts3InitVtab( { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ { "order", 5 }, /* 4 -> ORDER */ { "content", 7 }, /* 5 -> CONTENT */ - { "languageid", 10 } /* 6 -> LANGUAGEID */ + { "languageid", 10 }, /* 6 -> LANGUAGEID */ + { "notindexed", 10 } /* 7 -> NOTINDEXED */ }; int iOpt; @@ -1197,6 +1210,11 @@ static int fts3InitVtab( zLanguageid = zVal; zVal = 0; break; + + case 7: /* NOTINDEXED */ + azNotindexed[nNotindexed++] = zVal; + zVal = 0; + break; } } sqlite3_free(zVal); @@ -1268,6 +1286,7 @@ static int fts3InitVtab( nByte = sizeof(Fts3Table) + /* Fts3Table */ nCol * sizeof(char *) + /* azColumn */ nIndex * sizeof(struct Fts3Index) + /* aIndex */ + nCol * sizeof(u8) + /* abNotindexed */ nName + /* zName */ nDb + /* zDb */ nString; /* Space for azColumn strings */ @@ -1301,9 +1320,10 @@ static int fts3InitVtab( for(i=0; iaIndex[i].hPending, FTS3_HASH_STRING, 1); } + p->abNotindexed = (u8 *)&p->aIndex[nIndex]; /* Fill in the zName and zDb fields of the vtab structure. */ - zCsr = (char *)&p->aIndex[nIndex]; + zCsr = (char *)&p->abNotindexed[nCol]; p->zName = zCsr; memcpy(zCsr, argv[2], nName); zCsr += nName; @@ -1324,7 +1344,26 @@ static int fts3InitVtab( assert( zCsr <= &((char *)p)[nByte] ); } - if( (zCompress==0)!=(zUncompress==0) ){ + /* Fill in the abNotindexed array */ + for(iCol=0; iColazColumn[iCol]); + for(i=0; iazColumn[iCol], zNot, n) ){ + p->abNotindexed[iCol] = 1; + sqlite3_free(zNot); + azNotindexed[i] = 0; + } + } + } + for(i=0; inColumn+2; i++){ - const char *zText = (const char *)sqlite3_value_text(apVal[i]); - int rc = fts3PendingTermsAdd(p, iLangid, zText, i-2, &aSz[i-2]); - if( rc!=SQLITE_OK ){ - return rc; + int iCol = i-2; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_value_text(apVal[i]); + int rc = fts3PendingTermsAdd(p, iLangid, zText, iCol, &aSz[iCol]); + if( rc!=SQLITE_OK ){ + return rc; + } + aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); } - aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); } return SQLITE_OK; } @@ -1052,9 +1055,12 @@ static void fts3DeleteTerms( int iLangid = langidFromSelect(p, pSelect); rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0)); for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){ - const char *zText = (const char *)sqlite3_column_text(pSelect, i); - rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[i-1]); - aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i); + int iCol = i-1; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pSelect, i); + rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[iCol]); + aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i); + } } if( rc!=SQLITE_OK ){ sqlite3_reset(pSelect); @@ -3296,9 +3302,11 @@ static int fts3DoRebuild(Fts3Table *p){ rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0)); memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ - const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); - rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); - aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); + if( p->abNotindexed[iCol]==0 ){ + const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); + rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); + aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); + } } if( p->bHasDocsize ){ fts3InsertDocsize(&rc, p, aSz); @@ -5101,35 +5109,37 @@ int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){ iDocid = sqlite3_column_int64(pCsr->pStmt, 0); for(i=0; inColumn && rc==SQLITE_OK; i++){ - const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1); - sqlite3_tokenizer_cursor *pTC = 0; - - rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC); - while( rc==SQLITE_OK ){ - char const *zToken; /* Buffer containing token */ - int nToken = 0; /* Number of bytes in token */ - int iDum1 = 0, iDum2 = 0; /* Dummy variables */ - int iPos = 0; /* Position of token in zText */ - - rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); - for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ - Fts3PhraseToken *pPT = pDef->pToken; - if( (pDef->iCol>=p->nColumn || pDef->iCol==i) - && (pPT->bFirst==0 || iPos==0) - && (pPT->n==nToken || (pPT->isPrefix && pPT->nz, pPT->n)) - ){ - fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); + if( p->abNotindexed[i]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1); + sqlite3_tokenizer_cursor *pTC = 0; + + rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC); + while( rc==SQLITE_OK ){ + char const *zToken; /* Buffer containing token */ + int nToken = 0; /* Number of bytes in token */ + int iDum1 = 0, iDum2 = 0; /* Dummy variables */ + int iPos = 0; /* Position of token in zText */ + + rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); + for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ + Fts3PhraseToken *pPT = pDef->pToken; + if( (pDef->iCol>=p->nColumn || pDef->iCol==i) + && (pPT->bFirst==0 || iPos==0) + && (pPT->n==nToken || (pPT->isPrefix && pPT->nz, pPT->n)) + ){ + fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); + } } } + if( pTC ) pModule->xClose(pTC); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; } - if( pTC ) pModule->xClose(pTC); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - } - - for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ - if( pDef->pList ){ - rc = fts3PendingListAppendVarint(&pDef->pList, 0); + + for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ + if( pDef->pList ){ + rc = fts3PendingListAppendVarint(&pDef->pList, 0); + } } } } diff --git a/manifest b/manifest index 4b1070228c..949e9c0e1f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Disable\sposix_fallocate()\sfor\sall\ssystems,\sall\sthe\stime,\sunless\sthe\nHAVE_POSIX_FALLOCATE\scompile-time\smacro\sis\ssupplied. -D 2013-06-20T14:07:37.671 +C Add\sthe\s"notindexed"\soption\sto\sfts4. +D 2013-06-21T17:30:47.476 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -78,9 +78,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 931b3c83abdd1ab3bb389b2130431c2a9ff73b91 +F ext/fts3/fts3.c 3cb4afd0accf903fbe66e2cc48d6f44e5ccb8a76 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h cb4df04cf886d9920a71df9e8faaa5aae2fa48c6 +F ext/fts3/fts3Int.h 2659cdfc8cde3f981ea99b2f60383e6239f9f4d5 F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 @@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9 F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d -F ext/fts3/fts3_write.c 6a1fc0e922e76b68e594bf7bc33bac72af9dc47b +F ext/fts3/fts3_write.c cd264daa4f92b8eb6d61245333d0e3b147e8fd80 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197 @@ -550,6 +550,7 @@ F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584 +F test/fts4noti.test 7710af8ad41b23571d62c0cee2a062c30ecb8012 F test/fts4unicode.test c8ac44217bf6c17812b03eaafa6c06995ad304c2 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/func.test b0fc34fdc36897769651975a2b0a606312753643 @@ -706,7 +707,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test 4614301e38398df7fdd5f28f4ed8f272b328251b -F test/permutations.test d997a947ab8aabb15f763d50a030b3c11e8ef1b6 +F test/permutations.test 7161be2569550924a8a437272acabfe9e6f48b86 F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 @@ -1093,7 +1094,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 2b2ade92788be623af6f57e37d98994be2cec142 -R 4c8df645fee7190a620dee659859568b -U drh -Z 4cfe85260540c90b4ee0898bd7491d71 +P b674462243138fcee192ef05d434665e30c681c4 +R 977878ca999ebdf95aeef1dd83187bfc +T *branch * fts4-notindexed +T *sym-fts4-notindexed * +T -sym-trunk * +U dan +Z 6bb2b422fa6b5870298aeb31440d85b9 diff --git a/manifest.uuid b/manifest.uuid index 225d72de72..ddcb0bcc50 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b674462243138fcee192ef05d434665e30c681c4 \ No newline at end of file +8ff2b8f5948ccddce70102e6d68d464c66e4f7ca \ No newline at end of file diff --git a/test/fts4noti.test b/test/fts4noti.test new file mode 100644 index 0000000000..4a49933d0a --- /dev/null +++ b/test/fts4noti.test @@ -0,0 +1,111 @@ +# 2013 June 21 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the notindexed=xxx FTS4 option. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix fts4noti + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + + +#------------------------------------------------------------------------- +# Test that typos in "notindexed=" column names are detected. +# +do_execsql_test 1.0 { + CREATE TABLE cc(a, b, c); +} +foreach {tn arg res} { + 1 "(b, c, notindexed=a)" {1 {no such column: a}} + 2 "(a, b, notindexed=a)" {0 {}} + 3 "(a, b, notindexed=a, notindexed=a)" {0 {}} + 4 "(notindexed=a, a, b)" {0 {}} + 5 "(notindexed=a, notindexed=b, notindexed=c, a, b, c, d)" {0 {}} + 6 "(notindexed=a, notindexed=B, notindexed=c, a, b, c, d)" {0 {}} + 7 "(notindexed=a, notindexed=b, notindexed=c, a, B, c, d)" {0 {}} + 8 "(notindexed=d, content=cc)" {1 {no such column: d}} + 9 "(notindexed=a, content=cc)" {0 {}} +} { + do_catchsql_test 1.$tn "CREATE VIRTUAL TABLE t1 USING fts4 $arg" $res + if {[lindex $res 0]==0} { execsql "DROP TABLE t1" } +} + +do_execsql_test 1.x { SELECT name FROM sqlite_master } {cc} + + +#------------------------------------------------------------------------- +# Test that notindexed columns are not indexed. +# +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE t1 USING fts4(a, b, c, notindexed=b); + INSERT INTO t1 VALUES('one two', 'three four', 'five six'); + INSERT INTO t1 VALUES('three four', 'five six', 'one two'); +} +do_execsql_test 2.2 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} +do_execsql_test 2.3 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} +do_execsql_test 2.4 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + +do_execsql_test 2.5 { INSERT INTO t1(t1) VALUES('optimize') } + +do_execsql_test 2.6 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} +do_execsql_test 2.7 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} +do_execsql_test 2.8 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + +do_execsql_test 2.9 { INSERT INTO t1(t1) VALUES('rebuild') } + +do_execsql_test 2.10 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} +do_execsql_test 2.11 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} +do_execsql_test 2.12 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + +do_execsql_test 2.13 { + SELECT * FROM t1 WHERE docid=1 +} {{one two} {three four} {five six}} +do_execsql_test 2.14 { + SELECT * FROM t1 WHERE docid=2 +} {{three four} {five six} {one two}} + +do_execsql_test 2.x { DROP TABLE t1 } + +#------------------------------------------------------------------------- +# Test that notindexed columns are not scanned for deferred tokens. +# + +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE t2 USING fts4(x, y, notindexed=x); +} +do_test 3.2 { + set v [string repeat " 1" 50000] + set v1 "x $v" + set v2 "y $v" + execsql { + INSERT INTO t2 VALUES(1, 'x y z'); + INSERT INTO t2 VALUES(2, $v1); + INSERT INTO t2 VALUES(3, $v2); + INSERT INTO t2 VALUES(4, $v2); + INSERT INTO t2 VALUES(5, $v2); + INSERT INTO t2 VALUES(6, $v2); + } +} {} + +do_execsql_test 3.3 { SELECT x FROM t2 WHERE t2 MATCH '2' } {} +do_execsql_test 3.4 { SELECT x FROM t2 WHERE t2 MATCH '1' } {2 3 4 5 6} +do_execsql_test 3.5 { SELECT x FROM t2 WHERE t2 MATCH 'x' } {1 2} +do_execsql_test 3.6 { SELECT x FROM t2 WHERE t2 MATCH 'x 1' } {2} + + + +finish_test diff --git a/test/permutations.test b/test/permutations.test index bc3ceb8085..d035a1afa5 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -194,7 +194,7 @@ test_suite "fts3" -prefix "" -description { fts4aa.test fts4content.test fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test fts3corrupt2.test fts3first.test fts4langid.test fts4merge.test - fts4check.test fts4unicode.test + fts4check.test fts4unicode.test fts4noti.test } test_suite "nofaultsim" -prefix "" -description { From 9faa6482397e93c7975d85eaaa9ecc6fdac54dc7 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 21 Jun 2013 18:18:23 +0000 Subject: [PATCH 140/144] Add a few more tests for the fts4 notindexed option. FossilOrigin-Name: b53c0c41f97c7ddaeea61f0e6035d1c4747db3f7 --- manifest | 17 +++---- manifest.uuid | 2 +- test/fts3malloc.test | 4 ++ test/fts4noti.test | 118 ++++++++++++++++++++++++++++++++----------- 4 files changed, 101 insertions(+), 40 deletions(-) diff --git a/manifest b/manifest index 949e9c0e1f..c009a5bf3d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s"notindexed"\soption\sto\sfts4. -D 2013-06-21T17:30:47.476 +C Add\sa\sfew\smore\stests\sfor\sthe\sfts4\snotindexed\soption. +D 2013-06-21T18:18:23.327 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -530,7 +530,7 @@ F test/fts3expr3.test 1bfb762b53a794f990f3dffaae8bbea5736422f7 F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660 F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887 F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 -F test/fts3malloc.test b86ea33db9e8c58c0c2f8027a9fcadaf6a1568be +F test/fts3malloc.test 1e3df7598534e77a7072aad610d46554cface3e9 F test/fts3matchinfo.test ecb08f586d027eb03941bcfcded6cb9d8ccb3a66 F test/fts3near.test 12895557870b0f9af7cc0be81a0171abb2d12f12 F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1 @@ -550,7 +550,7 @@ F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584 -F test/fts4noti.test 7710af8ad41b23571d62c0cee2a062c30ecb8012 +F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057 F test/fts4unicode.test c8ac44217bf6c17812b03eaafa6c06995ad304c2 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/func.test b0fc34fdc36897769651975a2b0a606312753643 @@ -1094,10 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b674462243138fcee192ef05d434665e30c681c4 -R 977878ca999ebdf95aeef1dd83187bfc -T *branch * fts4-notindexed -T *sym-fts4-notindexed * -T -sym-trunk * +P 8ff2b8f5948ccddce70102e6d68d464c66e4f7ca +R 78eae7e4eba9ee605ccaf88bbcc953f5 U dan -Z 6bb2b422fa6b5870298aeb31440d85b9 +Z 1a5ea5678be579c71cc2f3fe2b3716ce diff --git a/manifest.uuid b/manifest.uuid index ddcb0bcc50..375d0c4373 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8ff2b8f5948ccddce70102e6d68d464c66e4f7ca \ No newline at end of file +b53c0c41f97c7ddaeea61f0e6035d1c4747db3f7 \ No newline at end of file diff --git a/test/fts3malloc.test b/test/fts3malloc.test index 7eeee7fe0d..095f9a7a50 100644 --- a/test/fts3malloc.test +++ b/test/fts3malloc.test @@ -62,6 +62,9 @@ do_error_test fts3_malloc-1.5 { do_write_test fts3_malloc-1.6 sqlite_master { CREATE VIRTUAL TABLE ft6 USING fts3(a, b, tokenize porter) } +do_write_test fts3_malloc-1.7 sqlite_master { + CREATE VIRTUAL TABLE ft7 USING fts4(a, b, notindexed=b) +} # Test the xConnect/xDisconnect methods: #db eval { ATTACH 'test2.db' AS aux } @@ -81,6 +84,7 @@ do_test fts3_malloc-2.0 { DROP TABLE ft3; DROP TABLE ft4; DROP TABLE ft6; + DROP TABLE ft7; } execsql { CREATE VIRTUAL TABLE ft USING fts3(a, b) } for {set ii 1} {$ii < 32} {incr ii} { diff --git a/test/fts4noti.test b/test/fts4noti.test index 4a49933d0a..e926228330 100644 --- a/test/fts4noti.test +++ b/test/fts4noti.test @@ -39,6 +39,8 @@ foreach {tn arg res} { 7 "(notindexed=a, notindexed=b, notindexed=c, a, B, c, d)" {0 {}} 8 "(notindexed=d, content=cc)" {1 {no such column: d}} 9 "(notindexed=a, content=cc)" {0 {}} + 10 "(notindexed=a, notindexed=b, a)" {1 {no such column: b}} + 11 "(notindexed=a, notindexed=b, b)" {1 {no such column: a}} } { do_catchsql_test 1.$tn "CREATE VIRTUAL TABLE t1 USING fts4 $arg" $res if {[lindex $res 0]==0} { execsql "DROP TABLE t1" } @@ -50,35 +52,54 @@ do_execsql_test 1.x { SELECT name FROM sqlite_master } {cc} #------------------------------------------------------------------------- # Test that notindexed columns are not indexed. # -do_execsql_test 2.1 { - CREATE VIRTUAL TABLE t1 USING fts4(a, b, c, notindexed=b); - INSERT INTO t1 VALUES('one two', 'three four', 'five six'); - INSERT INTO t1 VALUES('three four', 'five six', 'one two'); +foreach {tn schema} { + 1 { + CREATE VIRTUAL TABLE t1 USING fts4(a, b, c, notindexed=b); + } + 2 { + CREATE TABLE c1(a, b, c); + INSERT INTO c1 VALUES('one two', 'three four', 'five six'); + INSERT INTO c1 VALUES('three four', 'five six', 'one two'); + CREATE VIRTUAL TABLE t1 USING fts4(content=c1, notindexed=b); + } + 3 { + CREATE VIRTUAL TABLE t1 USING fts4(content="", a, b, c, notindexed=b); + } +} { + execsql $schema + + do_execsql_test 2.$tn.1 { + INSERT INTO t1(docid,a,b,c) VALUES(1, 'one two', 'three four', 'five six'); + INSERT INTO t1(docid,a,b,c) VALUES(2, 'three four', 'five six', 'one two'); + } + + do_execsql_test 2.$tn.2 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} + do_execsql_test 2.$tn.3 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} + do_execsql_test 2.$tn.4 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + + do_execsql_test 2.$tn.5 { INSERT INTO t1(t1) VALUES('optimize') } + + do_execsql_test 2.$tn.6 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} + do_execsql_test 2.$tn.7 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} + do_execsql_test 2.$tn.8 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + + if {$tn!=3} { + do_execsql_test 2.$tn.9 { INSERT INTO t1(t1) VALUES('rebuild') } + + do_execsql_test 2.$tn.10 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} + do_execsql_test 2.$tn.11 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} + do_execsql_test 2.$tn.12 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} + + do_execsql_test 2.$tn.13 { + SELECT a,b,c FROM t1 WHERE docid=1 + } {{one two} {three four} {five six}} + do_execsql_test 2.$tn.14 { + SELECT a,b,c FROM t1 WHERE docid=2 + } {{three four} {five six} {one two}} + } + + do_execsql_test 2.x { DROP TABLE t1 } } -do_execsql_test 2.2 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} -do_execsql_test 2.3 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} -do_execsql_test 2.4 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} - -do_execsql_test 2.5 { INSERT INTO t1(t1) VALUES('optimize') } - -do_execsql_test 2.6 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} -do_execsql_test 2.7 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} -do_execsql_test 2.8 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} - -do_execsql_test 2.9 { INSERT INTO t1(t1) VALUES('rebuild') } - -do_execsql_test 2.10 { SELECT docid FROM t1 WHERE t1 MATCH 'one' } {1 2} -do_execsql_test 2.11 { SELECT docid FROM t1 WHERE t1 MATCH 'three' } {2} -do_execsql_test 2.12 { SELECT docid FROM t1 WHERE t1 MATCH 'five' } {1} - -do_execsql_test 2.13 { - SELECT * FROM t1 WHERE docid=1 -} {{one two} {three four} {five six}} -do_execsql_test 2.14 { - SELECT * FROM t1 WHERE docid=2 -} {{three four} {five six} {one two}} - -do_execsql_test 2.x { DROP TABLE t1 } #------------------------------------------------------------------------- # Test that notindexed columns are not scanned for deferred tokens. @@ -105,7 +126,46 @@ do_execsql_test 3.3 { SELECT x FROM t2 WHERE t2 MATCH '2' } {} do_execsql_test 3.4 { SELECT x FROM t2 WHERE t2 MATCH '1' } {2 3 4 5 6} do_execsql_test 3.5 { SELECT x FROM t2 WHERE t2 MATCH 'x' } {1 2} do_execsql_test 3.6 { SELECT x FROM t2 WHERE t2 MATCH 'x 1' } {2} - +do_execsql_test 3.x { DROP TABLE t2 } + +#------------------------------------------------------------------------- +# Test that the types of notindexed columns are not modified. +# +do_execsql_test 4.1 { + CREATE VIRTUAL TABLE t2 USING fts4(poi, addr, notindexed=poi); + INSERT INTO t2 VALUES(114, 'x x x'); + INSERT INTO t2 VALUES(X'1234', 'y y y'); + INSERT INTO t2 VALUES(NULL, 'z z z'); + INSERT INTO t2 VALUES(113.2, 'w w w'); + INSERT INTO t2 VALUES('poi', 'v v v'); +} +do_execsql_test 4.2 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'x' } {integer} +do_execsql_test 4.3 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'y' } {blob} +do_execsql_test 4.4 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'z' } {null} +do_execsql_test 4.5 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'w' } {real} +do_execsql_test 4.6 { SELECT typeof(poi) FROM t2 WHERE t2 MATCH 'v' } {text} + +do_execsql_test 4.x { DROP TABLE t2 } + +#------------------------------------------------------------------------- +# Test that multiple notindexed options on a single table work as expected. +# +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE t2 USING fts4( + notindexed="three", one, two, three, notindexed="one", + ); + INSERT INTO t2 VALUES('a', 'b', 'c'); + INSERT INTO t2 VALUES('c', 'a', 'b'); + INSERT INTO t2 VALUES('b', 'c', 'a'); +} +do_execsql_test 5.2 { SELECT docid FROM t2 WHERE t2 MATCH 'a' } {2} +do_execsql_test 5.3 { SELECT docid FROM t2 WHERE t2 MATCH 'b' } {1} +do_execsql_test 5.4 { SELECT docid FROM t2 WHERE t2 MATCH 'c' } {3} + +do_execsql_test 5.x { DROP TABLE t2 } finish_test + + + From adbae616bdbbd264514df275958ef566250b524b Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 21 Jun 2013 18:36:44 +0000 Subject: [PATCH 141/144] Remove an unused function declaration from the FTS3 source code. FossilOrigin-Name: 096ae1d8f9a08f92daedece6b0615f4d22b05023 --- ext/fts3/fts3Int.h | 1 - manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index afb152dc73..59beae5938 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -434,7 +434,6 @@ int sqlite3Fts3SegReaderPending( Fts3Table*,int,const char*,int,int,Fts3SegReader**); void sqlite3Fts3SegReaderFree(Fts3SegReader *); int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, int, sqlite3_stmt **); -int sqlite3Fts3ReadLock(Fts3Table *); int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*); int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **); diff --git a/manifest b/manifest index f3a124c901..cb36277b86 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\sfts4-notindexed\sbranch\swith\sthe\strunk. -D 2013-06-21T18:29:49.697 +C Remove\san\sunused\sfunction\sdeclaration\sfrom\sthe\sFTS3\ssource\scode. +D 2013-06-21T18:36:44.416 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -80,7 +80,7 @@ F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d F ext/fts3/fts3.c 3cb4afd0accf903fbe66e2cc48d6f44e5ccb8a76 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h 2659cdfc8cde3f981ea99b2f60383e6239f9f4d5 +F ext/fts3/fts3Int.h a50cd231e906da818f00f0a81845bbf7bbeba002 F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 @@ -1094,7 +1094,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b674462243138fcee192ef05d434665e30c681c4 b53c0c41f97c7ddaeea61f0e6035d1c4747db3f7 -R 78eae7e4eba9ee605ccaf88bbcc953f5 -U dan -Z d8def49936980c4606b68402ae38fa82 +P 361084e1eb281e985568d19fe217263be92be31d +R 0d6c636b8cfd628682ea33e027cb07be +U drh +Z 55b5720fc386809651d148c0a8415781 diff --git a/manifest.uuid b/manifest.uuid index eb0a0c67b7..773d5a6db0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -361084e1eb281e985568d19fe217263be92be31d \ No newline at end of file +096ae1d8f9a08f92daedece6b0615f4d22b05023 \ No newline at end of file From 1031bd99581c1c3d7da99eb1c9a74a4cf053e0da Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 22 Jun 2013 15:44:26 +0000 Subject: [PATCH 142/144] Add the ability to disable the omit-join-table optimization for testing purposes. FossilOrigin-Name: d929df9b1ba214c27d8c437099a53ee9b07aa169 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 1 + src/where.c | 5 ++++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index a54bc73242..1bb860ddcd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Only\seliminate\sinner\sloops\sof\sa\sJOIN\sif\sthey\sare\sthe\sRHS\sof\sa\sLEFT\sJOIN\nand\sif\sthey\sgive\sno\smore\sthan\sa\ssingle\sresult.\s\sThis\sappears\sto\sgive\scorrect\nanswers\sin\sall\scases. -D 2013-06-21T02:15:48.306 +C Add\sthe\sability\sto\sdisable\sthe\somit-join-table\soptimization\sfor\stesting\npurposes. +D 2013-06-22T15:44:26.893 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,7 @@ F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h cabeb0401566d80503a0bc6e2d12e7fe2577bf6d +F src/sqliteInt.h e6f069b07fdef1ab54034940b7a6e7be2b4efd57 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -289,7 +289,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 0ca9544cca6e40550b970574a32055463650df12 +F src/where.c 9bcfcb4ec6a14dd0111bf287bee02be88d5709f9 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P ca839723a21bb13d3e0666a672c15c6f3a267c2f -R 6b62f4d6f88cb9d978862e981acfa473 +P d7a25cc79794817504ca1a4262008a68b2a4dece +R ca6216e1e7f1e0a7cea14bc87e274a42 U drh -Z b99e6e4ea8d5a45c0b5323f96846f0b0 +Z 6a72a8bdf1b2e20868f42b8b65540410 diff --git a/manifest.uuid b/manifest.uuid index 32c308b877..f7dd8d6565 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d7a25cc79794817504ca1a4262008a68b2a4dece \ No newline at end of file +d929df9b1ba214c27d8c437099a53ee9b07aa169 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 731612d345..0a661937ff 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1024,6 +1024,7 @@ struct sqlite3 { #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ +#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* diff --git a/src/where.c b/src/where.c index 32fa61c7f0..e20f2b3018 100644 --- a/src/where.c +++ b/src/where.c @@ -5789,7 +5789,10 @@ WhereInfo *sqlite3WhereBegin( } #endif /* Attempt to omit tables from the join that do not effect the result */ - if( pResultSet!=0 && pWInfo->nLevel>=2 ){ + if( pWInfo->nLevel>=2 + && pResultSet!=0 + && OptimizationEnabled(db, SQLITE_OmitNoopJoin) + ){ Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet); if( pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, pOrderBy); while( pWInfo->nLevel>=2 ){ From bf159fa21b14fc7d6f42d3ddda43feed3144928e Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 25 Jun 2013 22:01:22 +0000 Subject: [PATCH 143/144] Add a new (experimental) sqlite3_stmt_status() verb that returns the number of VM steps. FossilOrigin-Name: f1366bab737a3ac2ea20a0ec014cc306d7ded8a5 --- manifest | 23 +++++++++++++---------- manifest.uuid | 2 +- src/shell.c | 2 ++ src/sqlite.h.in | 10 ++++++++++ src/test1.c | 1 + src/vdbe.c | 5 ++++- src/vdbeInt.h | 2 +- 7 files changed, 32 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index cb36277b86..ef2d2ada38 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunused\sfunction\sdeclaration\sfrom\sthe\sFTS3\ssource\scode. -D 2013-06-21T18:36:44.416 +C Add\sa\snew\s(experimental)\ssqlite3_stmt_status()\sverb\sthat\sreturns\sthe\snumber\nof\sVM\ssteps. +D 2013-06-25T22:01:22.917 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -216,8 +216,8 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 22ee971346a736ddefdc4497d07c92f2e9978afc -F src/shell.c ab6eea968c8745be3aa74e45fedb37d057b4cd0d -F src/sqlite.h.in 5b390ca5d94e09e56e7fee6a51ddde4721b89f8e +F src/shell.c a02544af6697c5782d29ec3204616f35ed9e8458 +F src/sqlite.h.in 5f86553f4c1d8b4a9069285ed19e7981451ea77a F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 F src/sqliteInt.h 46fb17f604ce941551fe64c342dbeb4dbed3edaa @@ -225,7 +225,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c b8835978e853a89bf58de88acc943a5ca94d752e -F src/test1.c 6d2a340eea1d866bf7059894491652a69a7ee802 +F src/test1.c d94d55d85e7250fa3493585635811c584b1d05be F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -276,9 +276,9 @@ F src/update.c 4c0c6864c4349ba292042e984a56d15985b57f4e F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 F src/vacuum.c ddf21cc9577c4cb459d08bee9863a78ec000c5bb -F src/vdbe.c 34929e1b5bd95a85b5e1b7767b5cc8da582ad78d +F src/vdbe.c af2bc360189ce8eaed47133037e082a1652bc4a0 F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d -F src/vdbeInt.h c1e830268b75f04a2901dd895b51a637a26c7045 +F src/vdbeInt.h b8a76f7b7304abfdb8e6bd286eba954ecfe73863 F src/vdbeapi.c 0b2c78797058c6c9bfa1687977de039566e22877 F src/vdbeaux.c af9cd9372c7ab82294b9645723e652c2d4213b95 F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69 @@ -1094,7 +1094,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 361084e1eb281e985568d19fe217263be92be31d -R 0d6c636b8cfd628682ea33e027cb07be +P 096ae1d8f9a08f92daedece6b0615f4d22b05023 +R dca9e91df626c57b27d64840398d576b +T *branch * status-vm-step +T *sym-status-vm-step * +T -sym-trunk * U drh -Z 55b5720fc386809651d148c0a8415781 +Z 5f8be8eb1fd8b6cd7aa46981a30c4d1b diff --git a/manifest.uuid b/manifest.uuid index 773d5a6db0..6702da1e76 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -096ae1d8f9a08f92daedece6b0615f4d22b05023 \ No newline at end of file +f1366bab737a3ac2ea20a0ec014cc306d7ded8a5 \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 9f2f46bd18..9a8a906944 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1109,6 +1109,8 @@ static int display_stats( fprintf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); + fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur); } return 0; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 0d23f38944..0921d23a09 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6303,11 +6303,21 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** A non-zero value in this counter may indicate an opportunity to ** improvement performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run. +** +** [[SQLITE_STMTSTATUS_VM_STEP]]
SQLITE_STMTSTATUS_VM_STEP
+**
^This is the number of virtual machine operations executed +** by the prepared statement if that number is less than or equal +** to 2147483647. The number of virtual machine operations can be +** used as a proxy for the total work done by the prepared statement. +** If the number of virtual machine operations exceeds 2147483647 +** then the value returned by this statement status code is undefined. +**
** */ #define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 +#define SQLITE_STMTSTATUS_VM_STEP 4 /* ** CAPI3REF: Custom Page Cache Object diff --git a/src/test1.c b/src/test1.c index bd6d4a4cfd..a4df0e764f 100644 --- a/src/test1.c +++ b/src/test1.c @@ -2218,6 +2218,7 @@ static int test_stmt_status( { "SQLITE_STMTSTATUS_FULLSCAN_STEP", SQLITE_STMTSTATUS_FULLSCAN_STEP }, { "SQLITE_STMTSTATUS_SORT", SQLITE_STMTSTATUS_SORT }, { "SQLITE_STMTSTATUS_AUTOINDEX", SQLITE_STMTSTATUS_AUTOINDEX }, + { "SQLITE_STMTSTATUS_VM_STEP", SQLITE_STMTSTATUS_VM_STEP }, }; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT PARAMETER RESETFLAG"); diff --git a/src/vdbe.c b/src/vdbe.c index 7abc2889df..81b40628e1 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -556,12 +556,13 @@ int sqlite3VdbeExec( int checkProgress; /* True if progress callbacks are enabled */ int nProgressOps = 0; /* Opcodes executed since progress callback. */ #endif + int iCompare = 0; /* Result of last OP_Compare operation */ + unsigned nVmStep = 0; /* Number of virtual machine steps */ Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ Mem *pIn2 = 0; /* 2nd input operand */ Mem *pIn3 = 0; /* 3rd input operand */ Mem *pOut = 0; /* Output operand */ - int iCompare = 0; /* Result of last OP_Compare operation */ int *aPermute = 0; /* Permutation of columns for OP_Compare */ i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */ #ifdef VDBE_PROFILE @@ -606,6 +607,7 @@ int sqlite3VdbeExec( origPc = pc; start = sqlite3Hwtime(); #endif + nVmStep++; pOp = &aOp[pc]; /* Only allow tracing if SQLITE_DEBUG is defined. @@ -6200,6 +6202,7 @@ vdbe_error_halt: ** top. */ vdbe_return: db->lastRowid = lastRowid; + p->aCounter[SQLITE_STMTSTATUS_VM_STEP-1] += (int)nVmStep; sqlite3VdbeLeave(p); return rc; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 3a5b4028bb..dc42187f06 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -344,7 +344,7 @@ struct Vdbe { yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ int iStatement; /* Statement number (or 0 if has not opened stmt) */ - int aCounter[3]; /* Counters used by sqlite3_stmt_status() */ + int aCounter[4]; /* Counters used by sqlite3_stmt_status() */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif From 2c036cff3d2fa5e993448ef1aeaf9e1eab388749 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 26 Jun 2013 00:34:13 +0000 Subject: [PATCH 144/144] Fix an uninitialized variable detected by valgrind. Unclear whether or not this should apply to trunk. FossilOrigin-Name: 19ab4811d542ba781aeb6a4eb3c74642677225e1 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index e7e71b5de4..a758c3108d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\sNEVER()\smacro\sand\san\sexplanation\scomment\saround\san\sunreachable\sbranch\nin\sthe\sSTAT3\slogic. -D 2013-06-20T17:32:28.451 +C Fix\san\suninitialized\svariable\sdetected\sby\svalgrind.\s\sUnclear\swhether\sor\snot\nthis\sshould\sapply\sto\strunk. +D 2013-06-26T00:34:13.504 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -171,7 +171,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778 -F src/expr.c 3286e703adde34865d3a2cb62f9f4f31e3d2f2ed +F src/expr.c 2b47ae9da6c9f34eff6736962ea2e102c6c4a755 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179 F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef @@ -1096,7 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P d94db3fd921890ab1d6414ab629410ae50779686 -R 4877ecf4e1d53d3b49ba9f1fadfb6d66 +P 604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 +R 2ed2dcc6fe1201d795c5181c6afd8a91 U drh -Z c939c499a0659dd37def1fcbcc79c922 +Z 9f76be0e05737d7f0f0ba2111ccc0b78 diff --git a/manifest.uuid b/manifest.uuid index bda9422793..4852f22866 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 \ No newline at end of file +19ab4811d542ba781aeb6a4eb3c74642677225e1 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index d066e9b8bc..2c0419aa2e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -920,6 +920,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan); pItem->sortOrder = pOldItem->sortOrder; pItem->done = 0; + pItem->bSpanIsTab = pOldItem->bSpanIsTab; pItem->iOrderByCol = pOldItem->iOrderByCol; pItem->iAlias = pOldItem->iAlias; }