Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -8137,10 +8137,32 @@ iCellDepth = pCur->iPage; iCellIdx = pCur->aiIdx[iCellDepth]; pPage = pCur->apPage[iCellDepth]; pCell = findCell(pPage, iCellIdx); + + /* If the bPreserve flag is set to true, then the cursor position must + ** be preserved following this delete operation. If the current delete + ** will cause a b-tree rebalance, then this is done by saving the cursor + ** key and leaving the cursor in CURSOR_REQUIRESEEK state before + ** returning. + ** + ** Or, if the current delete will not cause a rebalance, then the cursor + ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately + ** before or after the deleted entry. In this case set bSkipnext to true. */ + if( bPreserve ){ + if( !pPage->leaf + || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) + ){ + /* A b-tree rebalance will be required after deleting this entry. + ** Save the cursor key. */ + rc = saveCursorKey(pCur); + if( rc ) return rc; + }else{ + bSkipnext = 1; + } + } /* If the page containing the entry to delete is not a leaf page, move ** the cursor to the largest entry in the tree that is smaller than ** the entry being deleted. This cell will replace the cell being deleted ** from the internal node. The 'previous' entry is used for this instead @@ -8164,32 +8186,10 @@ ** invalidate any incrblob cursors open on the row being deleted. */ if( pCur->pKeyInfo==0 ){ invalidateIncrblobCursors(p, pCur->info.nKey, 0); } - /* If the bPreserve flag is set to true, then the cursor position must - ** be preserved following this delete operation. If the current delete - ** will cause a b-tree rebalance, then this is done by saving the cursor - ** key and leaving the cursor in CURSOR_REQUIRESEEK state before - ** returning. - ** - ** Or, if the current delete will not cause a rebalance, then the cursor - ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately - ** before or after the deleted entry. In this case set bSkipnext to true. */ - if( bPreserve ){ - if( !pPage->leaf - || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) - ){ - /* A b-tree rebalance will be required after deleting this entry. - ** Save the cursor key. */ - rc = saveCursorKey(pCur); - if( rc ) return rc; - }else{ - bSkipnext = 1; - } - } - /* Make the page containing the entry to be deleted writable. Then free any ** overflow pages associated with the entry and finally remove the cell ** itself from within the page. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; Index: test/delete4.test ================================================================== --- test/delete4.test +++ test/delete4.test @@ -137,9 +137,28 @@ CREATE INDEX idx_t4_0 ON t4 (col1, col0); DELETE FROM t4 WHERE col0=69 OR col0>7; PRAGMA integrity_check; } {ok} - - +# 2016-04-09 +# Ticket https://sqlite.org/src/info/a306e56ff68b8fa5 +# Failure to completely delete when reverse_unordered_selects is +# engaged. +# +db close +forcedelete test.db +sqlite3 db test.db +do_execsql_test 5.0 { + PRAGMA page_size=1024; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + CREATE INDEX x1 ON t1(b, c); + INSERT INTO t1(a,b,c) VALUES(1, 1, zeroblob(80)); + INSERT INTO t1(a,b,c) SELECT a+1, 1, c FROM t1; + INSERT INTO t1(a,b,c) SELECT a+2, 1, c FROM t1; + INSERT INTO t1(a,b,c) SELECT a+10, 2, c FROM t1 WHERE b=1; + INSERT INTO t1(a,b,c) SELECT a+20, 3, c FROM t1 WHERE b=1; + PRAGMA reverse_unordered_selects = ON; + DELETE FROM t1 WHERE b=2; + SELECT a FROM t1 WHERE b=2; +} {} finish_test