-C Add\sa\smissing\scall\sto\sfree()\sin\sLemon.
-D 2018-09-08T16:55:18.635
+C Fix\smultiple\sissues\swith\sthe\sORDER\sBY\sLIMIT\soptimization.\s\sThis\sis\sthe\nproposed\sresolution\sto\sticket\s[9936b2fa443fec03ff25].
+D 2018-09-08T20:09:46.990
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 6b650013511fd9d8b094203ac268af9220d292cc7d4e1bc9fbca15aacd8c7995
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 352c6af1a99441206ff62a6f7429dbf537827f42c428639695220b9c8639e33b
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
-F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04
+F src/select.c ed6192ddd09a97169cb1c6d732b26c0f647b72d5fa8ca401c7ee1180fbbe521a
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
F src/sqlite.h.in cdf2a539cd0570322a94bcb97c01c56feb1be0657ec7cfb8273c89d19fff87a9
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
-F src/sqliteInt.h c72e50d876b1fd909db70399a228d022a44b6a7326a6031f76594acdfd25b69e
+F src/sqliteInt.h f63f04e3db06b605ead2d9bb8eda8bc3add3baf3da9655954dfb24860e625933
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/wal.c df50883d93689d009be5ad9bdc4e53a4ee45fcc291087ec9272569d00b360791
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4
-F src/where.c 155809967fbab889374dedf970ea6561b8fb519fcb165d6ba00776552ecc5cde
+F src/where.c 5192013a21843523f4772087a56e59db73bd4c7401349968120dc0693b7c4eb4
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
F src/wherecode.c 2b6cd1b27736cc803060289e04ecf9849976106f4077aa67d1a2c0e3ec420159
F src/whereexpr.c d87df2c00ecc0c2ef4409562608d19cec259a6a03ca72b86fc999db9c07ce119
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
F test/like3.test 3608a2042b6f922f900fbfd5d3ce4e7eca57f7c4
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
-F test/limit2.test 360982809e03211636d2b18ddbc97d5da06826941370607e4b00e113f827cb5a
+F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e
F test/loadext.test d077450695ddb5c1ea3ad7d48e5f5850fe732ad9
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
F test/lock.test be4fe08118fb988fed741f429b7dd5d65e1c90db
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P e812e5d59a699e8b82c51d465d9c0f09df6a1e6996b5499814dca99c5f8020d5
-R 985ed317810844fbd8e283aa0c269697
-U mistachkin
-Z e4dcf479c4692c03c98ec48ee992b041
+P 8b4cf33aafe09d9009119dcbd464b54be9605af5701002ee458819efa6e2e1f9
+R 314bbe63eed86b2216509901a995337d
+U drh
+Z 40fd1d6c79004b4386462b0fab14be9d
-8b4cf33aafe09d9009119dcbd464b54be9605af5701002ee458819efa6e2e1f9
\ No newline at end of file
+206720129ed2fa8875a286266d05b99fb2caf8671e4b74b26a6286a2073fcd8b
\ No newline at end of file
int labelBkOut; /* Start label for the block-output subroutine */
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
int labelDone; /* Jump here when done, ex: LIMIT reached */
+ int labelOBLopt; /* Jump here when sorter is full */
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
- u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
u8 nDefer; /* Number of valid entries in aDefer[] */
struct DeferredCsr {
** than LIMIT+OFFSET items in the sorter.
**
** If the new record does not need to be inserted into the sorter,
- ** jump to the next iteration of the loop. Or, if the
- ** pSort->bOrderedInnerLoop flag is set to indicate that the inner
- ** loop delivers items in sorted order, jump to the next iteration
- ** of the outer loop.
+ ** jump to the next iteration of the loop. If the pSort->labelOBLopt
+ ** value is not zero, then it is a label of where to jump. Otherwise,
+ ** just bypass the row insert logic. See the header comment on the
+ ** sqlite3WhereOrderByLimitOptLabel() function for additional info.
*/
int iCsr = pSort->iECursor;
sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4);
sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
regBase+nOBSat, nBase-nOBSat);
if( iSkip ){
- assert( pSort->bOrderedInnerLoop==0 || pSort->bOrderedInnerLoop==1 );
sqlite3VdbeChangeP2(v, iSkip,
- sqlite3VdbeCurrentAddr(v) + pSort->bOrderedInnerLoop);
+ pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v));
}
}
}
if( sSort.pOrderBy ){
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
- sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
+ sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo);
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
sSort.pOrderBy = 0;
}
LogEst sqlite3WhereOutputRowCount(WhereInfo*);
int sqlite3WhereIsDistinct(WhereInfo*);
int sqlite3WhereIsOrdered(WhereInfo*);
-int sqlite3WhereOrderedInnerLoop(WhereInfo*);
+int sqlite3WhereOrderByLimitOptLabel(WhereInfo*);
int sqlite3WhereIsSorted(WhereInfo*);
int sqlite3WhereContinueLabel(WhereInfo*);
int sqlite3WhereBreakLabel(WhereInfo*);
}
/*
-** Return TRUE if the innermost loop of the WHERE clause implementation
-** returns rows in ORDER BY order for complete run of the inner loop.
+** In the ORDER BY LIMIT optimization, if the inner-most loop is known
+** to emit rows in increasing order, and if the last row emitted by the
+** inner-most loop did not fit within the sorter, then we can skip all
+** subsequent rows for the current iteration of the inner loop (because they
+** will not fit in the sorter either) and continue with the second inner
+** loop - the loop immediately outside the inner-most.
**
-** 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.
+** When a row does not fit in the sorter (because the sorter already
+** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the
+** label returned by this function.
+**
+** If the ORDER BY LIMIT optimization applies, the jump destination should
+** be the continuation for the second-inner-most loop. If the ORDER BY
+** LIMIT optimization does not apply, then the jump destination should
+** be the continuation for the inner-most loop.
+**
+** It is always safe for this routine to return the continuation of the
+** inner-most loop, in the sense that a correct answer will result.
+** Returning the continuation the second inner loop is an optimization
+** that might make the code run a little faster, but should not change
+** the final answer.
*/
-int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
- return pWInfo->bOrderedInnerLoop;
+int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){
+ WhereLevel *pInner;
+ if( !pWInfo->bOrderedInnerLoop ){
+ /* The ORDER BY LIMIT optimization does not apply. Jump to the
+ ** continuation of the inner-most loop. */
+ return pWInfo->iContinue;
+ }
+ pInner = &pWInfo->a[pWInfo->nLevel-1];
+ if( pInner->addrNxt ) return pInner->addrNxt;
+ return pInner->addrBrk;
}
/*
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}
+ pWInfo->bOrderedInnerLoop = 0;
if( pWInfo->pOrderBy ){
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
SELECT y FROM t1, t2 WHERE a=x AND b<=y ORDER BY b DESC;
} {3}
+# Ticket https://www.sqlite.org/src/info/9936b2fa443fec03 2018-09-08
+# Infinite loop due to the ORDER BY LIMIT optimization.
+#
+do_execsql_test 700 {
+ DROP TABLE IF EXISTS t1;
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t1(aa VARCHAR PRIMARY KEY NOT NULL,bb,cc,x VARCHAR(400));
+ INSERT INTO t1(aa,bb,cc) VALUES('maroon','meal','lecture');
+ INSERT INTO t1(aa,bb,cc) VALUES('reality','meal','catsear');
+ CREATE TABLE t2(aa VARCHAR PRIMARY KEY, dd INT DEFAULT 1, ee, x VARCHAR(100));
+ INSERT INTO t2(aa,dd,ee) VALUES('maroon',0,'travel'),('reality',0,'hour');
+ CREATE INDEX t2x1 ON t2(dd,ee);
+ ANALYZE;
+ DROP TABLE IF EXISTS sqlite_stat4;
+ DELETE FROM sqlite_stat1;
+ INSERT INTO sqlite_stat1 VALUES
+ ('t2','t2x1','3 3 3'),
+ ('t2','sqlite_autoindex_t2_1','3 1'),
+ ('t1','sqlite_autoindex_t1_1','2 1');
+ ANALYZE sqlite_master;
+ SELECT *
+ FROM t1 LEFT JOIN t2 ON t1.aa=t2.aa
+ WHERE t1.bb='meal'
+ ORDER BY t2.dd DESC
+ LIMIT 1;
+} {maroon meal lecture {} maroon 0 travel {}}
+do_execsql_test 710 {
+ DROP TABLE t1;
+ DROP TABLE t2;
+ CREATE TABLE t1(aa, bb);
+ INSERT INTO t1 VALUES('maroon','meal');
+ CREATE TABLE t2(cc, dd, ee, x VARCHAR(100));
+ INSERT INTO t2(cc,dd,ee) VALUES('maroon',1,'one');
+ INSERT INTO t2(cc,dd,ee) VALUES('maroon',2,'two');
+ INSERT INTO t2(cc,dd,ee) VALUES('maroon',0,'zero');
+ CREATE INDEX t2ddee ON t2(dd,ee);
+ CREATE INDEX t2cc ON t2(cc);
+ ANALYZE;
+ SELECT t2.cc, t2.dd, t2.ee FROM t1 CROSS JOIN t2 ON t1.aa=t2.cc
+ ORDER BY t2.dd LIMIT 1;
+} {maroon 0 zero}
+do_execsql_test 720 {
+ SELECT t2.cc, t2.dd, t2.ee FROM t1 CROSS JOIN t2 ON t1.aa=t2.cc
+ WHERE t1.bb='meal'
+ ORDER BY t2.dd LIMIT 1;
+} {maroon 0 zero}
+
finish_test