aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordan <dan@noemail.net>2014-03-19 20:01:25 +0000
committerdan <dan@noemail.net>2014-03-19 20:01:25 +0000
commit344510e62b113a570f1b2bc6c1a59c5de8ccd51a (patch)
tree26d27cdab6436230d54afc643d2640646e35837f /src
parent0e682099a1ee1bf0b63937834b952f77ec55f1b5 (diff)
downloadsqlite-344510e62b113a570f1b2bc6c1a59c5de8ccd51a.tar.gz
sqlite-344510e62b113a570f1b2bc6c1a59c5de8ccd51a.zip
Avoid some unnecessary calls to sqlite3VdbeRecordUnpack() that were being made when merging data from two or more temp files together in vdbesort.c
FossilOrigin-Name: 707ea170b3e26965b7e3982f7554d122d130b9a6
Diffstat (limited to 'src')
-rw-r--r--src/vdbesort.c53
1 files changed, 47 insertions, 6 deletions
diff --git a/src/vdbesort.c b/src/vdbesort.c
index b9ed97e8b..f971c2d93 100644
--- a/src/vdbesort.c
+++ b/src/vdbesort.c
@@ -956,14 +956,55 @@ int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
if( pSorter->aTree ){
int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
- int i; /* Index of aTree[] to recalculate */
-
rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
- for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){
- rc = vdbeSorterDoCompare(pCsr, i);
- }
+ if( rc==SQLITE_OK ){
+ int i; /* Index of aTree[] to recalculate */
+ VdbeSorterIter *pIter1; /* First iterator to compare */
+ VdbeSorterIter *pIter2; /* Second iterator to compare */
+ u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */
+
+ /* Find the first two iterators to compare. The one that was just
+ ** advanced (iPrev) and the one next to it in the array. */
+ pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)];
+ pIter2 = &pSorter->aIter[(iPrev | 0x0001)];
+ pKey2 = pIter2->aKey;
+
+ for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){
+ /* Compare pIter1 and pIter2. Store the result in variable iRes. */
+ int iRes;
+ if( pIter1->pFile==0 ){
+ iRes = +1;
+ }else if( pIter2->pFile==0 ){
+ iRes = -1;
+ }else{
+ vdbeSorterCompare(pCsr, 0,
+ pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes
+ );
+ }
- *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
+ /* If pIter1 contained the smaller value, set aTree[i] to its index.
+ ** Then set pIter2 to the next iterator to compare to pIter1. In this
+ ** case there is no cache of pIter2 in pSorter->pUnpacked, so set
+ ** pKey2 to point to the record belonging to pIter2.
+ **
+ ** Alternatively, if pIter2 contains the smaller of the two values,
+ ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare()
+ ** was actually called above, then pSorter->pUnpacked now contains
+ ** a value equivalent to pIter2. So set pKey2 to NULL to prevent
+ ** vdbeSorterCompare() from decoding pIter2 again. */
+ if( iRes<=0 ){
+ pSorter->aTree[i] = (pIter1 - pSorter->aIter);
+ pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
+ pKey2 = pIter2->aKey;
+ }else{
+ if( pIter1->pFile ) pKey2 = 0;
+ pSorter->aTree[i] = (pIter2 - pSorter->aIter);
+ pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
+ }
+
+ }
+ *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
+ }
}else{
SorterRecord *pFree = pSorter->pRecord;
pSorter->pRecord = pFree->pNext;