Change sqlite3BtreeNext() and sqlite3BtreePrevious() so that they return

SQLITE_DONE if they have already reached the end (or beginning) of the table.
This gives a performance increase and size reduction.

FossilOrigin-Name: e972a3860892022d57b26ec44ce0fbadc61c1ff54b7a10b7e82390db88d323a7
This commit is contained in:
drh 2017-05-30 18:34:07 +00:00
parent d26d2c7de2
commit 2ab792e4c0
9 changed files with 111 additions and 100 deletions

View File

@ -1,5 +1,5 @@
C Omit\sa\stest\sof\scodepoint\s0x202F\s(non-break\snarrow\sspace)\sfrom\sthe\sfts3\sICU\ntests.\sDifferent\sversions\sof\sICU\sapparently\shandle\sthis\sobscure\scodepoint\nslightly\sdifferently.
D 2017-05-30T18:14:47.018
C Change\ssqlite3BtreeNext()\sand\ssqlite3BtreePrevious()\sso\sthat\sthey\sreturn\nSQLITE_DONE\sif\sthey\shave\salready\sreached\sthe\send\s(or\sbeginning)\sof\sthe\stable.\nThis\sgives\sa\sperformance\sincrease\sand\ssize\sreduction.
D 2017-05-30T18:34:07.003
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 8eeb80162074004e906b53d7340a12a14c471a83743aab975947e95ce061efcc
@ -347,8 +347,8 @@ F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
F src/btree.c 0065e4bb6dc1431bca7aa806dc5635885aa93f3056bb26a4b6cc0cc53a5131f3
F src/btree.h 80f518c0788be6cec8d9f8e13bd8e380df299d2b5e4ac340dc887b0642647cfc
F src/btree.c 8ac6ae352c63998228718b5f11faa0da2676710898a47284de78e96cb41dca35
F src/btree.h 3edc5329bc59534d2d15b4f069a9f54b779a7e51289e98fa481ae3c0e526a5ca
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
F src/build.c 4026a9c554b233e50c5e9ad46963e676cf54dd2306d952aa1eaa07a1bc9ce14f
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
@ -416,7 +416,7 @@ F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c c8cf60d0c5411d5e70e7c136470d29dbe760d250f55198b71682c67086524e4a
F src/test1.c c99f0442918a7a5d5b68a95d6024c211989e6c782c15ced5a558994baaf76a5e
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
@ -471,14 +471,14 @@ F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23
F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
F src/vdbe.c 70f1c27d3de7b3ea68d3ee2b7fbf407335b66f7483eb321201ffe53724f9c54e
F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848
F src/vdbeInt.h 1ecdacc1322fdd3241ec30c32a480e328a6f864e532dc53fae8e0ab68121aebf
F src/vdbe.c cce462ad3cf1cad1944e105f773712a979e23fbe302328dc2885b0f4a612e1f6
F src/vdbe.h 70a409d171d4e51b962f0d53abf15c33c404c6aa4c9d62fb3a931b5a62ba9615
F src/vdbeInt.h cdcdabad4f5d6bf7a3beb826a7f33ee6f8f1cb220042bedd5b7d4bf2ea1d179f
F src/vdbeapi.c 6009dbf02b70aa0dc461e98ebad98b88e4b22588341818891a2ea5c3c6533411
F src/vdbeaux.c 4ff778d12873ec6e3c222634dd17afeddfcee3ffa5dc51c173b306a2677cfa22
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
F src/vdbemem.c 2c70f8f5de6c71fb99a22c5b83be9fab5c47cdd8e279fa44a8c00cfed06d7e89
F src/vdbesort.c f26595dfcc342f4ea8b2e703686c2352638ed578e20acfc3e6534d30bbd4f555
F src/vdbesort.c f512c68d0bf7e0105316a5594c4329358c8ee9cae3b25138df041d97516c0372
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
@ -1581,7 +1581,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 9a3e3b34ba6eafce2f560c13225a3673e18d696b29295b59d958e938fa593baf
R 9de325377be231c595f4cf6787a5ac94
U dan
Z 59447a6f11e0bcdf6110b0800c8ba319
P 69ae688982d6cb9f859f5643c315a1dc5ba76ad35553ecea8329a75ee70a87b1
R 01f70d2b820b4999a40771b05d021f40
U drh
Z 9376a3b7b02b59becba99aee408544a5

