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:
parent
d26d2c7de2
commit
2ab792e4c0
26
manifest
26
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
|
||||
|
@ -1 +1 @@
|
||||
69ae688982d6cb9f859f5643c315a1dc5ba76ad35553ecea8329a75ee70a87b1
|
||||
e972a3860892022d57b26ec44ce0fbadc61c1ff54b7a10b7e82390db88d323a7
|
103
src/btree.c
103
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
47
src/vdbe.c
47
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) ){
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user