When processing an "ORDER BY ... LIMIT" that does not use an index, check
whether or not a record may appear in the final result set before adding it to the sorter. FossilOrigin-Name: 71bf91c218334381b1b4bdba6a093e623b62e17f3e8550e154a11f0cb0b404f3
This commit is contained in:
parent
de7ca50dac
commit
f226f03d4f
17
manifest
17
manifest
@ -1,5 +1,5 @@
|
||||
C Clarification\sof\sthe\sbehavior\sof\sa\sBEFORE\sUPDATE\strigger\swhen\sthe\strigger\nchanges\sthe\svalues\sof\ssome\sof\sthe\scolumns\sused\sto\scompute\snew\scolumns\sin\nthe\sUPDATE.
|
||||
D 2018-04-26T15:04:18.138
|
||||
C When\sprocessing\san\s"ORDER\sBY\s...\sLIMIT"\sthat\sdoes\snot\suse\san\sindex,\scheck\nwhether\sor\snot\sa\srecord\smay\sappear\sin\sthe\sfinal\sresult\sset\sbefore\sadding\sit\sto\nthe\ssorter.
|
||||
D 2018-04-26T16:13:47.273
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 5ce9343cba9c189046f1afe6d2bcc1f68079439febc05267b98aec6ecc752439
|
||||
@ -492,7 +492,7 @@ F src/printf.c d3b7844ddeb11fbbdd38dd84d09c9c1ac171d21fb038473c3aa97981201cc660
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 6415381a0e9d22c0e7cba33ca4a53f81474190862f5d4838190f5eb5b0b47bc9
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 3dbce4379836189acbc5719f40125f3d1e0dbaee024ec4550ab449744a8cb074
|
||||
F src/select.c daf07d8defce3311f9e69f1280a874d78bc1d16c305f6aa689640f7afa02842f
|
||||
F src/shell.c.in d63f06c870ec1761ea98bd1cae651ff0ea6beadf8be892105dabd913f94cb3da
|
||||
F src/sqlite.h.in 8e70752a57597c08f64f3d49fc1fc46926b862d2e23b038b0d23b9cc748d88ea
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
@ -1725,7 +1725,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 368c14da868a843767344f6cc17c499fddd83244c0510337ed9a918e64ee2413
|
||||
R d67c07078741cec11cd337cb536cdcc8
|
||||
U drh
|
||||
Z aca21fa0a22205b706503004c2920563
|
||||
P 7bb23c2a3d37f0d5e5515b917860818906819d54a0066e1ba8e9792a82f7d279
|
||||
R 6079da62ec760c692d1ac980ae12bf44
|
||||
T *branch * sorter-limit-opt
|
||||
T *sym-sorter-limit-opt *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 8f9d35d6b39a3409ee54166c5149a9b9
|
||||
|
@ -1 +1 @@
|
||||
7bb23c2a3d37f0d5e5515b917860818906819d54a0066e1ba8e9792a82f7d279
|
||||
71bf91c218334381b1b4bdba6a093e623b62e17f3e8550e154a11f0cb0b404f3
|
59
src/select.c
59
src/select.c
@ -579,7 +579,6 @@ static void pushOntoSorter(
|
||||
if( nPrefixReg==0 && nData>0 ){
|
||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
|
||||
if( nOBSat>0 ){
|
||||
int regPrevKey; /* The first nOBSat columns of the previous row */
|
||||
int addrFirst; /* Address of the OP_IfNot opcode */
|
||||
@ -588,6 +587,7 @@ static void pushOntoSorter(
|
||||
int nKey; /* Number of sorting key columns, including OP_Sequence */
|
||||
KeyInfo *pKI; /* Original KeyInfo on the sorter table */
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat,regRecord);
|
||||
regPrevKey = pParse->nMem+1;
|
||||
pParse->nMem += pSort->nOBSat;
|
||||
nKey = nExpr - pSort->nOBSat + bSeq;
|
||||
@ -621,6 +621,35 @@ static void pushOntoSorter(
|
||||
sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
|
||||
sqlite3VdbeJumpHere(v, addrJmp);
|
||||
}
|
||||
if( iLimit ){
|
||||
/* At this point the values for the new sorter entry are stored
|
||||
** in an array of registers. They need to be composed into a record
|
||||
** and inserted into the sorter if either (a) there are currently
|
||||
** less than LIMIT+OFFSET items or (b) the new record is smaller than
|
||||
** the largest record currently in the sorter. If (b) is true and there
|
||||
** are already LIMIT+OFFSET items in the sorter, delete the largest
|
||||
** entry before inserting the new one. This way there are never more
|
||||
** 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.
|
||||
*/
|
||||
int iCsr = pSort->iECursor;
|
||||
int iJmp = sqlite3VdbeCurrentAddr(v)+5+(nOBSat<=0)+pSort->bOrderedInnerLoop;
|
||||
assert( pSort->bOrderedInnerLoop==0 || pSort->bOrderedInnerLoop==1 );
|
||||
sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Last, iCsr, 0);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxLE, iCsr, iJmp, regBase+nOBSat, nExpr-nOBSat);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp1(v, OP_Delete, iCsr);
|
||||
}
|
||||
if( nOBSat<=0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat,regRecord);
|
||||
}
|
||||
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||
op = OP_SorterInsert;
|
||||
}else{
|
||||
@ -628,34 +657,6 @@ static void pushOntoSorter(
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
|
||||
regBase+nOBSat, nBase-nOBSat);
|
||||
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 = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); 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);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user