View File

@ -1 +1 @@
69ae688982d6cb9f859f5643c315a1dc5ba76ad35553ecea8329a75ee70a87b1
e972a3860892022d57b26ec44ce0fbadc61c1ff54b7a10b7e82390db88d323a7

View File

@ -5163,16 +5163,19 @@ int sqlite3BtreeMovetoUnpacked(
/* If the requested key is one more than the previous key, then
** try to get there using sqlite3BtreeNext() rather than a full
** binary search. This is an optimization only. The correct answer
** is still obtained without this ase, only a little more slowely */
** is still obtained without this case, only a little more slowely */
if( pCur->info.nKey+1==intKey && !pCur->skipNext ){
*pRes = 0;
rc = sqlite3BtreeNext(pCur, pRes);
if( rc ) return rc;
if( *pRes==0 ){
rc = sqlite3BtreeNext(pCur, 0);
if( rc==SQLITE_OK ){
getCellInfo(pCur);
if( pCur->info.nKey==intKey ){
return SQLITE_OK;
}
}else if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}else{
return rc;
}
}
}
@ -5406,10 +5409,12 @@ i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
}
/*
** Advance the cursor to the next entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the last entry in the database before
** this routine was called, then set *pRes=1.
** Advance the cursor to the next entry in the database.
** Return value:
**
** SQLITE_OK success
** SQLITE_DONE cursor is already pointing at the last element
** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreeNext(). That routine is optimized
** for the common case of merely incrementing the cell counter BtCursor.aiIdx
@ -5417,23 +5422,19 @@ i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
** routine is called when it is necessary to move to a different page or
** to restore the cursor.
**
** The calling function will set *pRes to 0 or 1. The initial *pRes value
** will be 1 if the cursor being stepped corresponds to an SQL index and
** if this routine could have been skipped if that SQL index had been
** a unique index. Otherwise the caller will have set *pRes to zero.
** Zero is the common case. The btree implementation is free to use the
** initial *pRes value as a hint to improve performance, but the current
** SQLite btree implementation does not. (Note that the comdb2 btree
** implementation does use this hint, however.)
** If bit 0x01 of the flags argument is 1, then the cursor corresponds to
** an SQL index and this routine could have been skipped if the SQL index
** had been a unique index. The flags argument is a hint to the implement.
** SQLite btree implementation does not use this hint, but COMDB2 does.
*/
static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int flags){
int rc;
int idx;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
assert( *pRes==0 );
assert( flags==0 );
if( pCur->eState!=CURSOR_VALID ){
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
rc = restoreCursorPosition(pCur);
@ -5441,8 +5442,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
return SQLITE_DONE;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
@ -5474,15 +5474,14 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
}
do{
if( pCur->iPage==0 ){
*pRes = 1;
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
return SQLITE_DONE;
}
moveToParent(pCur);
pPage = pCur->apPage[pCur->iPage];
}while( pCur->ix>=pPage->nCell );
if( pPage->intKey ){
return sqlite3BtreeNext(pCur, pRes);
return sqlite3BtreeNext(pCur, flags);
}else{
return SQLITE_OK;
}
@ -5493,20 +5492,18 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
return moveToLeftmost(pCur);
}
}
int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
int sqlite3BtreeNext(BtCursor *pCur, int flags){
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( flags==0 || flags==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
*pRes = 0;
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, 0);
pPage = pCur->apPage[pCur->iPage];
if( (++pCur->ix)>=pPage->nCell ){
pCur->ix--;
return btreeNext(pCur, pRes);
return btreeNext(pCur, 0);
}
if( pPage->leaf ){
return SQLITE_OK;
@ -5516,10 +5513,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
}
/*
** Step the cursor to the back to the previous entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the first entry in the database before
** this routine was called, then set *pRes=1.
** Step the cursor to the back to the previous entry in the database.
** Return values:
**
** SQLITE_OK success
** SQLITE_DONE the cursor is already on the first element of the table
** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreePrevious(). That routine is optimized
** for the common case of merely decrementing the cell counter BtCursor.aiIdx
@ -5527,22 +5526,18 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
** helper routine is called when it is necessary to move to a different page
** or to restore the cursor.
**
** The calling function will set *pRes to 0 or 1. The initial *pRes value
** will be 1 if the cursor being stepped corresponds to an SQL index and
** if this routine could have been skipped if that SQL index had been
** a unique index. Otherwise the caller will have set *pRes to zero.
** Zero is the common case. The btree implementation is free to use the
** initial *pRes value as a hint to improve performance, but the current
** SQLite btree implementation does not. (Note that the comdb2 btree
** implementation does use this hint, however.)
**
** If bit 0x01 of the flags argument is 1, then the cursor corresponds to
** an SQL index and this routine could have been skipped if the SQL index
** had been a unique index. The flags argument is a hint to the implement.
** SQLite btree implementation does not use this hint, but COMDB2 does.
*/
static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int flags){
int rc;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
assert( pRes!=0 );
assert( *pRes==0 );
assert( flags==0 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
assert( pCur->info.nSize==0 );
@ -5552,8 +5547,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
return SQLITE_DONE;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
@ -5577,8 +5571,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
while( pCur->ix==0 ){
if( pCur->iPage==0 ){
pCur->eState = CURSOR_INVALID;
*pRes = 1;
return SQLITE_OK;
return SQLITE_DONE;
}
moveToParent(pCur);
}
@ -5588,26 +5581,24 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
pCur->ix--;
pPage = pCur->apPage[pCur->iPage];
if( pPage->intKey && !pPage->leaf ){
rc = sqlite3BtreePrevious(pCur, pRes);
rc = sqlite3BtreePrevious(pCur, flags);
}else{
rc = SQLITE_OK;
}
}
return rc;
}
int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
int sqlite3BtreePrevious(BtCursor *pCur, int flags){
assert( cursorOwnsBtShared(pCur) );
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( flags==0 || flags==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
*pRes = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
|| pCur->ix==0
|| pCur->apPage[pCur->iPage]->leaf==0
){
return btreePrevious(pCur, pRes);
return btreePrevious(pCur, 0);
}
pCur->ix--;
return SQLITE_OK;
@ -8322,8 +8313,8 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** sub-tree headed by the child page of the cell being deleted. This makes
** balancing the tree following the delete operation easier. */
if( !pPage->leaf ){
int notUsed = 0;
rc = sqlite3BtreePrevious(pCur, &notUsed);
rc = sqlite3BtreePrevious(pCur, 0);
assert( rc!=SQLITE_DONE );
if( rc ) return rc;
}

View File

@ -286,9 +286,9 @@ int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
int flags, int seekResult);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int flags);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreePrevious(BtCursor*, int flags);
i64 sqlite3BtreeIntegerKey(BtCursor*);
int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);

