From: drh Date: Tue, 30 May 2017 18:34:07 +0000 (+0000) Subject: Change sqlite3BtreeNext() and sqlite3BtreePrevious() so that they return X-Git-Tag: version-3.20.0~234 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2ab792e4c0dd5662bcb482c2c6a89961afd1251f;p=thirdparty%2Fsqlite.git 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 --- diff --git a/manifest b/manifest index 10112c0cf5..fabcd4ccd1 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 4731d466b0..d670db15d4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -69ae688982d6cb9f859f5643c315a1dc5ba76ad35553ecea8329a75ee70a87b1 \ No newline at end of file +e972a3860892022d57b26ec44ce0fbadc61c1ff54b7a10b7e82390db88d323a7 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 8e7bfa5531..eeb076c4d8 100644 --- a/src/btree.c +++ b/src/btree.c @@ -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, ¬Used); + rc = sqlite3BtreePrevious(pCur, 0); + assert( rc!=SQLITE_DONE ); if( rc ) return rc; } diff --git a/src/btree.h b/src/btree.h index 6bd90455a8..b56eb85e68 100644 --- a/src/btree.h +++ b/src/btree.h @@ -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); diff --git a/src/test3.c b/src/test3.c index 6b4bfedbd9..0de19469a4 100644 --- a/src/test3.c +++ b/src/test3.c @@ -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); diff --git a/src/vdbe.c b/src/vdbe.c index 61b2e4e9e2..9a0678ced1 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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) ){ @@ -1324,7 +1326,7 @@ case OP_ResultRow: { /* Run the progress counter just before returning. */ if( db->xProgress!=0 - && nVmStep>=nProgressLimit + && nVmStep>=nProgressLimit && db->xProgress(db->pProgressArg)!=0 ){ rc = SQLITE_INTERRUPT; @@ -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->p1nCursor ); assert( pOp->p5aCounter) ); 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; } diff --git a/src/vdbe.h b/src/vdbe.h index 651810d4a4..126f199b5a 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -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 */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 65e47c33f3..93a6fcda5b 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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 *); diff --git a/src/vdbesort.c b/src/vdbesort.c index 51636c9fa1..31edba7509 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -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; }