-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
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
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
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
*/
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 */
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","");
}
}
/*
-** 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; i<nOrderBy; i++){
+ pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[nUsed].pExpr);
+ if( pOBExpr->op!=TK_COLUMN ) return 0;
+ }
+
+ for(i=0; i<=nLoop && nUsed<nOrderBy; i++){
+ pLoop = i<nLoop ? pPath->aLoop[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; j<nColumn && nUsed<nOrderBy; j++, nUsed++){
+ pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[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)<<i;
+ }
+ if( nUsed==nOrderBy ){
+ *pRevMask = revMask;
+ return 1;
+ }
+ return -1;
}
for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
for(pWLoop=pWInfo->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;
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;
}
/* 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;
&& (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; ii<nTabList; ii++){
whereLoopPrint(pWInfo->a[ii].pWLoop, pTabList);
}