View File

@ -306,7 +306,11 @@ static int SQLITE_TCLAPI btree_next(
}
pCur = sqlite3TestTextToPtr(argv[1]);
sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreeNext(pCur, &res);
rc = sqlite3BtreeNext(pCur, 0);
if( rc==SQLITE_DONE ){
res = 1;
rc = SQLITE_OK;
}
sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);

View File

@ -573,7 +573,7 @@ int sqlite3VdbeExec(
int iCompare = 0; /* Result of last comparison */
unsigned nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */
@ -605,6 +605,8 @@ int sqlite3VdbeExec(
u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
assert( 0 < db->nProgressOps );
nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
}else{
nProgressLimit = 0xffffffff;
}
#endif
#ifdef SQLITE_DEBUG
@ -782,7 +784,7 @@ check_for_interrupt:
** If the progress callback returns non-zero, exit the virtual machine with
** a return code SQLITE_ABORT.
*/
if( db->xProgress!=0 && nVmStep>=nProgressLimit ){
if( nVmStep>=nProgressLimit && db->xProgress!=0 ){
assert( db->nProgressOps!=0 );
nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
if( db->xProgress(db->pProgressArg) ){
@ -3977,8 +3979,15 @@ case OP_SeekGT: { /* jump, in3 */
if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT );
if( res<0 || (res==0 && oc==OP_SeekGT) ){
res = 0;
rc = sqlite3BtreeNext(pC->uc.pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
res = 1;
}else{
goto abort_due_to_error;
}
}
}else{
res = 0;
}
@ -3986,8 +3995,15 @@ case OP_SeekGT: { /* jump, in3 */
assert( oc==OP_SeekLT || oc==OP_SeekLE );
if( res>0 || (res==0 && oc==OP_SeekLT) ){
res = 0;
rc = sqlite3BtreePrevious(pC->uc.pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
rc = sqlite3BtreePrevious(pC->uc.pCursor, 0);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
res = 1;
}else{
goto abort_due_to_error;
}
}
}else{
/* res might be negative because the table is empty. Check to
** see if this is the case.
@ -5093,12 +5109,10 @@ case OP_Rewind: { /* jump */
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
int res;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
res = 0;
rc = sqlite3VdbeSorterNext(db, pC, &res);
rc = sqlite3VdbeSorterNext(db, pC);
goto next_tail;
case OP_PrevIfOpen: /* jump */
case OP_NextIfOpen: /* jump */
@ -5109,12 +5123,9 @@ case OP_Next: /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<ArraySize(p->aCounter) );
pC = p->apCsr[pOp->p1];
res = pOp->p3;
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( res==0 || (res==1 && pC->isTable==0) );
testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
@ -5129,21 +5140,21 @@ case OP_Next: /* jump */
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last );
rc = pOp->p4.xAdvance(pC->uc.pCursor, &res);
rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
next_tail:
pC->cacheStatus = CACHE_STALE;
VdbeBranchTaken(res==0,2);
if( rc ) goto abort_due_to_error;
if( res==0 ){
VdbeBranchTaken(rc==SQLITE_OK,2);
if( rc==SQLITE_OK ){
pC->nullRow = 0;
p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
goto jump_to_p2_and_check_for_interrupt;
}else{
pC->nullRow = 1;
}
if( rc!=SQLITE_DONE ) goto abort_due_to_error;
rc = SQLITE_OK;
pC->nullRow = 1;
goto check_for_interrupt;
}

View File

@ -63,7 +63,7 @@ struct VdbeOp {
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
int (*xAdvance)(BtCursor *, int *);
int (*xAdvance)(BtCursor *, int);
} p4;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
char *zComment; /* Comment to improve readability */

View File

@ -506,7 +506,7 @@ int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *);
int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);

View File

@ -2612,9 +2612,13 @@ int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
}
/*
** Advance to the next element in the sorter.
** Advance to the next element in the sorter. Return value:
**
** SQLITE_OK success
** SQLITE_DONE end of data
** otherwise some kind of error.
*/
int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){
VdbeSorter *pSorter;
int rc; /* Return code */
@ -2628,21 +2632,22 @@ int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
#if SQLITE_MAX_WORKER_THREADS>0
if( pSorter->bUseThreads ){
rc = vdbePmaReaderNext(pSorter->pReader);
*pbEof = (pSorter->pReader->pFd==0);
if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE;
}else
#endif
/*if( !pSorter->bUseThreads )*/ {
int res = 0;
assert( pSorter->pMerger!=0 );
assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
rc = vdbeMergeEngineStep(pSorter->pMerger, &res);
if( rc==SQLITE_OK && res ) rc = SQLITE_DONE;
}
}else{
SorterRecord *pFree = pSorter->list.pList;
pSorter->list.pList = pFree->u.pNext;
pFree->u.pNext = 0;
if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree);
*pbEof = !pSorter->list.pList;
rc = SQLITE_OK;
rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE;
}
return rc;
}