diff --git a/manifest b/manifest index 89053f9deb..d01cdd7db8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixup\scomments\son\swctrlFlags\svalue\sdefinitions. -D 2016-05-19T19:31:30.127 +C In\sa\squery\swith\sboth\sORDER\sBY\sand\sLIMIT,\sif\sthe\sinner\sloop\ssatisfies\sthe\s\nORDER\sBY\sthen\stry\sto\scut\sshort\seach\sinvocation\sof\sthe\sinner\sloop\sonce\sthe\nLIMIT\shas\sbeen\ssatisfied.\s\sThis\scheck-in\sis\sa\spartial\simplementation\sonly. +D 2016-05-19T22:13:37.318 F Makefile.in f59e0763ff448719fc1bd25513882b0567286317 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 306d73e854b1a92ea06e5d1e637faa5c44de53c7 @@ -378,12 +378,12 @@ F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c cca3aa77b95706df5d635a2141a4d1de60ae6598 F src/rowset.c 49eb91c588a2bab36647368e031dc5b66928149d -F src/select.c fd4a7ce2937497181063cfedb92058ac89491a5d +F src/select.c 131eeddfcaf3777c4acd4727bf742b98af8183b5 F src/shell.c 14ff7f660530a52b117d110ba3390b7b2eb719b6 F src/sqlite.h.in 9984129d86243424b765fcb3f147c697bd20bb54 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2 -F src/sqliteInt.h 19de316bfce65ff074b379a67b493a446f3cf8ee +F src/sqliteInt.h 863cf0d421611ccfa30541ee5ffe761c896ffa5b F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247 F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9 @@ -458,8 +458,8 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 4db22ed7e77bcf672b1a685d6ddeffba8d5be302 F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354 -F src/where.c 72fd2e1258625c1aee8e33a529914aea2d487422 -F src/whereInt.h 3b1fc240e322613ba4e9dc857ca9c7c3390acc74 +F src/where.c a7454e62ca13f1ff54892339022f8cb0a8bb3728 +F src/whereInt.h 6e18240be400bef8e4dbafea605251707c5dbf49 F src/wherecode.c e3f18fcda2d7f8218a09dc33cf495dca0efa6e3e F src/whereexpr.c eacc0e60d029a082b4fc0cc42ea98544add1319e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1489,7 +1489,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d01305841da94b2d47e32744802f69525bf590df -R be830660ecf90ba00189952af638cb97 +P 58b516e8c0b00a41bc0364eab267bc2ecb9efeff +R 766495aa6109f75a3c3b0e829e8d3b47 +T *branch * orderby-limit +T *sym-orderby-limit * +T -sym-trunk * U drh -Z 54bddff0ee366139e2fb13081e6cf75a +Z 1f191cc43f073ab10b6b672b5a12f950 diff --git a/manifest.uuid b/manifest.uuid index 177ef2d35a..ec9b410bfa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -58b516e8c0b00a41bc0364eab267bc2ecb9efeff \ No newline at end of file +852d1eda6ecca1171f6ed800b06f5b4854672002 \ No newline at end of file diff --git a/src/select.c b/src/select.c index eb37536b6f..080ccf3480 100644 --- a/src/select.c +++ b/src/select.c @@ -56,6 +56,7 @@ struct SortCtx { int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ + u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ @@ -589,9 +590,29 @@ static void pushOntoSorter( sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); if( iLimit ){ int addr; + int r1 = 0; + /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit + ** register is initialized with value of LIMIT+OFFSET.) After the sorter + ** fills up, delete the least entry in the sorter after each insert. + ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */ addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + r1 = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1); + VdbeComment((v, "seq")); + } sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + /* If the inner loop is driven by an index such that values from + ** the same iteration of the inner loop are in sorted order, then + ** immediately jump to the next iteration of an inner loop if the + ** entry from the current iteration does not fit into the top + ** LIMIT+OFFSET entries of the sorter. */ + int iBrk = sqlite3VdbeCurrentAddr(v) + 2; + sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1); + VdbeCoverage(v); + } sqlite3VdbeJumpHere(v, addr); } } @@ -5176,6 +5197,7 @@ int sqlite3Select( } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); + sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c795036666..7adfd3779b 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3637,6 +3637,7 @@ void sqlite3WhereEnd(WhereInfo*); LogEst sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); +int sqlite3WhereOrderedInnerLoop(WhereInfo*); int sqlite3WhereIsSorted(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*); diff --git a/src/where.c b/src/where.c index f6f6f68eab..521d2e19ec 100644 --- a/src/where.c +++ b/src/where.c @@ -51,6 +51,18 @@ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } +/* +** Return TRUE if the innermost loop of the WHERE clause implementation +** returns rows in ORDER BY order for complete run of the inner loop. +** +** Across multiple iterations of outer loops, the output rows need not be +** sorted. As long as rows are sorted for just the innermost loop, this +** routine can return TRUE. +*/ +int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){ + return pWInfo->bOrderedInnerLoop; +} + /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. @@ -3898,8 +3910,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ } }else{ pWInfo->nOBSat = pFrom->isOrdered; - if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; pWInfo->revMask = pFrom->revLoop; + if( pWInfo->nOBSat<=0 ){ + pWInfo->nOBSat = 0; + } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 diff --git a/src/whereInt.h b/src/whereInt.h index d33d995af1..ed6b198e4b 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -418,8 +418,9 @@ struct WhereInfo { u8 sorted; /* True if really sorted (not just grouped) */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ - u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ + u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ u8 nLevel; /* Number of nested loop */ + u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */ 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 */