]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
When processing an "ORDER BY ... LIMIT" that does not use an index, check sorter-limit-opt
authordan <dan@noemail.net>
Thu, 26 Apr 2018 16:13:47 +0000 (16:13 +0000)
committerdan <dan@noemail.net>
Thu, 26 Apr 2018 16:13:47 +0000 (16:13 +0000)
whether or not a record may appear in the final result set before adding it to
the sorter.

FossilOrigin-Name: 71bf91c218334381b1b4bdba6a093e623b62e17f3e8550e154a11f0cb0b404f3

manifest
manifest.uuid
src/select.c

index 954f369eef16d009ac52cb99bbab73f09354436e..21484880f4467e6a4bcb2eb4a2b6f1a7f4b4c1f0 100644 (file)
--- a/manifest
+++ b/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
index 1c442962fc9447cee620439d6ca2f5f47fd3516e..2cb0bbfb3c4ce9c33bf3439fe8ea2b8d9729f473 100644 (file)
@@ -1 +1 @@
-7bb23c2a3d37f0d5e5515b917860818906819d54a0066e1ba8e9792a82f7d279
\ No newline at end of file
+71bf91c218334381b1b4bdba6a093e623b62e17f3e8550e154a11f0cb0b404f3
\ No newline at end of file
index 79fc211147e2705638740b54eb1f4eb3a80f0a9f..ac313d028899491250522a929fe85fc77be03ca1 100644 (file)
@@ -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);
-  }
 }
 
 /*